CVE-2021-4097 (Other, published 2021-12-12T00:15Z)
Description: value: phpservermon is vulnerable to Improper Neutralization of CRLF Sequences
Severity: MEDIUM (CVSS v3 base score: 5.4)
Weakness: CWE-93 \u2014 Improper Neutralization of CRLF Sequences ('CRLF Injection')
The product uses CRLF (carriage return line feeds) as a special element, e.g. to separate lines or records, but it does not neutralize or incorrectly neutralizes CRLF sequences from inputs.
Repository: https://github.com/phpservermon/phpservermon
Files changed:
Vagrantfile
dev/config.php
dev/phpservermon-default
docs/developers.rst
provision.yaml
setup-mysql.sh
setup-php.sh
Commit message: Update and Fix Vagrant development setup (#1111)

CHANGES

- Updated to Ubuntu 20.04 bento vagrant box
- Updated PHP to PHP-FPM 7.4
- Updated MySQL to Percona Server 5.7
- Now runs with NGINX as web server (default vhost kept as before http://192.168.50.100/)
- DEPRECATED: No longer relying on puphpet code (it's outdated and no longer maintained)
- Updated Vagrantfile to use ansible
- NEW: Automation in vagrant is now handled by ansible (see provision.yaml for details)
- A couple of shell scripts to handle "re-running" of the vagrant up command for faster executions ( setup-php.sh, setup-mysql.sh )

Vulnerable code:
require 'yaml'

dir = File.dirname(File.expand_path(__FILE__))

configValues = YAML.load_file("#{dir}/puphpet/config.yaml")
data         = configValues['vagrantfile-local']

Vagrant.require_version '>= 1.6.0'

Vagrant.configure('2') do |config|
  config.vm.box     = "#{data['vm']['box']}"
  config.vm.box_url = "#{data['vm']['box_url']}"

  if data['vm']['hostname'].to_s.strip.length != 0
    config.vm.hostname = "#{data['vm']['hostname']}"
  end

  if data['vm']['network']['private_network'].to_s != ''
    config.vm.network 'private_network', ip: "#{data['vm']['network']['private_network']}"
  end

  data['vm']['network']['forwarded_port'].each do |i, port|
    if port['guest'] != '' && port['host'] != ''
      config.vm.network :forwarded_port, guest: port['guest'].to_i, host: port['host'].to_i
    end
  end

  if !data['vm']['post_up_message'].nil?
    config.vm.post_up_message = "#{data['vm']['post_up_message']}"
  end

  if Vagrant.has_plugin?('vagrant-hostmanager')
    hosts = Array.new()

    if !configValues['apache']['install'].nil? &&
        configValues['apache']['install'].to_i == 1 &&
        configValues['apache']['vhosts'].is_a?(Hash)
      configValues['apache']['vhosts'].each do |i, vhost|
        hosts.push(vhost['servername'])

        if vhost['serveraliases'].is_a?(Array)
          vhost['serveraliases'].each do |vhost_alias|
            hosts.push(vhost_alias)
          end
        end
      end
    elsif !configValues['nginx']['install'].nil? &&
           configValues['nginx']['install'].to_i == 1 &&
           configValues['nginx']['vhosts'].is_a?(Hash)
      configValues['nginx']['vhosts'].each do |i, vhost|
        hosts.push(vhost['server_name'])

        if vhost['server_aliases'].is_a?(Array)
          vhost['server_aliases'].each do |x, vhost_alias|
            hosts.push(vhost_alias)
          end
        end
      end
    end

    if hosts.any?
      if config.vm.hostname.to_s.strip.length == 0
        config.vm.hostname = 'puphpet-dev-machine'
      end

      config.hostmanager.enabled           = true
      config.hostmanager.manage_host       = true
      config.hostmanager.ignore_private_ip = false
      config.hostmanager.include_offline   = false
      config.hostmanager.aliases           = hosts
    end
  end

  if Vagrant.has_plugin?('vagrant-cachier')
    config.cache.scope = :box
  end

  data['vm']['synced_folder'].each do |i, folder|
    if folder['source'] != '' && folder['target'] != ''
      sync_owner = !folder['sync_owner'].nil? ? folder['sync_owner'] : 'www-data'
      sync_group = !folder['sync_group'].nil? ? folder['sync_group'] : 'www-data'

      if folder['sync_type'] == 'nfs'
        config.vm.synced_folder "#{folder['source']}", "#{folder['target']}", id: "#{i}", type: 'nfs'
      elsif folder['sync_type'] == 'smb'
        config.vm.synced_folder "#{folder['source']}", "#{folder['target']}", id: "#{i}", type: 'smb'
      elsif folder['sync_type'] == 'rsync'
        rsync_args = !folder['rsync']['args'].nil? ? folder['rsync']['args'] : ['--verbose', '--archive', '-z']
        rsync_auto = !folder['rsync']['auto'].nil? ? folder['rsync']['auto'] : true
        rsync_exclude = !folder['rsync']['exclude'].nil? ? folder['rsync']['exclude'] : ['.vagrant/']

        config.vm.synced_folder "#{folder['source']}", "#{folder['target']}", id: "#{i}",
          rsync__args: rsync_args, rsync__exclude: rsync_exclude, rsync__auto: rsync_auto, type: 'rsync', group: sync_group, owner: sync_owner
      elsif data['vm']['chosen_provider'] == 'parallels'
        config.vm.synced_folder "#{folder['source']}", "#{folder['target']}", id: "#{i}",
          group: sync_group, owner: sync_owner, mount_options: ['share']
      else
        config.vm.synced_folder "#{folder['source']}", "#{folder['target']}", id: "#{i}",
          group: sync_group, owner: sync_owner, mount_options: ['dmode=775', 'fmode=764']
      end
    end
  end

  config.vm.usable_port_range = (data['vm']['usable_port_range']['start'].to_i..data['vm']['usable_port_range']['stop'].to_i)

  if data['vm']['chosen_provider'].empty? || data['vm']['chosen_provider'] == 'virtualbox'
    ENV['VAGRANT_DEFAULT_PROVIDER'] = 'virtualbox'

    config.vm.provider :virtualbox do |virtualbox|
      data['vm']['provider']['virtualbox']['modifyvm'].each do |key, value|
        if key == 'memory'
          next
        end
        if key == 'cpus'
          next
        end

        if key == 'natdnshostresolver1'
          value = value ? 'on' : 'off'
        end

        virtualbox.customize ['modifyvm', :id, "--#{key}", "#{value}"]
      end

      virtualbox.customize ['modifyvm', :id, '--memory', "#{data['vm']['memory']}"]
      virtualbox.customize ['modifyvm', :id, '--cpus', "#{data['vm']['cpus']}"]

      if data['vm']['provider']['virtualbox']['modifyvm']['name'].nil? ||
        data['vm']['provider']['virtualbox']['modifyvm']['name'].empty?
        if data['vm']['hostname'].to_s.strip.length != 0
          virtualbox.customize ['modifyvm', :id, '--name', config.vm.hostname]
        end
      end
    end
  end

  if data['vm']['chosen_provider'] == 'vmware_fusion' || data['vm']['chosen_provider'] == 'vmware_workstation'
    ENV['VAGRANT_DEFAULT_PROVIDER'] = (data['vm']['chosen_provider'] == 'vmware_fusion') ? 'vmware_fusion' : 'vmware_workstation'

    config.vm.provider :vmware_fusion do |v, override|
      data['vm']['provider']['vmware'].each do |key, value|
        if key == 'memsize'
          next
        end
        if key == 'cpus'
          next
        end

        v.vmx["#{key}"] = "#{value}"
      end

      v.vmx['memsize']  = "#{data['vm']['memory']}"
      v.vmx['numvcpus'] = "#{data['vm']['cpus']}"

      if data['vm']['provider']['vmware']['displayName'].nil? ||
        data['vm']['provider']['vmware']['displayName'].empty?
        if data['vm']['hostname'].to_s.strip.length != 0
          v.vmx['displayName'] = config.vm.hostname
        end
      end
    end
  end

  if data['vm']['chosen_provider'] == 'parallels'
    ENV['VAGRANT_DEFAULT_PROVIDER'] = 'parallels'

    config.vm.provider 'parallels' do |v|
      data['vm']['provider']['parallels'].each do |key, value|
        if key == 'memsize'
          next
        end
        if key == 'cpus'
          next
        end

        v.customize ['set', :id, "--#{key}", "#{value}"]
      end

      v.memory = "#{data['vm']['memory']}"
      v.cpus   = "#{data['vm']['cpus']}"

      if data['vm']['provider']['parallels']['name'].nil? ||
        data['vm']['provider']['parallels']['name'].empty?
        if data['vm']['hostname'].to_s.strip.length != 0
          v.name = config.vm.hostname
        end
      end
    end
  end

  ssh_username = !data['ssh']['username'].nil? ? data['ssh']['username'] : 'vagrant'

  config.vm.provision 'shell' do |s|
    s.path = 'puphpet/shell/initial-setup.sh'
    s.args = '/vagrant/puphpet'
  end
  config.vm.provision 'shell' do |kg|
    kg.path = 'puphpet/shell/ssh-keygen.sh'
    kg.args = "#{ssh_username}"
  end
  config.vm.provision :shell, :path => 'puphpet/shell/install-ruby.sh'
  config.vm.provision :shell, :path => 'puphpet/shell/install-puppet.sh'

  config.vm.provision :puppet do |puppet|
    puppet.facter = {
      'ssh_username'     => "#{ssh_username}",
      'provisioner_type' => ENV['VAGRANT_DEFAULT_PROVIDER'],
      'vm_target_key'    => 'vagrantfile-local',
    }
    puppet.manifests_path = "#{data['vm']['provision']['puppet']['manifests_path']}"
    puppet.manifest_file  = "#{data['vm']['provision']['puppet']['manifest_file']}"
    puppet.module_path    = "#{data['vm']['provision']['puppet']['module_path']}"

    if !data['vm']['provision']['puppet']['options'].empty?
      puppet.options = data['vm']['provision']['puppet']['options']
    end
  end

  config.vm.provision :shell do |s|
    s.path = 'puphpet/shell/execute-files.sh'
    s.args = ['exec-once', 'exec-always']
  end
  config.vm.provision :shell, run: 'always' do |s|
    s.path = 'puphpet/shell/execute-files.sh'
    s.args = ['startup-once', 'startup-always']
  end
  config.vm.provision :shell, :path => 'puphpet/shell/important-notices.sh'

  if File.file?("#{dir}/puphpet/files/dot/ssh/id_rsa")
    config.ssh.private_key_path = [
      "#{dir}/puphpet/files/dot/ssh/id_rsa",
      "#{dir}/puphpet/files/dot/ssh/insecure_private_key"
    ]
  end

  if !data['ssh']['host'].nil?
    config.ssh.host = "#{data['ssh']['host']}"
  end
  if !data['ssh']['port'].nil?
    config.ssh.port = "#{data['ssh']['port']}"
  end
  if !data['ssh']['username'].nil?
    config.ssh.username = "#{data['ssh']['username']}"
  end
  if !data['ssh']['guest_port'].nil?
    config.ssh.guest_port = data['ssh']['guest_port']
  end
  if !data['ssh']['shell'].nil?
    config.ssh.shell = "#{data['ssh']['shell']}"
  end
  if !data['ssh']['keep_alive'].nil?
    config.ssh.keep_alive = data['ssh']['keep_alive']
  end
  if !data['ssh']['forward_agent'].nil?
    config.ssh.forward_agent = data['ssh']['forward_agent']
  end
  if !data['ssh']['forward_x11'].nil?
    config.ssh.forward_x11 = data['ssh']['forward_x11']
  end
  if !data['vagrant']['host'].nil?
    config.vagrant.host = data['vagrant']['host'].gsub(':', '').intern

To ease development, a Vagrantfile has been included along with a full provisioning profile generated using PuPHPet (https://puphpet.com).
The Vagrantfile is configured to set up a CentOS 6.5 box with PHP 5.6 and MySQL installed, with a local port forward on port 8080.
To set up the development environment, make sure you have Vagrant and VirtualBox (https://www.virtualbox.org/) installed, then run::
After that, you can access your development environment by navigating to http://localhost:8080/psm/ or http://192.158.56.101/psm/.
vagrantfile-local:
    vm:
        box: puphpet/centos65-x64
        box_url: puphpet/centos65-x64
        hostname: ''
        memory: '512'
        cpus: '1'
        chosen_provider: virtualbox
        network:
            private_network: 192.168.56.101
            forwarded_port:
                h2nLRhrSzIlF:
                    host: '8080'
                    guest: '80'
        post_up_message: ''
        provider:
            virtualbox:
                modifyvm:
                    natdnshostresolver1: on
            vmware:
                numvcpus: 1
            parallels:
                cpus: 1
        provision:
            puppet:
                manifests_path: puphpet/puppet
                manifest_file: site.pp
                module_path: puphpet/puppet/modules
                options:
                    - '--verbose'
                    - '--hiera_config /vagrant/puphpet/puppet/hiera.yaml'
                    - '--parser future'
        synced_folder:
            w8S8WFz0oRfc:
                owner: ''
                group: ''
                source: ./
                target: /var/www/default/psm
                sync_type: default
                rsync:
                    auto: 'false'
        usable_port_range:
            start: 10200
            stop: 10500
    ssh:
        host: null
        port: null
        private_key_path: null
        username: vagrant
        guest_port: null
        keep_alive: true
        forward_agent: false
        forward_x11: false
        shell: 'bash -l'
    vagrant:
        host: detect
server:
    install: '1'
    packages:
        - vim-common
firewall:
    install: '1'
    rules: null
apache:
    install: '1'
    settings:
        user: www-data
        group: www-data
        default_vhost: true
        manage_user: false
        manage_group: false
        sendfile: 0
    modules:
        - rewrite
    vhosts: {  }
    mod_pagespeed: 0
nginx:
    install: '0'
    settings:
        default_vhost: 1
        proxy_buffer_size: 128k
        proxy_buffers: '4 256k'
    upstreams: {  }
    vhosts: {  }
php:
    install: '1'
    version: '56'
    composer: '1'
    composer_home: ''
    modules:
        php:
            - cli
            - intl
            - mcrypt
            - mysqlnd
        pear: {  }
        pecl:
            - pecl_http
    ini:
        display_errors: On
        error_reporting: E_ALL
        session.save_path: /var/lib/php/session
    timezone: America/Chicago
    mod_php: 0
hhvm:
    install: '0'
    nightly: 0
    composer: '1'
    composer_home: ''
    settings:
        host: '0'
        port: '0'
    ini: {  }
    timezone: null
xdebug:
    install: '1'
    settings:
        xdebug.default_enable: '1'
        xdebug.remote_autostart: '0'
        xdebug.remote_connect_back: '1'
        xdebug.remote_enable: '1'
        xdebug.remote_handler: dbgp
        xdebug.remote_port: '9000'
        xdebug.remote_host: 192.168.56.101
        xdebug.idekey: XDEBUGPSM
xhprof:
    install: '0'
wpcli:
    install: '0'
    version: ''
drush:
    install: '0'
    version: ''
ruby:
    install: '1'
    versions: {  }
nodejs:
    install: '0'
    npm_packages: {  }
python:
    install: '1'
    packages: {  }
    versions:
        sAxFy93LRP7G:
            version: ''
mysql:
    install: '1'
    override_options: {  }
    root_password: psm
    adminer: '1'
    databases:
        TiL7OqnkkdEw:
            grant:
                - ALL
            name: psm
            host: localhost
            user: psm
            password: psm
            sql_file: ''
postgresql:
    install: '0'
    settings:
        root_password: '123'
        user_group: postgres
        encoding: UTF8
        version: '9.3'
    databases: {  }
    adminer: 0
mariadb:
    install: '0'
    override_options: {  }
    root_password: '123'
    adminer: 0
    databases: {  }
sqlite:
    install: '0'
    adminer: 0
    databases: {  }
mongodb:
    install: '0'
    settings:
        auth: 1
        port: '27017'
    databases: {  }
redis:
    install: '0'
    settings:
        conf_port: '6379'
mailcatcher:
    install: '0'
    settings:
        smtp_ip: 0.0.0.0
        smtp_port: 1025
        http_ip: 0.0.0.0
        http_port: '1080'
        mailcatcher_path: /usr/local/rvm/wrappers/default
        from_email_method: inline
beanstalkd:
    install: '0'
    settings:
        listenaddress: 0.0.0.0
        listenport: '13000'
        maxjobsize: '65535'
        maxconnections: '1024'
        binlogdir: /var/lib/beanstalkd/binlog
        binlogfsync: null
        binlogsize: '10485760'
    beanstalk_console: 0
    binlogdir: /var/lib/beanstalkd/binlog
rabbitmq:
    install: '0'
    settings:
        port: '5672'
elastic_search:
    install: '0'
    settings:
        version: ''
        java_install: true
solr:
    install: '0'
    settings:
        version: ''
        port: ''

if [ -f /etc/bash_completion ]; then
    source /etc/bash_completion
fi

__has_parent_dir () {
    # Utility function so we can test for things like .git/.hg without firing up a
    # separate process
    test -d "$1" && return 0;

    current="."
    while [ ! "$current" -ef "$current/.." ]; do
        if [ -d "$current/$1" ]; then
            return 0;
        fi
        current="$current/..";
    done

    return 1;
}

__vcs_name() {
    if [ -d .svn ]; then
        echo "-[svn]";
    elif __has_parent_dir ".git"; then
        echo "-[$(__git_ps1 'git %s')]";
    elif __has_parent_dir ".hg"; then
        echo "-[hg $(hg branch)]"
    fi
}

black=$(tput -Txterm setaf 0)
red=$(tput -Txterm setaf 1)
green=$(tput -Txterm setaf 2)
yellow=$(tput -Txterm setaf 3)
dk_blue=$(tput -Txterm setaf 4)
pink=$(tput -Txterm setaf 5)
lt_blue=$(tput -Txterm setaf 6)

bold=$(tput -Txterm bold)
reset=$(tput -Txterm sgr0)

# Nicely formatted terminal prompt
export PS1='\n\[$bold\]\[$black\][\[$dk_blue\]\@\[$black\]]-[\[$green\]\u\[$yellow\]@\[$green\]\h\[$black\]]-[\[$pink\]\w\[$black\]]\[\033[0;33m\]$(__vcs_name) \[\033[00m\]\[$reset\]\n\[$reset\]\$ '

alias ls='ls -F --color=always'
alias dir='dir -F --color=always'
alias ll='ls -l'
alias cp='cp -iv'
alias rm='rm -i'
alias mv='mv -iv'
alias grep='grep --color=auto -in'
alias ..='cd ..'
# bash/zsh git prompt support
#
# Copyright (C) 2006,2007 Shawn O. Pearce <spearce@spearce.org>
# Distributed under the GNU General Public License, version 2.0.
#
# This script allows you to see repository status in your prompt.
#
# To enable:
#
#    1) Copy this file to somewhere (e.g. ~/.git-prompt.sh).
#    2) Add the following line to your .bashrc/.zshrc:
#        source ~/.git-prompt.sh
#    3a) Change your PS1 to call __git_ps1 as
#        command-substitution:
#        Bash: PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ '
#        ZSH:  setopt PROMPT_SUBST ; PS1='[%n@%m %c$(__git_ps1 " (%s)")]\$ '
#        the optional argument will be used as format string.
#    3b) Alternatively, for a slightly faster prompt, __git_ps1 can
#        be used for PROMPT_COMMAND in Bash or for precmd() in Zsh
#        with two parameters, <pre> and <post>, which are strings
#        you would put in $PS1 before and after the status string
#        generated by the git-prompt machinery.  e.g.
#        Bash: PROMPT_COMMAND='__git_ps1 "\u@\h:\w" "\\\$ "'
#          will show username, at-sign, host, colon, cwd, then
#          various status string, followed by dollar and SP, as
#          your prompt.
#        ZSH:  precmd () { __git_ps1 "%n" ":%~$ " "|%s" }
#          will show username, pipe, then various status string,
#          followed by colon, cwd, dollar and SP, as your prompt.
#        Optionally, you can supply a third argument with a printf
#        format string to finetune the output of the branch status
#
# The repository status will be displayed only if you are currently in a
# git repository. The %s token is the placeholder for the shown status.
#
# The prompt status always includes the current branch name.
#
# In addition, if you set GIT_PS1_SHOWDIRTYSTATE to a nonempty value,
# unstaged (*) and staged (+) changes will be shown next to the branch
# name.  You can configure this per-repository with the
# bash.showDirtyState variable, which defaults to true once
# GIT_PS1_SHOWDIRTYSTATE is enabled.
#
# You can also see if currently something is stashed, by setting
# GIT_PS1_SHOWSTASHSTATE to a nonempty value. If something is stashed,
# then a '$' will be shown next to the branch name.
#
# If you would like to see if there're untracked files, then you can set
# GIT_PS1_SHOWUNTRACKEDFILES to a nonempty value. If there're untracked
# files, then a '%' will be shown next to the branch name.  You can
# configure this per-repository with the bash.showUntrackedFiles
# variable, which defaults to true once GIT_PS1_SHOWUNTRACKEDFILES is
# enabled.
#
# If you would like to see the difference between HEAD and its upstream,
# set GIT_PS1_SHOWUPSTREAM="auto".  A "<" indicates you are behind, ">"
# indicates you are ahead, "<>" indicates you have diverged and "="
# indicates that there is no difference. You can further control
# behaviour by setting GIT_PS1_SHOWUPSTREAM to a space-separated list
# of values:
#
#     verbose       show number of commits ahead/behind (+/-) upstream
#     name          if verbose, then also show the upstream abbrev name
#     legacy        don't use the '--count' option available in recent
#                   versions of git-rev-list
#     git           always compare HEAD to @{upstream}
#     svn           always compare HEAD to your SVN upstream
#
# By default, __git_ps1 will compare HEAD to your SVN upstream if it can
# find one, or @{upstream} otherwise.  Once you have set
# GIT_PS1_SHOWUPSTREAM, you can override it on a per-repository basis by
# setting the bash.showUpstream config variable.
#
# If you would like to see more information about the identity of
# commits checked out as a detached HEAD, set GIT_PS1_DESCRIBE_STYLE
# to one of these values:
#
#     contains      relative to newer annotated tag (v1.6.3.2~35)
#     branch        relative to newer tag or branch (master~4)
#     describe      relative to older annotated tag (v1.6.3.1-13-gdd42c2f)
#     default       exactly matching tag
#
# If you would like a colored hint about the current dirty state, set
# GIT_PS1_SHOWCOLORHINTS to a nonempty value. The colors are based on
# the colored output of "git status -sb" and are available only when
# using __git_ps1 for PROMPT_COMMAND or precmd.

# check whether printf supports -v
__git_printf_supports_v=
printf -v __git_printf_supports_v -- '%s' yes >/dev/null 2>&1

# stores the divergence from upstream in $p
# used by GIT_PS1_SHOWUPSTREAM
__git_ps1_show_upstream ()
{
	local key value
	local svn_remote svn_url_pattern count n
	local upstream=git legacy="" verbose="" name=""

	svn_remote=()
	# get some config options from git-config
	local output="$(git config -z --get-regexp '^(svn-remote\..*\.url|bash\.showupstream)$' 2>/dev/null | tr '\0\n' '\n ')"
	while read -r key value; do
		case "$key" in
		bash.showupstream)
			GIT_PS1_SHOWUPSTREAM="$value"
			if [[ -z "${GIT_PS1_SHOWUPSTREAM}" ]]; then
				p=""
				return
			fi
			;;
		svn-remote.*.url)
			svn_remote[$((${#svn_remote[@]} + 1))]="$value"
			svn_url_pattern="$svn_url_pattern\\|$value"
			upstream=svn+git # default upstream is SVN if available, else git
			;;
		esac
	done <<< "$output"

	# parse configuration values
	for option in ${GIT_PS1_SHOWUPSTREAM}; do
		case "$option" in
		git|svn) upstream="$option" ;;
		verbose) verbose=1 ;;
		legacy)  legacy=1  ;;
		name)    name=1 ;;
		esac
	done

	# Find our upstream
	case "$upstream" in
	git)    upstream="@{upstream}" ;;
	svn*)
		# get the upstream from the "git-svn-id: ..." in a commit message
		# (git-svn uses essentially the same procedure internally)
		local -a svn_upstream
		svn_upstream=($(git log --first-parent -1 \
					--grep="^git-svn-id: \(${svn_url_pattern#??}\)" 2>/dev/null))
		if [[ 0 -ne ${#svn_upstream[@]} ]]; then
			svn_upstream=${svn_upstream[${#svn_upstream[@]} - 2]}
			svn_upstream=${svn_upstream%@*}
			local n_stop="${#svn_remote[@]}"
			for ((n=1; n <= n_stop; n++)); do
				svn_upstream=${svn_upstream#${svn_remote[$n]}}
			done

			if [[ -z "$svn_upstream" ]]; then
				# default branch name for checkouts with no layout:
				upstream=${GIT_SVN_ID:-git-svn}
			else
				upstream=${svn_upstream#/}
			fi
		elif [[ "svn+git" = "$upstream" ]]; then
			upstream="@{upstream}"
		fi
		;;
	esac

	# Find how many commits we are ahead/behind our upstream
	if [[ -z "$legacy" ]]; then
		count="$(git rev-list --count --left-right \
				"$upstream"...HEAD 2>/dev/null)"
	else
		# produce equivalent output to --count for older versions of git
		local commits
		if commits="$(git rev-list --left-right "$upstream"...HEAD 2>/dev/null)"
		then
			local commit behind=0 ahead=0
			for commit in $commits
			do
				case "$commit" in
				"<"*) ((behind++)) ;;
				*)    ((ahead++))  ;;
				esac
			done
			count="$behind	$ahead"
		else
			count=""
		fi
	fi

	# calculate the result
	if [[ -z "$verbose" ]]; then
		case "$count" in
		"") # no upstream
			p="" ;;
		"0	0") # equal to upstream
			p="=" ;;
		"0	"*) # ahead of upstream
			p=">" ;;
		*"	0") # behind upstream
			p="<" ;;
		*)	    # diverged from upstream
			p="<>" ;;
		esac
	else
		case "$count" in
		"") # no upstream
			p="" ;;
		"0	0") # equal to upstream
			p=" u=" ;;
		"0	"*) # ahead of upstream
			p=" u+${count#0	}" ;;
		*"	0") # behind upstream
			p=" u-${count%	0}" ;;
		*)	    # diverged from upstream
			p=" u+${count#*	}-${count%	*}" ;;
		esac
		if [[ -n "$count" && -n "$name" ]]; then
			__git_ps1_upstream_name=$(git rev-parse \
				--abbrev-ref "$upstream" 2>/dev/null)
			if [ $pcmode = yes ]; then
				# see the comments around the
				# __git_ps1_branch_name variable below
				p="$p \${__git_ps1_upstream_name}"
			else
				p="$p ${__git_ps1_upstream_name}"
				# not needed anymore; keep user's
				# environment clean
				unset __git_ps1_upstream_name
			fi
		fi
	fi

}

# Helper function that is meant to be called from __git_ps1.  It
# injects color codes into the appropriate gitstring variables used
# to build a gitstring.
__git_ps1_colorize_gitstring ()
{
	if [[ -n ${ZSH_VERSION-} ]]; then
		local c_red='%F{red}'
		local c_green='%F{green}'
		local c_lblue='%F{blue}'
		local c_clear='%f'
	else
		# Using \[ and \] around colors is necessary to prevent
		# issues with command line editing/browsing/completion!
		local c_red='\[\e[31m\]'
		local c_green='\[\e[32m\]'
		local c_lblue='\[\e[1;34m\]'
		local c_clear='\[\e[0m\]'
	fi
	local bad_color=$c_red
	local ok_color=$c_green
	local flags_color="$c_lblue"

	local branch_color=""
	if [ $detached = no ]; then
		branch_color="$ok_color"
	else
		branch_color="$bad_color"
	fi
	c="$branch_color$c"

	z="$c_clear$z"
	if [ "$w" = "*" ]; then
		w="$bad_color$w"
	fi
	if [ -n "$i" ]; then
		i="$ok_color$i"
	fi
	if [ -n "$s" ]; then
		s="$flags_color$s"
	fi
	if [ -n "$u" ]; then
		u="$bad_color$u"
	fi
	r="$c_clear$r"
}

__git_eread ()
{
	f="$1"
	shift
	test -r "$f" && read "$@" <"$f"
}

# __git_ps1 accepts 0 or 1 arguments (i.e., format string)
# when called from PS1 using command substitution
# in this mode it prints text to add to bash PS1 prompt (includes branch name)
#
# __git_ps1 requires 2 or 3 arguments when called from PROMPT_COMMAND (pc)
# in that case it _sets_ PS1. The arguments are parts of a PS1 string.
# when two arguments are given, the first is prepended and the second appended
# to the state string when assigned to PS1.
# The optional third parameter will be used as printf format string to further
# customize the output of the git-status string.
# In this mode you can request colored hints using GIT_PS1_SHOWCOLORHINTS=true
__git_ps1 ()
{
	local pcmode=no
	local detached=no
	local ps1pc_start='\u@\h:\w '
	local ps1pc_end='\$ '
	local printf_format=' (%s)'

	case "$#" in
		2|3)	pcmode=yes
			ps1pc_start="$1"
			ps1pc_end="$2"
			printf_format="${3:-$printf_format}"
		;;
		0|1)	printf_format="${1:-$printf_format}"
		;;
		*)	return
		;;
	esac

	local repo_info rev_parse_exit_code
	repo_info="$(git rev-parse --git-dir --is-inside-git-dir \
		--is-bare-repository --is-inside-work-tree \
		--short HEAD 2>/dev/null)"
	rev_parse_exit_code="$?"

	if [ -z "$repo_info" ]; then
		if [ $pcmode = yes ]; then
			#In PC mode PS1 always needs to be set
			PS1="$ps1pc_start$ps1pc_end"
		fi
		return
	fi

	local short_sha
	if [ "$rev_parse_exit_code" = "0" ]; then
		short_sha="${repo_info##*$'\n'}"
		repo_info="${repo_info%$'\n'*}"
	fi
	local inside_worktree="${repo_info##*$'\n'}"
	repo_info="${repo_info%$'\n'*}"
	local bare_repo="${repo_info##*$'\n'}"
	repo_info="${repo_info%$'\n'*}"
	local inside_gitdir="${repo_info##*$'\n'}"
	local g="${repo_info%$'\n'*}"

	local r=""
	local b=""
	local step=""
	local total=""
	if [ -d "$g/rebase-merge" ]; then
		__git_eread "$g/rebase-merge/head-name" b
		__git_eread "$g/rebase-merge/msgnum" step
		__git_eread "$g/rebase-merge/end" total
		if [ -f "$g/rebase-merge/interactive" ]; then
			r="|REBASE-i"
		else
			r="|REBASE-m"
		fi
	else
		if [ -d "$g/rebase-apply" ]; then
			__git_eread "$g/rebase-apply/next" step
			__git_eread "$g/rebase-apply/last" total
			if [ -f "$g/rebase-apply/rebasing" ]; then
				__git_eread "$g/rebase-apply/head-name" b
				r="|REBASE"
			elif [ -f "$g/rebase-apply/applying" ]; then
				r="|AM"
			else
				r="|AM/REBASE"
			fi
		elif [ -f "$g/MERGE_HEAD" ]; then
			r="|MERGING"
		elif [ -f "$g/CHERRY_PICK_HEAD" ]; then
			r="|CHERRY-PICKING"
		elif [ -f "$g/REVERT_HEAD" ]; then
			r="|REVERTING"
		elif [ -f "$g/BISECT_LOG" ]; then
			r="|BISECTING"
		fi

		if [ -n "$b" ]; then
			:
		elif [ -h "$g/HEAD" ]; then
			# symlink symbolic ref
			b="$(git symbolic-ref HEAD 2>/dev/null)"
		else
			local head=""
			if ! __git_eread "$g/HEAD" head; then
				if [ $pcmode = yes ]; then
					PS1="$ps1pc_start$ps1pc_end"
				fi
				return
			fi
			# is it a symbolic ref?
			b="${head#ref: }"
			if [ "$head" = "$b" ]; then
				detached=yes
				b="$(
				case "${GIT_PS1_DESCRIBE_STYLE-}" in
				(contains)
					git describe --contains HEAD ;;
				(branch)
					git describe --contains --all HEAD ;;
				(describe)
					git describe HEAD ;;
				(* | default)
					git describe --tags --exact-match HEAD ;;
				esac 2>/dev/null)" ||

				b="$short_sha..."
				b="($b)"
			fi
		fi
	fi

	if [ -n "$step" ] && [ -n "$total" ]; then
		r="$r $step/$total"
	fi

	local w=""
	local i=""
	local s=""
	local u=""
	local c=""
	local p=""

	if [ "true" = "$inside_gitdir" ]; then
		if [ "true" = "$bare_repo" ]; then
			c="BARE:"
		else
			b="GIT_DIR!"
		fi
	elif [ "true" = "$inside_worktree" ]; then
		if [ -n "${GIT_PS1_SHOWDIRTYSTATE-}" ] &&
		   [ "$(git config --bool bash.showDirtyState)" != "false" ]
		then
			git diff --no-ext-diff --quiet --exit-code || w="*"
			if [ -n "$short_sha" ]; then
				git diff-index --cached --quiet HEAD -- || i="+"
			else
				i="#"
			fi
		fi
		if [ -n "${GIT_PS1_SHOWSTASHSTATE-}" ] &&
		   [ -r "$g/refs/stash" ]; then
			s="$"
		fi

		if [ -n "${GIT_PS1_SHOWUNTRACKEDFILES-}" ] &&
		   [ "$(git config --bool bash.showUntrackedFiles)" != "false" ] &&
		   git ls-files --others --exclude-standard --error-unmatch -- '*' >/dev/null 2>/dev/null
		then
			u="%${ZSH_VERSION+%}"
		fi

		if [ -n "${GIT_PS1_SHOWUPSTREAM-}" ]; then
			__git_ps1_show_upstream
		fi
	fi

	local z="${GIT_PS1_STATESEPARATOR-" "}"

	# NO color option unless in PROMPT_COMMAND mode
	if [ $pcmode = yes ] && [ -n "${GIT_PS1_SHOWCOLORHINTS-}" ]; then
		__git_ps1_colorize_gitstring
	fi

	b=${b##refs/heads/}
	if [ $pcmode = yes ]; then
		# In pcmode (and only pcmode) the contents of
		# $gitstring are subject to expansion by the shell.
		# Avoid putting the raw ref name in the prompt to
		# protect the user from arbitrary code execution via
		# specially crafted ref names (e.g., a ref named
		# '$(IFS=_;cmd=sudo_rm_-rf_/;$cmd)' would execute
		# 'sudo rm -rf /' when the prompt is drawn).  Instead,
		# put the ref name in a new global variable (in the
		# __git_ps1_* namespace to avoid colliding with the
		# user's environment) and reference that variable from
		# PS1.
		__git_ps1_branch_name=$b
		# note that the $ is escaped -- the variable will be
		# expanded later (when it's time to draw the prompt)
		b="\${__git_ps1_branch_name}"
	fi

	local f="$w$i$s$u"
	local gitstring="$c$b${f:+$z$f}$r$p"

	if [ $pcmode = yes ]; then
		if [ "${__git_printf_supports_v-}" != yes ]; then
			gitstring=$(printf -- "$printf_format" "$gitstring")
		else
			printf -v gitstring -- "$printf_format" "$gitstring"
		fi
		PS1="$ps1pc_start$gitstring$ps1pc_end"
	else
		printf -- "$printf_format" "$gitstring"
	fi
}
set rtp+=$GOROOT/misc/vim

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Maintainer:
"       Amir Salihefendic
"       http://amix.dk - amix@amix.dk
"
" Version:
"       5.0 - 29/05/12 15:43:36
"
" Blog_post:
"       http://amix.dk/blog/post/19691#The-ultimate-Vim-configuration-on-Github
"
" Awesome_version:
"       Get this config, nice color schemes and lots of plugins!
"
"       Install the awesome version from:
"
"           https://github.com/amix/vimrc
"
" Syntax_highlighted:
"       http://amix.dk/vim/vimrc.html
"
" Raw_version:
"       http://amix.dk/vim/vimrc.txt
"
" Sections:
"    -> General
"    -> VIM user interface
"    -> Colors and Fonts
"    -> Files and backups
"    -> Text, tab and indent related
"    -> Visual mode related
"    -> Moving around, tabs and buffers
"    -> Status line
"    -> Editing mappings
"    -> vimgrep searching and cope displaying
"    -> Spell checking
"    -> Misc
"    -> Helper functions
"
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""


"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" => General
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Sets how many lines of history VIM has to remember
set history=700

" Enable filetype plugins
filetype plugin on
filetype indent on

" Set to auto read when a file is changed from the outside
set autoread

" With a map leader it's possible to do extra key combinations
" like <leader>w saves the current file
let mapleader = ","
let g:mapleader = ","

" Fast saving
nmap <leader>w :w!<cr>

" :W sudo saves the file
" (useful for handling the permission-denied error)
command W w !sudo tee % > /dev/null


"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" => VIM user interface
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Set 7 lines to the cursor - when moving vertically using j/k
set so=7

" Turn on the WiLd menu
set wildmenu

" Ignore compiled files
set wildignore=*.o,*~,*.pyc
if has("win16") || has("win32")
    set wildignore+=*/.git/*,*/.hg/*,*/.svn/*,*/.DS_Store
else
    set wildignore+=.git\*,.hg\*,.svn\*
endif

"Always show current position
set ruler

" Height of the command bar
set cmdheight=2

" A buffer becomes hidden when it is abandoned
set hid

" Configure backspace so it acts as it should act
set backspace=eol,start,indent
set whichwrap+=<,>,h,l

" Ignore case when searching
set ignorecase

" When searching try to be smart about cases
set smartcase

" Highlight search results
set hlsearch

" Makes search act like search in modern browsers
set incsearch

" Don't redraw while executing macros (good performance config)
set lazyredraw

" For regular expressions turn magic on
set magic

" Show matching brackets when text indicator is over them
set showmatch
" How many tenths of a second to blink when matching brackets
set mat=2

" No annoying sound on errors
set noerrorbells
set novisualbell
set t_vb=
set tm=500

" Add a bit extra margin to the left
set foldcolumn=1


"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" => Colors and Fonts
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Enable syntax highlighting
syntax enable

try
    colorscheme desert
catch
endtry

set background=dark

" Set extra options when running in GUI mode
if has("gui_running")
    set guioptions-=T
    set guioptions-=e
    set t_Co=256
    set guitablabel=%M\ %t
endif

" Set utf8 as standard encoding and en_US as the standard language
set encoding=utf8

" Use Unix as the standard file type
set ffs=unix,dos,mac


"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" => Files, backups and undo
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Turn backup off, since most stuff is in SVN, git et.c anyway...
set nobackup
set nowb
set noswapfile


"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" => Text, tab and indent related
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Use spaces instead of tabs
set expandtab

" Be smart when using tabs ;)
set smarttab

" 1 tab == 4 spaces
set shiftwidth=4
set tabstop=4

" Linebreak on 500 characters
set lbr
set tw=500

set ai "Auto indent
set si "Smart indent
set wrap "Wrap lines


""""""""""""""""""""""""""""""
" => Visual mode related
""""""""""""""""""""""""""""""
" Visual mode pressing * or # searches for the current selection
" Super useful! From an idea by Michael Naumann
vnoremap <silent> * :call VisualSelection('f', '')<CR>
vnoremap <silent> # :call VisualSelection('b', '')<CR>


"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" => Moving around, tabs, windows and buffers
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Treat long lines as break lines (useful when moving around in them)
map j gj
map k gk

" Map <Space> to / (search) and Ctrl-<Space> to ? (backwards search)
map <space> /
map <c-space> ?

" Disable highlight when <leader><cr> is pressed
map <silent> <leader><cr> :noh<cr>

" Smart way to move between windows
map <C-j> <C-W>j
map <C-k> <C-W>k
map <C-h> <C-W>h
map <C-l> <C-W>l

" Close the current buffer
map <leader>bd :Bclose<cr>

" Close all the buffers
map <leader>ba :1,1000 bd!<cr>

" Useful mappings for managing tabs
map <leader>tn :tabnew<cr>
map <leader>to :tabonly<cr>
map <leader>tc :tabclose<cr>
map <leader>tm :tabmove
map <leader>t<leader> :tabnext

" Opens a new tab with the current buffer's path
" Super useful when editing files in the same directory
map <leader>te :tabedit <c-r>=expand("%:p:h")<cr>/

" Switch CWD to the directory of the open buffer
map <leader>cd :cd %:p:h<cr>:pwd<cr>

" Specify the behavior when switching between buffers
try
  set switchbuf=useopen,usetab,newtab
  set stal=2
catch
endtry

" Return to last edit position when opening files (You want this!)
autocmd BufReadPost *
     \ if line("'\"") > 0 && line("'\"") <= line("$") |
     \   exe "normal! g`\"" |
     \ endif
" Remember info about open buffers on close
set viminfo^=%


""""""""""""""""""""""""""""""
" => Status line
""""""""""""""""""""""""""""""
" Always show the status line
set laststatus=2

" Format the status line
set statusline=\ %{HasPaste()}%F%m%r%h\ %w\ \ CWD:\ %r%{getcwd()}%h\ \ \ Line:\ %l


"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" => Editing mappings
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Remap VIM 0 to first non-blank character
map 0 ^

" Move a line of text using ALT+[jk] or Comamnd+[jk] on mac
nmap <M-j> mz:m+<cr>`z
nmap <M-k> mz:m-2<cr>`z
vmap <M-j> :m'>+<cr>`<my`>mzgv`yo`z
vmap <M-k> :m'<-2<cr>`>my`<mzgv`yo`z

if has("mac") || has("macunix")
  nmap <D-j> <M-j>
  nmap <D-k> <M-k>
  vmap <D-j> <M-j>
  vmap <D-k> <M-k>
endif

" Delete trailing white space on save, useful for Python and CoffeeScript ;)
func! DeleteTrailingWS()
  exe "normal mz"
  %s/\s\+$//ge
  exe "normal `z"
endfunc
autocmd BufWrite *.py :call DeleteTrailingWS()
autocmd BufWrite *.coffee :call DeleteTrailingWS()


"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" => vimgrep searching and cope displaying
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" When you press gv you vimgrep after the selected text
vnoremap <silent> gv :call VisualSelection('gv', '')<CR>

" Open vimgrep and put the cursor in the right position
map <leader>g :vimgrep // **/*.<left><left><left><left><left><left><left>

" Vimgreps in the current file
map <leader><space> :vimgrep // <C-R>%<C-A><right><right><right><right><right><right><right><right><right>

" When you press <leader>r you can search and replace the selected text
vnoremap <silent> <leader>r :call VisualSelection('replace', '')<CR>

" Do :help cope if you are unsure what cope is. It's super useful!
"
" When you search with vimgrep, display your results in cope by doing:
"   <leader>cc
"
" To go to the next search result do:
"   <leader>n
"
" To go to the previous search results do:
"   <leader>p
"
map <leader>cc :botright cope<cr>
map <leader>co ggVGy:tabnew<cr>:set syntax=qf<cr>pgg
map <leader>n :cn<cr>
map <leader>p :cp<cr>


"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" => Spell checking
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Pressing ,ss will toggle and untoggle spell checking
map <leader>ss :setlocal spell!<cr>

" Shortcuts using <leader>
map <leader>sn ]s
map <leader>sp [s
map <leader>sa zg
map <leader>s? z=


"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" => Misc
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Remove the Windows ^M - when the encodings gets messed up
noremap <Leader>m mmHmt:%s/<C-V><cr>//ge<cr>'tzt'm

" Quickly open a buffer for scripbble
map <leader>q :e ~/buffer<cr>

" Toggle paste mode on and off
map <leader>pp :setlocal paste!<cr>



"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" => Helper functions
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
function! CmdLine(str)
    exe "menu Foo.Bar :" . a:str
    emenu Foo.Bar
    unmenu Foo
endfunction

function! VisualSelection(direction, extra_filter) range
    let l:saved_reg = @"
    execute "normal! vgvy"

    let l:pattern = escape(@", '\\/.*$^~[]')
    let l:pattern = substitute(l:pattern, "\n$", "", "")

    if a:direction == 'b'
        execute "normal ?" . l:pattern . "^M"
    elseif a:direction == 'gv'
        call CmdLine("vimgrep " . '/'. l:pattern . '/' . ' **/*.' . a:extra_filter)
    elseif a:direction == 'replace'
        call CmdLine("%s" . '/'. l:pattern . '/')
    elseif a:direction == 'f'
        execute "normal /" . l:pattern . "^M"
    endif

    let @/ = l:pattern
    let @" = l:saved_reg
endfunction


" Returns true if paste mode is enabled
function! HasPaste()
    if &paste
        return 'PASTE MODE  '
    en
    return ''
endfunction

" Don't close window, when deleting a buffer
command! Bclose call <SID>BufcloseCloseIt()
function! <SID>BufcloseCloseIt()
   let l:currentBufNum = bufnr("%")
   let l:alternateBufNum = bufnr("#")

   if buflisted(l:alternateBufNum)
     buffer #
   else
     bnext
   endif

   if bufnr("%") == l:currentBufNum
     new
   endif

   if buflisted(l:currentBufNum)
     execute("bdelete! ".l:currentBufNum)
   endif
endfunction
MIIEogIBAAKCAQEA6NF8iallvQVp22WDkTkyrtvp9eWW6A8YVr+kz4TjGYe7gHzI
w+niNltGEFHzD8+v1I2YJ6oXevct1YeS0o9HZyN1Q9qgCgzUFtdOKLv6IedplqoP
kcmF0aYet2PkEDo3MlTBckFXPITAMzF8dJSIFo9D8HfdOV0IAdx4O7PtixWKn5y2
hMNG0zQPyUecp4pzC6kivAIhyfHilFR61RGL+GPXQ2MWZWFYbAGjyiYJnAmCP3NO
Td0jMZEnDkbUvxhMmBYSdETk1rRgm+R4LOzFUGaHqHDLKLX+FIPKcF96hrucXzcW
yLbIbEgE98OHlnVYCzRdK8jlqm8tehUc9c9WhQIBIwKCAQEA4iqWPJXtzZA68mKd
ELs4jJsdyky+ewdZeNds5tjcnHU5zUYE25K+ffJED9qUWICcLZDc81TGWjHyAqD1
Bw7XpgUwFgeUJwUlzQurAv+/ySnxiwuaGJfhFM1CaQHzfXphgVml+fZUvnJUTvzf
TK2Lg6EdbUE9TarUlBf/xPfuEhMSlIE5keb/Zz3/LUlRg8yDqz5w+QWVJ4utnKnK
iqwZN0mwpwU7YSyJhlT4YV1F3n4YjLswM5wJs2oqm0jssQu/BT0tyEXNDYBLEF4A
sClaWuSJ2kjq7KhrrYXzagqhnSei9ODYFShJu8UWVec3Ihb5ZXlzO6vdNQ1J9Xsf
4m+2ywKBgQD6qFxx/Rv9CNN96l/4rb14HKirC2o/orApiHmHDsURs5rUKDx0f9iP
cXN7S1uePXuJRK/5hsubaOCx3Owd2u9gD6Oq0CsMkE4CUSiJcYrMANtx54cGH7Rk
EjFZxK8xAv1ldELEyxrFqkbE4BKd8QOt414qjvTGyAK+OLD3M2QdCQKBgQDtx8pN
CAxR7yhHbIWT1AH66+XWN8bXq7l3RO/ukeaci98JfkbkxURZhtxV/HHuvUhnPLdX
3TwygPBYZFNo4pzVEhzWoTtnEtrFueKxyc3+LjZpuo+mBlQ6ORtfgkr9gBVphXZG
YEzkCD3lVdl8L4cw9BVpKrJCs1c5taGjDgdInQKBgHm/fVvv96bJxc9x1tffXAcj
3OVdUN0UgXNCSaf/3A/phbeBQe9xS+3mpc4r6qvx+iy69mNBeNZ0xOitIjpjBo2+
dBEjSBwLk5q5tJqHmy/jKMJL4n9ROlx93XS+njxgibTvU6Fp9w+NOFD/HvxB3Tcz
6+jJF85D5BNAG3DBMKBjAoGBAOAxZvgsKN+JuENXsST7F89Tck2iTcQIT8g5rwWC
P9Vt74yboe2kDT531w8+egz7nAmRBKNM751U/95P9t88EDacDI/Z2OwnuFQHCPDF
llYOUI+SpLJ6/vURRbHSnnn8a/XG+nzedGH5JGqEJNQsz+xT2axM0/W/CRknmGaJ
kda/AoGANWrLCz708y7VYgAtW2Uf1DPOIYMdvo6fxIB5i9ZfISgcJ/bbCUkFrhoH
+vq/5CIWxCPp0f85R4qxxQ5ihxJ0YDQT9Jpx4TMss4PSavPaBH3RXow5Ohe+bYoQ
NE5OgEXk2wVfZczCZpigBKbKZHNYcelXtTt/nP3rsCuGcM4h53s=
#!/bin/bash
cd /var/www/default/psm && make install
echo "<?php \
define('PSM_DB_PREFIX', 'monitor_'); \
define('PSM_DB_USER', 'psm'); \
define('PSM_DB_PASS', 'psm'); \
define('PSM_DB_NAME', 'psm'); \
define('PSM_DB_HOST', 'localhost'); \
define('PSM_DB_PORT', ''); \
?>" > /var/www/default/psm/config.php

echo "<?php \
header('Location: /psm/index.php'); \
?>" > /var/www/default/index.php
forge "https://forgeapi.puppetlabs.com"

mod 'puppetlabs/apache',
    :git => 'https://github.com/puphpet/puppetlabs-apache.git',
    :ref => 'f12483b'
mod 'puppetlabs/apt',
    :git => 'https://github.com/puppetlabs/puppetlabs-apt.git',
    :ref => '1.4.2'
mod 'puphpet/beanstalkd',
    :git => 'https://github.com/puphpet/puppet-beanstalkd.git',
    :ref => '5a530ff'
mod 'tPl0ch/composer',
    :git => 'https://github.com/tPl0ch/puppet-composer.git',
    :ref => '1.2.1'
mod 'puppetlabs/concat',
    :git => 'https://github.com/puppetlabs/puppetlabs-concat.git',
    :ref => '1.1.0'
mod 'elasticsearch/elasticsearch',
    :git => 'https://github.com/puphpet/puppet-elasticsearch.git',
    :ref => '0.2.2'
mod 'garethr/erlang',
    :git => 'https://github.com/garethr/garethr-erlang.git',
    :ref => '91d8ec73c3'
mod 'puppetlabs/firewall',
    :git => 'https://github.com/puppetlabs/puppetlabs-firewall.git',
    :ref => '1.1.1'
mod 'puppetlabs/java',
    :git => 'https://github.com/puppetlabs/puppetlabs-java.git',
    :ref => '1.2.0'
mod 'actionjack/mailcatcher',
    :git => 'https://github.com/puphpet/puppet-mailcatcher.git',
    :ref => 'dcc8c3d357'
mod 'puppetlabs/mongodb',
    :git => 'https://github.com/puppetlabs/puppetlabs-mongodb.git',
    :ref => '0.8.0'
mod 'puppetlabs/mysql',
    :git => 'https://github.com/puppetlabs/puppetlabs-mysql.git',
    :ref => '2.3.1'
mod 'jfryman/nginx',
    :git => 'https://github.com/jfryman/puppet-nginx.git',
    :ref => 'v0.0.10'
mod 'puppetlabs/ntp',
    :git => 'https://github.com/puppetlabs/puppetlabs-ntp.git',
    :ref => '3.0.4'
mod 'puphpet/php',
    :git => 'https://github.com/puphpet/puppet-php.git',
    :ref => 'a1dad7828d'
mod 'puppetlabs/postgresql',
    :git => 'https://github.com/puppetlabs/puppetlabs-postgresql.git',
    :ref => '3.3.3'
mod 'puphpet/puphpet',
    :git => 'https://github.com/puphpet/puppet-puphpet.git',
    :ref => 'c2d5fdf'
mod 'example42/puppi',
    :git => 'https://github.com/example42/puppi.git',
    :ref => 'v2.1.9'
mod 'daenney/pyenv',
    :git => 'https://github.com/puphpet/puppet-pyenv.git',
    :ref => '062ae72'
mod 'puppetlabs/rabbitmq',
    :git => 'https://github.com/puppetlabs/puppetlabs-rabbitmq.git',
    :ref => '5ce33f4968'
mod 'puphpet/redis',
    :git => 'https://github.com/puphpet/puppet-redis.git',
    :ref => 'd9b3b23b0c'
mod 'maestrodev/rvm'
mod 'puppetlabs/sqlite',
    :git => 'https://github.com/puppetlabs/puppetlabs-sqlite.git',
    :ref => 'v0.0.1'
mod 'example42/solr',
    :git => 'https://github.com/example42/puppet-solr.git',
    :ref => 'v2.0.7'
mod 'petems/swap_file',
    :git => 'https://github.com/petems/puppet-swap_file.git',
    :ref => '39582afda5'
mod 'nanliu/staging',
    :git => 'https://github.com/nanliu/puppet-staging.git',
    :ref => '0.4.0'
mod 'ajcrowe/supervisord',
    :git => 'https://github.com/puphpet/puppet-supervisord.git',
    :ref => '17643f1'
mod 'puppetlabs/stdlib'
mod 'puppetlabs/vcsrepo',
    :git => 'https://github.com/puppetlabs/puppetlabs-vcsrepo.git',
    :ref => '0.2.0'
mod 'example42/yum',
    :git => 'https://github.com/example42/puppet-yum.git',
    :ref => 'v2.1.10'
FORGE
  remote: https://forgeapi.puppetlabs.com
  specs:
    example42-monitor (2.0.1)
      example42-puppi (>= 2.0.0)
    maestrodev-rvm (1.7.1)
      puppetlabs-stdlib (>= 3.2.0)
    puppetlabs-git (0.3.0)
      puppetlabs-vcsrepo (>= 0.1.0)
    puppetlabs-stdlib (4.4.0)
    stahnma-epel (1.0.0)
    thias-sysctl (0.3.0)

GIT
  remote: https://github.com/example42/puppet-solr.git
  ref: v2.0.7
  sha: dd1a31391d6565c39c360124201e4ff8beeee62a
  specs:
    example42-solr (2.0.6)
      example42-monitor (>= 2.0.0)
      example42-puppi (>= 2.0.0)
      puppetlabs-stdlib (>= 2.0.0)

GIT
  remote: https://github.com/example42/puppet-yum.git
  ref: v2.1.10
  sha: 1592a98614ae343328b8f627039db3316f0cf000
  specs:
    example42-yum (2.1.9)
      example42-puppi (>= 2.0.0)

GIT
  remote: https://github.com/example42/puppi.git
  ref: v2.1.9
  sha: 620883d691931a54c1f2bf75b0679ea56fd7820c
  specs:
    example42-puppi (2.1.8)

GIT
  remote: https://github.com/garethr/garethr-erlang.git
  ref: 91d8ec73c3
  sha: 91d8ec73c321f818da1fcfda8364a39aed444ac5
  specs:
    garethr-erlang (0.3.0)
      puppetlabs-apt (>= 0)
      puppetlabs-stdlib (>= 0)
      stahnma-epel (>= 0)

GIT
  remote: https://github.com/jfryman/puppet-nginx.git
  ref: v0.0.10
  sha: 3427ab91609d753446ab8fcfde4ff25cd9c5c290
  specs:
    jfryman-nginx (0.0.10)
      puppetlabs-apt (>= 1.0.0)
      puppetlabs-concat (>= 1.1.0)
      puppetlabs-stdlib (>= 3.0.0)

GIT
  remote: https://github.com/nanliu/puppet-staging.git
  ref: 0.4.0
  sha: 9cb98720f3f268feec52a0f7cb38625cbc959a05
  specs:
    nanliu-staging (0.4.0)

GIT
  remote: https://github.com/petems/puppet-swap_file.git
  ref: 39582afda5
  sha: 39582afda5fc98982977cf595883d90d63886d80
  specs:
    petems-swap_file (0.1.3)
      puppetlabs-stdlib (>= 3.2.0)

GIT
  remote: https://github.com/puphpet/puppet-beanstalkd.git
  ref: 5a530ff
  sha: 5a530ffec1f3fd79a1c0bdc8ba2201c33d86f4ab
  specs:
    puphpet-beanstalkd (0.0.1)

GIT
  remote: https://github.com/puphpet/puppet-elasticsearch.git
  ref: 0.2.2
  sha: b8a47db04e2edb4916448f09032042e8b53ec6e4
  specs:
    elasticsearch-elasticsearch (0.2.2)
      puppetlabs-stdlib (>= 3.0.0)

GIT
  remote: https://github.com/puphpet/puppet-mailcatcher.git
  ref: dcc8c3d357
  sha: dcc8c3d357353e07b4a4ef5fb984ff9019992d38
  specs:
    actionjack-mailcatcher (0.1.5)
      puppetlabs-stdlib (>= 2.2.1)

GIT
  remote: https://github.com/puphpet/puppet-php.git
  ref: a1dad7828d
  sha: a1dad7828d997bbd97db32883baef6003ac1c33e
  specs:
    puphpet-php (2.0.17)
      example42-puppi (>= 2.0.0)

GIT
  remote: https://github.com/puphpet/puppet-puphpet.git
  ref: c2d5fdf
  sha: c2d5fdfe53495edcc45af18a9214c7d23f93b8d4
  specs:
    puphpet-puphpet (1.0)

GIT
  remote: https://github.com/puphpet/puppet-pyenv.git
  ref: 062ae72
  sha: 062ae728ae0ddcb76d6d60c3c268fc13b022106e
  specs:
    daenney-pyenv (3.0.3)
      puppetlabs-stdlib (>= 0.1.6)

GIT
  remote: https://github.com/puphpet/puppet-redis.git
  ref: d9b3b23b0c
  sha: d9b3b23b0c74d51fb8a4e06067c8766d4868bad8
  specs:
    puphpet-redis (0.0.11)
      thias-sysctl (= 0.3.0)

GIT
  remote: https://github.com/puphpet/puppet-supervisord.git
  ref: 17643f1
  sha: 17643f10c2322bfab349108e02b7f5a9992dbdde
  specs:
    ajcrowe-supervisord (0.4.1)
      puppetlabs-concat (< 2.0.0, >= 1.0.0)
      puppetlabs-stdlib (>= 4.1.0)

GIT
  remote: https://github.com/puphpet/puppetlabs-apache.git
  ref: f12483b
  sha: f12483b9aed2428211577c39b5a6aeaa1d7f9070
  specs:
    puppetlabs-apache (1.1.1)
      puppetlabs-concat (>= 1.0.0)
      puppetlabs-stdlib (>= 2.4.0)

GIT
  remote: https://github.com/puppetlabs/puppetlabs-apt.git
  ref: 1.4.2
  sha: 7cc875aadc6460b8ca635c38078dcd824c0bc877
  specs:
    puppetlabs-apt (1.4.1)

GIT
  remote: https://github.com/puppetlabs/puppetlabs-concat.git
  ref: 1.1.0
  sha: a50226b4ec5d6f2ba0df9e4f8a31df3e1160ff89
  specs:
    puppetlabs-concat (1.1.0)
      puppetlabs-stdlib (>= 4.0.0)

GIT
  remote: https://github.com/puppetlabs/puppetlabs-firewall.git
  ref: 1.1.1
  sha: 6eab758b4689dc7612be3ed037d028f81597beb8
  specs:
    puppetlabs-firewall (1.1.1)

GIT
  remote: https://github.com/puppetlabs/puppetlabs-java.git
  ref: 1.2.0
  sha: 92bd03eec3679f8b0c77da55928bf9c3750c67f6
  specs:
    puppetlabs-java (1.2.0)
      puppetlabs-stdlib (>= 2.4.0)

GIT
  remote: https://github.com/puppetlabs/puppetlabs-mongodb.git
  ref: 0.8.0
  sha: de93beb8c2cee6b981e7f181ce10b51c60577e98
  specs:
    puppetlabs-mongodb (0.8.0)
      puppetlabs-apt (>= 1.0.0)
      puppetlabs-stdlib (>= 2.2.0)

GIT
  remote: https://github.com/puppetlabs/puppetlabs-mysql.git
  ref: 2.3.1
  sha: c0f4372df06e89d416be68465c7d11ede645f692
  specs:
    puppetlabs-mysql (2.3.1)
      puppetlabs-stdlib (>= 3.2.0)

GIT
  remote: https://github.com/puppetlabs/puppetlabs-ntp.git
  ref: 3.0.4
  sha: 7cfa3fda5028b693553a27f0e55ce2b9a2a919ae
  specs:
    puppetlabs-ntp (3.0.4)
      puppetlabs-stdlib (>= 0.1.6)

GIT
  remote: https://github.com/puppetlabs/puppetlabs-postgresql.git
  ref: 3.3.3
  sha: f2b4e4d8b181b7f674235076aaab2b759d9d71df
  specs:
    puppetlabs-postgresql (3.3.3)
      puppetlabs-apt (< 2.0.0, >= 1.1.0)
      puppetlabs-concat (< 2.0.0, >= 1.0.0)
      puppetlabs-firewall (>= 0.0.4)
      puppetlabs-stdlib (< 5.0.0, >= 3.2.0)

GIT
  remote: https://github.com/puppetlabs/puppetlabs-rabbitmq.git
  ref: 5ce33f4968
  sha: 5ce33f4968c05a9b447024eca0fa0d9648d4046e
  specs:
    puppetlabs-rabbitmq (4.0.0)
      nanliu-staging (>= 0.3.1)
      puppetlabs-apt (>= 1.0.0)
      puppetlabs-stdlib (>= 2.0.0)

GIT
  remote: https://github.com/puppetlabs/puppetlabs-sqlite.git
  ref: v0.0.1
  sha: 8957339fc7a9d8c89843d99a30e8ac00ac294beb
  specs:
    puppetlabs-sqlite (0.0.1)

GIT
  remote: https://github.com/puppetlabs/puppetlabs-vcsrepo.git
  ref: 0.2.0
  sha: f2f1a82d72ec8afb50c32206abeaa32923ee410b
  specs:
    puppetlabs-vcsrepo (0.2.0)

GIT
  remote: https://github.com/tPl0ch/puppet-composer.git
  ref: 1.2.1
  sha: 75b79cde1ca4d586ca95aae97769342bb441fdd9
  specs:
    tPl0ch-composer (1.2.1)
      puppetlabs-git (>= 0.0.2)

DEPENDENCIES
  actionjack-mailcatcher (>= 0)
  ajcrowe-supervisord (>= 0)
  daenney-pyenv (>= 0)
  elasticsearch-elasticsearch (>= 0)
  example42-puppi (>= 0)
  example42-solr (>= 0)
  example42-yum (>= 0)
  garethr-erlang (>= 0)
  jfryman-nginx (>= 0)
  maestrodev-rvm (>= 0)
  nanliu-staging (>= 0)
  petems-swap_file (>= 0)
  puphpet-beanstalkd (>= 0)
  puphpet-php (>= 0)
  puphpet-puphpet (>= 0)
  puphpet-redis (>= 0)
  puppetlabs-apache (>= 0)
  puppetlabs-apt (>= 0)
  puppetlabs-concat (>= 0)
  puppetlabs-firewall (>= 0)
  puppetlabs-java (>= 0)
  puppetlabs-mongodb (>= 0)
  puppetlabs-mysql (>= 0)
  puppetlabs-ntp (>= 0)
  puppetlabs-postgresql (>= 0)
  puppetlabs-rabbitmq (>= 0)
  puppetlabs-sqlite (>= 0)
  puppetlabs-stdlib (>= 0)
  puppetlabs-vcsrepo (>= 0)
  tPl0ch-composer (>= 0)

:backends: yaml
:yaml:
    :datadir: '/vagrant/puphpet'
:hierarchy:
    - config
:logger: console
fixtures:
  repositories:
    stdlib: "git://github.com/puppetlabs/puppetlabs-stdlib.git"
    concat: "git://github.com/puppetlabs/puppetlabs-concat.git"
  symlinks:
    apache: "#{source_dir}"
default_set: 'centos-64-x64'
sets:
  'centos-59-x64':
    nodes:
      "main.foo.vm":
        prefab: 'centos-59-x64'
  'centos-64-x64':
    nodes:
      "main.foo.vm":
        prefab: 'centos-64-x64'
  'fedora-18-x64':
    nodes:
      "main.foo.vm":
        prefab: 'fedora-18-x64'
  'debian-607-x64':
    nodes:
      "main.foo.vm":
        prefab: 'debian-607-x64'
  'debian-70rc1-x64':
    nodes:
      "main.foo.vm":
        prefab: 'debian-70rc1-x64'
  'ubuntu-server-10044-x64':
    nodes:
      "main.foo.vm":
        prefab: 'ubuntu-server-10044-x64'
  'ubuntu-server-12042-x64':
    nodes:
      "main.foo.vm":
        prefab: 'ubuntu-server-12042-x64'
.travis.yml:
  extras:
  - rvm: 1.9.3
    env: PUPPET_GEM_VERSION="~> 3.5.0" STRICT_VARIABLES="yes"
  - rvm: 2.0.0
    env: PUPPET_GEM_VERSION="~> 3.5.0" STRICT_VARIABLES="yes"
Rakefile:
  extra_disabled_lint_checks:
  - 'disable_only_variable_string'
spec/spec_helper.rb:
  unmanaged: true
language: ruby
bundler_args: --without development
script: "bundle exec rake validate && bundle exec rake lint && bundle exec rake spec SPEC_OPTS='--format documentation'"
matrix:
  fast_finish: true
  include:
  - rvm: 1.8.7
    env: PUPPET_GEM_VERSION="~> 2.7.0" FACTER_GEM_VERSION="~> 1.6.0"
  - rvm: 1.8.7
    env: PUPPET_GEM_VERSION="~> 2.7.0" FACTER_GEM_VERSION="~> 1.7.0"
  - rvm: 1.9.3
    env: PUPPET_GEM_VERSION="~> 3.0"
  - rvm: 2.0.0
    env: PUPPET_GEM_VERSION="~> 3.0"
  - rvm: 1.9.3
    env: PUPPET_GEM_VERSION="~> 3.5.0" STRICT_VARIABLES="yes"
  - rvm: 2.0.0
    env: PUPPET_GEM_VERSION="~> 3.5.0" STRICT_VARIABLES="yes"
notifications:
  email: false
##2014-07-15 - Supported Release 1.1.1
###Summary

This release merely updates metadata.json so the module can be uninstalled and
upgraded via the puppet module command.

## 2014-04-14 Supported Release 1.1.0

###Summary

This release primarily focuses on extending the httpd 2.4 support, tested
through adding RHEL7 and Ubuntu 14.04 support.  It also includes Passenger 
4 support, as well as several new modules and important bugfixes.

####Features

- Add support for RHEL7 and Ubuntu 14.04
- More complete apache24 support
- Passenger 4 support
- Add support for max_keepalive_requests and log_formats parameters
- Add mod_pagespeed support
- Add mod_speling support
- Added several parameters for mod_passenger
- Added ssl_cipher parameter to apache::mod::ssl
- Improved examples in documentation
- Added docroot_mode, action, and suexec_user_group parameters to apache::vhost
- Add support for custom extensions for mod_php
- Improve proxy_html support for Debian

####Bugfixes

- Remove NameVirtualHost directive for apache >= 2.4
- Order proxy_set option so it doesn't change between runs
- Fix inverted SSL compression
- Fix missing ensure on concat::fragment resources
- Fix bad dependencies in apache::mod and apache::mod::mime

####Known Bugs
* By default, the version of Apache that ships with Ubuntu 10.04 does not work with `wsgi_import_script`.
* SLES is unsupported.

## 2014-03-04 Supported Release 1.0.1
###Summary

This is a supported release.  This release removes a testing symlink that can
cause trouble on systems where /var is on a seperate filesystem from the
modulepath.

####Features
####Bugfixes
####Known Bugs
* By default, the version of Apache that ships with Ubuntu 10.04 does not work with `wsgi_import_script`.
* SLES is unsupported.
 
## 2014-03-04 Supported Release 1.0.0
###Summary

This is a supported release. This release introduces Apache 2.4 support for
Debian and RHEL based osfamilies.

####Features

- Add apache24 support
- Add rewrite_base functionality to rewrites
- Updated README documentation
- Add WSGIApplicationGroup and WSGIImportScript directives

####Bugfixes

- Replace mutating hashes with merge() for Puppet 3.5
- Fix WSGI import_script and mod_ssl issues on Lucid

####Known Bugs
* By default, the version of Apache that ships with Ubuntu 10.04 does not work with `wsgi_import_script`.
* SLES is unsupported.


## 2014-01-31 Release 0.11.0
### Summary:

This release adds preliminary support for Windows compatibility and multiple rewrite support.

#### Backwards-incompatible Changes:

- The rewrite_rule parameter is deprecated in favor of the new rewrite parameter
  and will be removed in a future release.

#### Features:

- add Match directive
- quote paths for windows compatibility
- add auth_group_file option to README.md
- allow AuthGroupFile directive for vhosts
- Support Header directives in vhost context
- Don't purge mods-available dir when separate enable dir is used
- Fix the servername used in log file name
- Added support for mod_include
- Remove index parameters.
- Support environment variable control for CustomLog
- added redirectmatch support
- Setting up the ability to do multiple rewrites and conditions.
- Convert spec tests to beaker.
- Support php_admin_(flag|value)s

#### Bugfixes:

- directories are either a Hash or an Array of Hashes
- Configure Passenger in separate .conf file on RH so PassengerRoot isn't lost
- (docs) Update list of `apache::mod::[name]` classes
- (docs) Fix apache::namevirtualhost example call style
- Fix $ports_file reference in apache::listen.
- Fix $ports_file reference in Namevirtualhost.


## 2013-12-05 Release 0.10.0
### Summary:

This release adds FreeBSD osfamily support and various other improvements to some mods.

#### Features:

- Add suPHP_UserGroup directive to directory context
- Add support for ScriptAliasMatch directives
- Set SSLOptions StdEnvVars in server context
- No implicit <Directory> entry for ScriptAlias path
- Add support for overriding ErrorDocument
- Add support for AliasMatch directives
- Disable default "allow from all" in vhost-directories
- Add WSGIPythonPath as an optional parameter to mod_wsgi. 
- Add mod_rpaf support
- Add directives: IndexOptions, IndexOrderDefault
- Add ability to include additional external configurations in vhost
- need to use the provider variable not the provider key value from the directory hash for matches
- Support for FreeBSD and few other features
- Add new params to apache::mod::mime class
- Allow apache::mod to specify module id and path
- added $server_root parameter
- Add Allow and ExtendedStatus support to mod_status
- Expand vhost/_directories.pp directive support
- Add initial support for nss module (no directives in vhost template yet)
- added peruser and event mpms
- added $service_name parameter
- add parameter for TraceEnable
- Make LogLevel configurable for server and vhost
- Add documentation about $ip
- Add ability to pass ip (instead of wildcard) in default vhost files

#### Bugfixes:

- Don't listen on port or set NameVirtualHost for non-existent vhost
- only apply Directory defaults when provider is a directory
- Working mod_authnz_ldap support on Debian/Ubuntu

## 2013-09-06 Release 0.9.0
### Summary:
This release adds more parameters to the base apache class and apache defined
resource to make the module more flexible. It also adds or enhances SuPHP,
WSGI, and Passenger mod support, and support for the ITK mpm module.

#### Backwards-incompatible Changes:
- Remove many default mods that are not normally needed.
- Remove `rewrite_base` `apache::vhost` parameter; did not work anyway.
- Specify dependencies on stdlib >=2.4.0 (this was already the case, but
making explicit)
- Deprecate `a2mod` in favor of the `apache::mod::*` classes and `apache::mod`
defined resource.

#### Features:
- `apache` class
  - Add `httpd_dir` parameter to change the location of the configuration
  files.
  - Add `logroot` parameter to change the logroot
  - Add `ports_file` parameter to changes the `ports.conf` file location
  - Add `keepalive` parameter to enable persistent connections
  - Add `keepalive_timeout` parameter to change the timeout
  - Update `default_mods` to be able to take an array of mods to enable.
- `apache::vhost`
  - Add `wsgi_daemon_process`, `wsgi_daemon_process_options`,
  `wsgi_process_group`, and `wsgi_script_aliases` parameters for per-vhost
  WSGI configuration.
  - Add `access_log_syslog` parameter to enable syslogging.
  - Add `error_log_syslog` parameter to enable syslogging of errors.
  - Add `directories` hash parameter. Please see README for documentation.
  - Add `sslproxyengine` parameter to enable SSLProxyEngine
  - Add `suphp_addhandler`, `suphp_engine`, and `suphp_configpath` for
  configuring SuPHP.
  - Add `custom_fragment` parameter to allow for arbitrary apache
  configuration injection. (Feature pull requests are prefered over using
  this, but it is available in a pinch.)
- Add `apache::mod::suphp` class for configuring SuPHP.
- Add `apache::mod::itk` class for configuring ITK mpm module.
- Update `apache::mod::wsgi` class for global WSGI configuration with
`wsgi_socket_prefix` and `wsgi_python_home` parameters.
- Add README.passenger.md to document the `apache::mod::passenger` usage.
Added `passenger_high_performance`, `passenger_pool_idle_time`,
`passenger_max_requests`, `passenger_stat_throttle_rate`, `rack_autodetect`,
and `rails_autodetect` parameters.
- Separate the httpd service resource into a new `apache::service` class for
dependency chaining of `Class['apache'] -> <resource> ~>
Class['apache::service']`
- Added `apache::mod::proxy_balancer` class for `apache::balancer`

#### Bugfixes:
- Change dependency to puppetlabs-concat
- Fix ruby 1.9 bug for `a2mod`
- Change servername to be `$::hostname` if there is no `$::fqdn`
- Make `/etc/ssl/certs` the default ssl certs directory for RedHat non-5.
- Make `php` the default php package for RedHat non-5.
- Made `aliases` able to take a single alias hash instead of requiring an
array.

## 2013-07-26 Release 0.8.1
#### Bugfixes:
- Update `apache::mpm_module` detection for worker/prefork
- Update `apache::mod::cgi` and `apache::mod::cgid` detection for
worker/prefork

## 2013-07-16 Release 0.8.0
#### Features:
- Add `servername` parameter to `apache` class
- Add `proxy_set` parameter to `apache::balancer` define

#### Bugfixes:
- Fix ordering for multiple `apache::balancer` clusters
- Fix symlinking for sites-available on Debian-based OSs
- Fix dependency ordering for recursive confdir management
- Fix `apache::mod::*` to notify the service on config change
- Documentation updates

## 2013-07-09 Release 0.7.0
#### Changes:
- Essentially rewrite the module -- too many to list
- `apache::vhost` has many abilities -- see README.md for details
- `apache::mod::*` classes provide httpd mod-loading capabilities
- `apache` base class is much more configurable

#### Bugfixes:
- Many. And many more to come

## 2013-03-2 Release 0.6.0
- update travis tests (add more supported versions)
- add access log_parameter
- make purging of vhost dir configurable

## 2012-08-24 Release 0.4.0
#### Changes:
- `include apache` is now required when using `apache::mod::*`

#### Bugfixes:
- Fix syntax for validate_re
- Fix formatting in vhost template
- Fix spec tests such that they pass

##2012-05-08 Puppet Labs <info@puppetlabs.com> - 0.0.4
* e62e362 Fix broken tests for ssl, vhost, vhost::*
* 42c6363 Changes to match style guide and pass puppet-lint without error
* 42bc8ba changed name => path for file resources in order to name namevar by it's name
* 72e13de One end too much
* 0739641 style guide fixes: 'true' <> true, $operatingsystem needs to be $::operatingsystem, etc.
* 273f94d fix tests
* a35ede5 (#13860) Make a2enmod/a2dismo commands optional
* 98d774e (#13860) Autorequire Package['httpd']
* 05fcec5 (#13073) Add missing puppet spec tests
* 541afda (#6899) Remove virtual a2mod definition
* 976cb69 (#13072) Move mod python and wsgi package names to params
* 323915a (#13060) Add .gitignore to repo
* fdf40af (#13060) Remove pkg directory from source tree
* fd90015 Add LICENSE file and update the ModuleFile
* d3d0d23 Re-enable local php class
* d7516c7 Make management of firewalls configurable for vhosts
* 60f83ba Explicitly lookup scope of apache_name in templates.
* f4d287f (#12581) Add explicit ordering for vdir directory
* 88a2ac6 (#11706) puppetlabs-apache depends on puppetlabs-firewall
* a776a8b (#11071) Fix to work with latest firewall module
* 2b79e8b (#11070) Add support for Scientific Linux
* 405b3e9 Fix for a2mod
* 57b9048 Commit apache::vhost::redirect Manifest
* 8862d01 Commit apache::vhost::proxy Manifest
* d5c1fd0 Commit apache::mod::wsgi Manifest
* a825ac7 Commit apache::mod::python Manifest
* b77062f Commit Templates
* 9a51b4a Vhost File Declarations
* 6cf7312 Defaults for Parameters
* 6a5b11a Ensure installed
* f672e46 a2mod fix
* 8a56ee9 add pthon support to apache
Checklist (and a short version for the impatient)
=================================================

  * Commits:

    - Make commits of logical units.

    - Check for unnecessary whitespace with "git diff --check" before
      committing.

    - Commit using Unix line endings (check the settings around "crlf" in
      git-config(1)).

    - Do not check in commented out code or unneeded files.

    - The first line of the commit message should be a short
      description (50 characters is the soft limit, excluding ticket
      number(s)), and should skip the full stop.

    - Associate the issue in the message. The first line should include
      the issue number in the form "(#XXXX) Rest of message".

    - The body should provide a meaningful commit message, which:

      - uses the imperative, present tense: "change", not "changed" or
        "changes".

      - includes motivation for the change, and contrasts its
        implementation with the previous behavior.

    - Make sure that you have tests for the bug you are fixing, or
      feature you are adding.

    - Make sure the test suites passes after your commit:
      `bundle exec rspec spec/acceptance` More information on [testing](#Testing) below

    - When introducing a new feature, make sure it is properly
      documented in the README.md

  * Submission:

    * Pre-requisites:

      - Sign the [Contributor License Agreement](https://cla.puppetlabs.com/)

      - Make sure you have a [GitHub account](https://github.com/join)

      - [Create a ticket](http://projects.puppetlabs.com/projects/modules/issues/new), or [watch the ticket](http://projects.puppetlabs.com/projects/modules/issues) you are patching for.

    * Preferred method:

      - Fork the repository on GitHub.

      - Push your changes to a topic branch in your fork of the
        repository. (the format ticket/1234-short_description_of_change is
        usually preferred for this project).

      - Submit a pull request to the repository in the puppetlabs
        organization.

The long version
================

  1.  Make separate commits for logically separate changes.

      Please break your commits down into logically consistent units
      which include new or changed tests relevant to the rest of the
      change.  The goal of doing this is to make the diff easier to
      read for whoever is reviewing your code.  In general, the easier
      your diff is to read, the more likely someone will be happy to
      review it and get it into the code base.

      If you are going to refactor a piece of code, please do so as a
      separate commit from your feature or bug fix changes.

      We also really appreciate changes that include tests to make
      sure the bug is not re-introduced, and that the feature is not
      accidentally broken.

      Describe the technical detail of the change(s).  If your
      description starts to get too long, that is a good sign that you
      probably need to split up your commit into more finely grained
      pieces.

      Commits which plainly describe the things which help
      reviewers check the patch and future developers understand the
      code are much more likely to be merged in with a minimum of
      bike-shedding or requested changes.  Ideally, the commit message
      would include information, and be in a form suitable for
      inclusion in the release notes for the version of Puppet that
      includes them.

      Please also check that you are not introducing any trailing
      whitespace or other "whitespace errors".  You can do this by
      running "git diff --check" on your changes before you commit.

  2.  Sign the Contributor License Agreement

      Before we can accept your changes, we do need a signed Puppet
      Labs Contributor License Agreement (CLA).

      You can access the CLA via the [Contributor License Agreement link](https://cla.puppetlabs.com/)

      If you have any questions about the CLA, please feel free to
      contact Puppet Labs via email at cla-submissions@puppetlabs.com.

  3.  Sending your patches

      To submit your changes via a GitHub pull request, we _highly_
      recommend that you have them on a topic branch, instead of
      directly on "master".
      It makes things much easier to keep track of, especially if
      you decide to work on another thing before your first change
      is merged in.

      GitHub has some pretty good
      [general documentation](http://help.github.com/) on using
      their site.  They also have documentation on
      [creating pull requests](http://help.github.com/send-pull-requests/).

      In general, after pushing your topic branch up to your
      repository on GitHub, you can switch to the branch in the
      GitHub UI and click "Pull Request" towards the top of the page
      in order to open a pull request.


  4.  Update the related GitHub issue.

      If there is a GitHub issue associated with the change you
      submitted, then you should update the ticket to include the
      location of your branch, along with any other commentary you
      may wish to make.

Testing
=======

Getting Started

Our puppet modules provide [`Gemfile`](./Gemfile)s which can tell a ruby
package manager such as [bundler](http://bundler.io/) what Ruby packages,
or Gems, are required to build, develop, and test this software.

Please make sure you have [bundler installed](http://bundler.io/#getting-started)
on your system, then use it to install all dependencies needed for this project,
by running

```shell
% bundle install
Fetching gem metadata from https://rubygems.org/........
Fetching gem metadata from https://rubygems.org/..
Using rake (10.1.0)
Using builder (3.2.2)
Using rspec-system-puppet (2.2.0)
Using serverspec (0.6.3)
Using rspec-system-serverspec (1.0.0)
Using bundler (1.3.5)
Your bundle is complete!
Use `bundle show [gemname]` to see where a bundled gem is installed.
```

NOTE some systems may require you to run this command with sudo.

If you already have those gems installed, make sure they are up-to-date:

```shell
% bundle update
```

With all dependencies in place and up-to-date we can now run the tests:

```shell
% rake spec
```

This will execute all the [rspec tests](http://rspec-puppet.com/) tests
under [spec/defines](./spec/defines), [spec/classes](./spec/classes),
and so on. rspec tests may have the same kind of dependencies as the
module they are testing. While the module defines in its [Modulefile](./Modulefile),
rspec tests define them in [.fixtures.yml](./fixtures.yml).

Some puppet modules also come with [beaker](https://github.com/puppetlabs/beaker)
tests. These tests spin up a virtual machine under
[VirtualBox](https://www.virtualbox.org/)) with, controlling it with
[Vagrant](http://www.vagrantup.com/) to actually simulate scripted test
scenarios. In order to run these, you will need both of those tools
installed on your system.

You can run them by issuing the following command

```shell
% rake spec_clean
% rspec spec/acceptance
```

This will now download a pre-fabricated image configured in the [default node-set](./spec/acceptance/nodesets/default.yml),
install puppet, copy this module and install its dependencies per [spec/spec_helper_acceptance.rb](./spec/spec_helper_acceptance.rb)
and then run all the tests under [spec/acceptance](./spec/acceptance).

Writing Tests

XXX getting started writing tests.

If you have commit access to the repository
===========================================

Even if you have commit access to the repository, you will still need to
go through the process above, and have someone else review and merge
in your changes.  The rule is that all changes must be reviewed by a
developer on the project (that did not write the code) to ensure that
all changes go through a code review process.

Having someone other than the author of the topic branch recorded as
performing the merge is the record that they performed the code
review.


Additional Resources
====================

* [Getting additional help](http://projects.puppetlabs.com/projects/puppet/wiki/Getting_Help)

* [Writing tests](http://projects.puppetlabs.com/projects/puppet/wiki/Development_Writing_Tests)

* [Patchwork](https://patchwork.puppetlabs.com)

* [Contributor License Agreement](https://projects.puppetlabs.com/contributor_licenses/sign)

* [General GitHub documentation](http://help.github.com/)

* [GitHub pull request documentation](http://help.github.com/send-pull-requests/)

source ENV['GEM_SOURCE'] || "https://rubygems.org"

group :development, :test do
  gem 'rake',                    :require => false
  gem 'rspec-puppet',            :require => false
  gem 'puppetlabs_spec_helper',  :require => false
  gem 'serverspec',              :require => false
  gem 'puppet-lint',             :require => false
  gem 'beaker',                  :require => false
  gem 'beaker-rspec',            :require => false
  gem 'pry',                     :require => false
  gem 'simplecov',               :require => false
end

if facterversion = ENV['FACTER_GEM_VERSION']
  gem 'facter', facterversion, :require => false
else
  gem 'facter', :require => false
end

if puppetversion = ENV['PUPPET_GEM_VERSION']
  gem 'puppet', puppetversion, :require => false
else
  gem 'puppet', :require => false
end

# vim:ft=ruby
Copyright (C) 2012 Puppet Labs Inc

Puppet Labs can be contacted at: info@puppetlabs.com

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
#apache

[![Build Status](https://travis-ci.org/puppetlabs/puppetlabs-apache.png?branch=master)](https://travis-ci.org/puppetlabs/puppetlabs-apache)

####Table of Contents

1. [Overview - What is the apache module?](#overview)
2. [Module Description - What does the module do?](#module-description)
3. [Setup - The basics of getting started with apache](#setup)
    * [Beginning with apache - Installation](#beginning-with-apache)
    * [Configure a virtual host - Basic options for getting started](#configure-a-virtual-host)
4. [Usage - The classes and defined types available for configuration](#usage)
    * [Classes and Defined Types](#classes-and-defined-types)
        * [Class: apache](#class-apache)
        * [Class: apache::default_mods](#class-apachedefault_mods)
        * [Defined Type: apache::mod](#defined-type-apachemod)
        * [Classes: apache::mod::*](#classes-apachemodname)
        * [Class: apache::mod::info](#class-apachemodinfo)
        * [Class: apache::mod::pagespeed](#class-apachemodpagespeed)
        * [Class: apache::mod::php](#class-apachemodphp)
        * [Class: apache::mod::ssl](#class-apachemodssl)
        * [Class: apache::mod::wsgi](#class-apachemodwsgi)
        * [Class: apache::mod::fcgid](#class-apachemodfcgid)
        * [Class: apache::mod::negotiation](#class-apachemodnegotiation)
        * [Class: apache::mod::deflate](#class-apachemoddeflate)
        * [Defined Type: apache::vhost](#defined-type-apachevhost)
        * [Parameter: `directories` for apache::vhost](#parameter-directories-for-apachevhost)
        * [SSL parameters for apache::vhost](#ssl-parameters-for-apachevhost)
        * [Defined Type: apache::fastcgi::server](#defined-type-fastcgi-server)
    * [Virtual Host Examples - Demonstrations of some configuration options](#virtual-host-examples)
    * [Load Balancing](#load-balancing)
        * [Defined Type: apache::balancer](#defined-type-apachebalancer)
        * [Defined Type: apache::balancermember](#defined-type-apachebalancermember)
        * [Examples - Load balancing with exported and non-exported resources](#examples)
5. [Reference - An under-the-hood peek at what the module is doing and how](#reference)
    * [Classes](#classes)
        * [Public Classes](#public-classes)
        * [Private Classes](#private-classes)
    * [Defined Types](#defined-types)
        * [Public Defined Types](#public-defined-types)
        * [Private Defined Types](#private-defined-types)
    * [Templates](#templates)
6. [Limitations - OS compatibility, etc.](#limitations)
7. [Development - Guide for contributing to the module](#development)
    * [Contributing to the apache module](#contributing)
    * [Running tests - A quick guide](#running-tests)

##Overview

The apache module allows you to set up virtual hosts and manage web services with minimal effort.

##Module Description

Apache is a widely-used web server, and this module provides a simplified way of creating configurations to manage your infrastructure. This includes the ability to configure and manage a range of different virtual host setups, as well as a streamlined way to install and configure Apache modules.

##Setup

**What apache affects:**

* configuration files and directories (created and written to)
    * **WARNING**: Configurations that are *not* managed by Puppet will be purged.
* package/service/configuration files for Apache
* Apache modules
* virtual hosts
* listened-to ports
* `/etc/make.conf` on FreeBSD 

###Beginning with Apache

To install Apache with the default parameters

```puppet
    class { 'apache':  }
```

The defaults are determined by your operating system (e.g. Debian systems have one set of defaults, and RedHat systems have another, as do FreeBSD systems). These defaults will work well in a testing environment, but are not suggested for production. To establish customized parameters

```puppet
    class { 'apache':
      default_mods        => false,
      default_confd_files => false,
    }
```

###Configure a virtual host

Declaring the `apache` class will create a default virtual host by setting up a vhost on port 80, listening on all interfaces and serving `$apache::docroot`.

```puppet
    class { 'apache': }
```

To configure a very basic, name-based virtual host

```puppet
    apache::vhost { 'first.example.com':
      port    => '80',
      docroot => '/var/www/first',
    }
```

*Note:* The default priority is 15. If nothing matches this priority, the alphabetically first name-based vhost will be used. This is also true if you pass a higher priority and no names match anything else.

A slightly more complicated example, changes the docroot owner/group from the default 'root'

```puppet
    apache::vhost { 'second.example.com':
      port          => '80',
      docroot       => '/var/www/second',
      docroot_owner => 'third',
      docroot_group => 'third',
    }
```

To set up a virtual host with SSL and default SSL certificates

```puppet
    apache::vhost { 'ssl.example.com':
      port    => '443',
      docroot => '/var/www/ssl',
      ssl     => true,
    }
```

To set up a virtual host with SSL and specific SSL certificates

```puppet
    apache::vhost { 'fourth.example.com':
      port     => '443',
      docroot  => '/var/www/fourth',
      ssl      => true,
      ssl_cert => '/etc/ssl/fourth.example.com.cert',
      ssl_key  => '/etc/ssl/fourth.example.com.key',
    }
```

Virtual hosts listen on '*' by default. To listen on a specific IP address

```puppet
    apache::vhost { 'subdomain.example.com':
      ip      => '127.0.0.1',
      port    => '80',
      docroot => '/var/www/subdomain',
    }
```

To set up a virtual host with a wildcard alias for the subdomain mapped to a same-named directory, for example: `http://example.com.loc` to `/var/www/example.com`

```puppet
    apache::vhost { 'subdomain.loc':
      vhost_name       => '*',
      port             => '80',
      virtual_docroot  => '/var/www/%-2+',
      docroot          => '/var/www',
      serveraliases    => ['*.loc',],
    }
```

To set up a virtual host with suPHP

```puppet
    apache::vhost { 'suphp.example.com':
      port                => '80',
      docroot             => '/home/appuser/myphpapp',
      suphp_addhandler    => 'x-httpd-php',
      suphp_engine        => 'on',
      suphp_configpath    => '/etc/php5/apache2',
      directories         => { path => '/home/appuser/myphpapp',
        'suphp'           => { user => 'myappuser', group => 'myappgroup' },
      }
    }
```

To set up a virtual host with WSGI

```puppet
    apache::vhost { 'wsgi.example.com':
      port                        => '80',
      docroot                     => '/var/www/pythonapp',
      wsgi_application_group      => '%{GLOBAL}',
      wsgi_daemon_process         => 'wsgi',
      wsgi_daemon_process_options => { 
        processes    => '2', 
        threads      => '15', 
        display-name => '%{GROUP}',
       },
      wsgi_import_script          => '/var/www/demo.wsgi',
      wsgi_import_script_options  =>
        { process-group => 'wsgi', application-group => '%{GLOBAL}' },
      wsgi_process_group          => 'wsgi',
      wsgi_script_aliases         => { '/' => '/var/www/demo.wsgi' },
    }
```

Starting in Apache 2.2.16, HTTPD supports [FallbackResource](https://httpd.apache.org/docs/current/mod/mod_dir.html#fallbackresource), a simple replacement for common RewriteRules.

```puppet
    apache::vhost { 'wordpress.example.com':
      port                => '80',
      docroot             => '/var/www/wordpress',
      fallbackresource    => '/index.php',
    }
```

Please note that the 'disabled' argument to FallbackResource is only supported since Apache 2.2.24.

See a list of all [virtual host parameters](#defined-type-apachevhost). See an extensive list of [virtual host examples](#virtual-host-examples).

##Usage

###Classes and Defined Types

This module modifies Apache configuration files and directories, and will purge any configuration not managed by Puppet. Configuration of Apache should be managed by Puppet, as non-Puppet configuration files can cause unexpected failures.

It is possible to temporarily disable full Puppet management by setting the [`purge_configs`](#purge_configs) parameter within the base `apache` class to 'false'. This option should only be used as a temporary means of saving and relocating customized configurations. See the [`purge_configs` parameter](#purge_configs) for more information.

####Class: `apache`

The apache module's primary class, `apache`, guides the basic setup of Apache on your system.

You may establish a default vhost in this class, the `vhost` class, or both. You may add additional vhost configurations for specific virtual hosts using a declaration of the `vhost` type.

**Parameters within `apache`:**

#####`apache_version`

Configures the behavior of the module templates, package names, and default mods by setting the Apache version. Default is determined by the class `apache::version` using the OS family and release. It should not be configured manually without special reason.

#####`confd_dir`

Changes the location of the configuration directory your custom configuration files are placed in. Defaults to '/etc/httpd/conf' on RedHat, '/etc/apache2' on Debian, and '/usr/local/etc/apache22' on FreeBSD.

#####`conf_template`

Overrides the template used for the main apache configuration file. Defaults to 'apache/httpd.conf.erb'.

*Note:* Using this parameter is potentially risky, as the module has been built for a minimal configuration file with the configuration primarily coming from conf.d/ entries.

#####`default_confd_files`

Generates default set of include-able Apache configuration files under  `${apache::confd_dir}` directory. These configuration files correspond to what is usually installed with the Apache package on a given platform.

#####`default_mods`

Sets up Apache with default settings based on your OS. Valid values are 'true', 'false', or an array of mod names. 

Defaults to 'true', which will include the default [HTTPD mods](https://github.com/puppetlabs/puppetlabs-apache/blob/master/manifests/default_mods.pp).

If false, it will only include the mods required to make HTTPD work, and any other mods can be declared on their own.

If an array, the apache module will include the array of mods listed.

#####`default_ssl_ca`

The default certificate authority, which is automatically set to 'undef'. This default will work out of the box but must be updated with your specific certificate information before being used in production.

#####`default_ssl_cert`

The default SSL certification, which is automatically set based on your operating system  ('/etc/pki/tls/certs/localhost.crt' for RedHat, '/etc/ssl/certs/ssl-cert-snakeoil.pem' for Debian, and '/usr/local/etc/apache22/server.crt' for FreeBSD). This default will work out of the box but must be updated with your specific certificate information before being used in production.

#####`default_ssl_chain`

The default SSL chain, which is automatically set to 'undef'. This default will work out of the box but must be updated with your specific certificate information before being used in production.

#####`default_ssl_crl`

The default certificate revocation list to use, which is automatically set to 'undef'. This default will work out of the box but must be updated with your specific certificate information before being used in production.

#####`default_ssl_crl_path`

The default certificate revocation list path, which is automatically set to 'undef'. This default will work out of the box but must be updated with your specific certificate information before being used in production.

#####`default_ssl_key`

The default SSL key, which is automatically set based on your operating system ('/etc/pki/tls/private/localhost.key' for RedHat, '/etc/ssl/private/ssl-cert-snakeoil.key' for Debian, and '/usr/local/etc/apache22/server.key' for FreeBSD). This default will work out of the box but must be updated with your specific certificate information before being used in production.

#####`default_ssl_vhost`

Sets up a default SSL virtual host. Defaults to 'false'. If set to 'true', will set up the following vhost:

```puppet
    apache::vhost { 'default-ssl':
      port            => 443,
      ssl             => true,
      docroot         => $docroot,
      scriptalias     => $scriptalias,
      serveradmin     => $serveradmin,
      access_log_file => "ssl_${access_log_file}",
      }
```

SSL vhosts only respond to HTTPS queries.

#####`default_vhost`

Sets up a default virtual host. Defaults to 'true', set to 'false' to set up [customized virtual hosts](#configure-a-virtual-host).

#####`error_documents`

Enables custom error documents. Defaults to 'false'.

#####`httpd_dir`

Changes the base location of the configuration directories used for the apache service. This is useful for specially repackaged HTTPD builds, but may have unintended consequences when used in combination with the default distribution packages. Defaults to '/etc/httpd' on RedHat, '/etc/apache2' on Debian, and '/usr/local/etc/apache22' on FreeBSD.

#####`keepalive`

Enables persistent connections.

#####`keepalive_timeout`

Sets the amount of time the server will wait for subsequent requests on a persistent connection. Defaults to '15'.

#####`max_keepalive_requests`

Sets the limit of the number of requests allowed per connection when KeepAlive is on. Defaults to '100'.

#####`loadfile_name`

Sets the file name for the module loadfile. Should be in the format *.load.  This can be used to set the module load order.

#####`log_level`

Changes the verbosity level of the error log. Defaults to 'warn'. Valid values are 'emerg', 'alert', 'crit', 'error', 'warn', 'notice', 'info', or 'debug'.

#####`log_formats`

Define additional [LogFormats](https://httpd.apache.org/docs/current/mod/mod_log_config.html#logformat). This is done in a Hash:

```puppet
  $log_formats = { vhost_common => '%v %h %l %u %t \"%r\" %>s %b' }
```

#####`logroot`

Changes the directory where Apache log files for the virtual host are placed. Defaults to '/var/log/httpd' on RedHat, '/var/log/apache2' on Debian, and '/var/log/apache22' on FreeBSD.

#####`logroot_mode`

Overrides the mode the logroot directory is set to. Defaults to undef. Do NOT give people write access to the directory the logs are stored
in without being aware of the consequences; see http://httpd.apache.org/docs/2.4/logs.html#security for details.

#####`manage_group`

Setting this to 'false' will stop the group resource from being created. This is for when you have a group, created from another Puppet module, you want to use to run Apache. Without this parameter, attempting to use a previously established group would result in a duplicate resource error.

#####`manage_user`

Setting this to 'false' will stop the user resource from being created. This is for instances when you have a user, created from another Puppet module, you want to use to run Apache. Without this parameter, attempting to use a previously established user would result in a duplicate resource error.

#####`mod_dir`

Changes the location of the configuration directory your Apache modules configuration files are placed in. Defaults to '/etc/httpd/conf.d' for RedHat, '/etc/apache2/mods-available' for Debian, and '/usr/local/etc/apache22/Modules' for FreeBSD.

#####`mpm_module`

Determines which MPM is loaded and configured for the HTTPD process. Valid values are 'event', 'itk', 'peruser', 'prefork', 'worker', or 'false'. Defaults to 'prefork' on RedHat and FreeBSD, and 'worker' on Debian. Must be set to 'false' to explicitly declare the following classes with custom parameters:

* `apache::mod::event`
* `apache::mod::itk`
* `apache::mod::peruser`
* `apache::mod::prefork`
* `apache::mod::worker` 

*Note:* Switching between different MPMs on FreeBSD is possible but quite difficult. Before changing `$mpm_module` you must uninstall all packages that depend on your currently-installed Apache. 

#####`package_ensure`

Allows control over the package ensure attribute. Can be 'present','absent', or a version string.

#####`ports_file`

Changes the name of the file containing Apache ports configuration. Default is `${conf_dir}/ports.conf`.

#####`purge_configs`

Removes all other Apache configs and vhosts, defaults to 'true'. Setting this to 'false' is a stopgap measure to allow the apache module to coexist with existing or otherwise-managed configuration. It is recommended that you move your configuration entirely to resources within this module.

#####`purge_vhost_configs`

If `vhost_dir` != `confd_dir`, this controls the removal of any configurations that are not managed by puppet within `vhost_dir`. It defaults to the value of `purge_configs`. Setting this to false is a stopgap measure to allow the apache module to coexist with existing or otherwise unmanaged configurations within `vhost_dir`

#####`sendfile`

Makes Apache use the Linux kernel sendfile to serve static files. Defaults to 'On'.

#####`serveradmin`

Sets the server administrator. Defaults to 'root@localhost'.

#####`servername`

Sets the server name. Defaults to `fqdn` provided by Facter.

#####`server_root`

Sets the root directory in which the server resides. Defaults to '/etc/httpd' on RedHat, '/etc/apache2' on Debian, and '/usr/local' on FreeBSD.

#####`server_signature`

Configures a trailing footer line under server-generated documents. More information about [ServerSignature](http://httpd.apache.org/docs/current/mod/core.html#serversignature). Defaults to 'On'.

#####`server_tokens`

Controls how much information Apache sends to the browser about itself and the operating system. More information about [ServerTokens](http://httpd.apache.org/docs/current/mod/core.html#servertokens). Defaults to 'OS'.

#####`service_enable`

Determines whether the HTTPD service is enabled when the machine is booted. Defaults to 'true'.

#####`service_ensure`

Determines whether the service should be running. Valid values are true, false, 'running' or 'stopped' when Puppet should manage the service. Any other value will set ensure to false for the Apache service, which is useful when you want to let the service be managed by some other application like Pacemaker. Defaults to 'running'.

#####`service_name`

Name of the Apache service to run. Defaults to: 'httpd' on RedHat, 'apache2' on Debian, and 'apache22' on FreeBSD.

#####`trace_enable`

Controls how TRACE requests per RFC 2616 are handled. More information about [TraceEnable](http://httpd.apache.org/docs/current/mod/core.html#traceenable). Defaults to 'On'.

#####`vhost_dir`

Changes the location of the configuration directory your virtual host configuration files are placed in. Defaults to 'etc/httpd/conf.d' on RedHat, '/etc/apache2/sites-available' on Debian, and '/usr/local/etc/apache22/Vhosts' on FreeBSD.

####Class: `apache::default_mods`

Installs default Apache modules based on what OS you are running.

```puppet
    class { 'apache::default_mods': }
```

####Defined Type: `apache::mod`

Used to enable arbitrary Apache HTTPD modules for which there is no specific `apache::mod::[name]` class. The `apache::mod` defined type will also install the required packages to enable the module, if any.

```puppet
    apache::mod { 'rewrite': }
    apache::mod { 'ldap': }
```

####Classes: `apache::mod::[name]`

There are many `apache::mod::[name]` classes within this module that can be declared using `include`:

* `actions`
* `alias`
* `auth_basic`
* `auth_kerb`
* `authnz_ldap`*
* `autoindex`
* `cache`
* `cgi`
* `cgid`
* `dav`
* `dav_fs`
* `dav_svn`*
* `deflate`
* `dev`
* `dir`*
* `disk_cache`
* `event`
* `expires`
* `fastcgi`
* `fcgid`
* `headers`
* `include`
* `info`*
* `itk`
* `ldap`
* `mime`
* `mime_magic`*
* `negotiation`
* `nss`*
* `pagespeed` (see [`apache::mod::pagespeed`](#class-apachemodpagespeed) below)
* `passenger`*
* `perl`
* `peruser`
* `php` (requires [`mpm_module`](#mpm_module) set to `prefork`)
* `prefork`*
* `proxy`*
* `proxy_ajp`
* `proxy_balancer`
* `proxy_html`
* `proxy_http`
* `python`
* `reqtimeout`
* `rewrite`
* `rpaf`*
* `setenvif`
* `speling`
* `ssl`* (see [`apache::mod::ssl`](#class-apachemodssl) below)
* `status`*
* `suphp`
* `userdir`*
* `vhost_alias`
* `worker`*
* `wsgi` (see [`apache::mod::wsgi`](#class-apachemodwsgi) below)
* `xsendfile`

Modules noted with a * indicate that the module has settings and, thus, a template that includes parameters. These parameters control the module's configuration. Most of the time, these parameters will not require any configuration or attention.

The modules mentioned above, and other Apache modules that have templates, will cause template files to be dropped along with the mod install and the module will not work without the template. Any module without a template will install the package but drop no files.

####Class: `apache::mod::info`

Installs and manages mod_info which provides a comprehensive overview of the server configuration. 

Full documentation for mod_info is available from [Apache](http://httpd.apache.org/docs/2.2/mod/mod_info.html).

These are the default settings:

```puppet
  $allow_from      = ['127.0.0.1','::1'],
  $apache_version  = $::apache::apache_version,
  $restrict_access = true,
```

To set the addresses that are allowed to access /server-info add the following:

```puppet
  class {'apache::mod::info':
    allow_from      => [
      '10.10.36',
      '10.10.38',
      '127.0.0.1',
    ],
  }
```

To disable the access restrictions add the following:

```puppet
  class {'apache::mod::info':
    restrict_access => false,
  }
```

It is not recommended to leave this set to false though it can be very useful for testing. For this reason, you can insert this setting in your normal code to temporarily disable the restrictions like so:

```puppet
  class {'apache::mod::info':
    restrict_access => false, # false disables the block below
    allow_from      => [
      '10.10.36',
      '10.10.38',
      '127.0.0.1',
    ],
  }
```

####Class: `apache::mod::pagespeed`

Installs and manages mod_pagespeed, which is a Google module that rewrites web pages to reduce latency and bandwidth.

This module does *not* manage the software repositories needed to automatically install the
mod-pagespeed-stable package. The module does however require that the package be installed,
or be installable using the system's default package provider.  You should ensure that this
pre-requisite is met or declaring `apache::mod::pagespeed` will cause the puppet run to fail.

These are the defaults:

```puppet
    class { 'apache::mod::pagespeed':
      inherit_vhost_config          => 'on',
      filter_xhtml                  => false,
      cache_path                    => '/var/cache/mod_pagespeed/',
      log_dir                       => '/var/log/pagespeed',
      memache_servers               => [],
      rewrite_level                 => 'CoreFilters',
      disable_filters               => [],
      enable_filters                => [],
      forbid_filters                => [],
      rewrite_deadline_per_flush_ms => 10,
      additional_domains            => undef,
      file_cache_size_kb            => 102400,
      file_cache_clean_interval_ms  => 3600000,
      lru_cache_per_process         => 1024,
      lru_cache_byte_limit          => 16384,
      css_flatten_max_bytes         => 2048,
      css_inline_max_bytes          => 2048,
      css_image_inline_max_bytes    => 2048,
      image_inline_max_bytes        => 2048,
      js_inline_max_bytes           => 2048,
      css_outline_min_bytes         => 3000,
      js_outline_min_bytes          => 3000,
      inode_limit                   => 500000,
      image_max_rewrites_at_once    => 8,
      num_rewrite_threads           => 4,
      num_expensive_rewrite_threads => 4,
      collect_statistics            => 'on',
      statistics_logging            => 'on',
      allow_view_stats              => [],
      allow_pagespeed_console       => [],
      allow_pagespeed_message       => [],
      message_buffer_size           => 100000,
      additional_configuration      => { }
    }
```

Full documentation for mod_pagespeed is available from [Google](http://modpagespeed.com).

####Class: `apache::mod::php`

Installs and configures mod_php. The defaults are OS-dependant.

Overriding the package name:
```
  class {'::apache::mod::php':
    package_name => "php54-php",
    path         => "${::apache::params::lib_path}/libphp54-php5.so",
  }
```

Overriding the default configuartion:
```puppet
  class {'::apache::mod::php':
    source => 'puppet:///modules/apache/my_php.conf',
  }
```

or 
```puppet
  class {'::apache::mod::php':
    template => 'apache/php.conf.erb',
  }
```

or

```puppet
  class {'::apache::mod::php':
    content => '
AddHandler php5-script .php
AddType text/html .php',
  }
```
####Class: `apache::mod::ssl`

Installs Apache SSL capabilities and uses the ssl.conf.erb template. These are the defaults:

```puppet
    class { 'apache::mod::ssl':
      ssl_compression => false,
      ssl_options     => [ 'StdEnvVars' ],
  }
```

To *use* SSL with a virtual host, you must either set the`default_ssl_vhost` parameter in `::apache` to 'true' or set the `ssl` parameter in `apache::vhost` to 'true'.

####Class: `apache::mod::wsgi`

Enables Python support in the WSGI module. To use, simply `include 'apache::mod::wsgi'`. 

For customized parameters, which tell Apache how Python is currently configured on the operating system,

```puppet
    class { 'apache::mod::wsgi':
      wsgi_socket_prefix => "\${APACHE_RUN_DIR}WSGI",
      wsgi_python_home   => '/path/to/venv',
      wsgi_python_path   => '/path/to/venv/site-packages',
    }
```

More information about [WSGI](http://modwsgi.readthedocs.org/en/latest/).

####Class: `apache::mod::fcgid`

Installs and configures mod_fcgid.

The class makes no effort to list all available options, but rather uses an options hash to allow for ultimate flexibility:

```puppet
    class { 'apache::mod::fcgid':
      options => {
        'FcgidIPCDir'  => '/var/run/fcgidsock',
        'SharememPath' => '/var/run/fcgid_shm',
        'AddHandler'   => 'fcgid-script .fcgi',
      },
    }
```

For a full list op options, see the [official mod_fcgid documentation](https://httpd.apache.org/mod_fcgid/mod/mod_fcgid.html).

It is also possible to set the FcgidWrapper per directory per vhost. You must ensure the fcgid module is loaded because there is no auto loading.

```puppet
    include apache::mod::fcgid
    apache::vhost { 'example.org':
      docroot     => '/var/www/html',
      directories => {
        path        => '/var/www/html',
        fcgiwrapper => {
          command => '/usr/local/bin/fcgiwrapper',
        }
      },
    }
```

See [FcgidWrapper documentation](https://httpd.apache.org/mod_fcgid/mod/mod_fcgid.html#fcgidwrapper) for more information.

####Class: `apache::mod::negotiation`

Installs and configures mod_negotiation. If there are not provided any
parameter, default apache mod_negotiation configuration is done.

```puppet
  class { '::apache::mod::negotiation':
    force_language_priority => 'Prefer',
    language_priority       => [ 'es', 'en', 'ca', 'cs', 'da', 'de', 'el', 'eo' ],
  }
```

**Parameters within `apache::mod::negotiation`:**

#####`force_language_priority`

A string that sets the `ForceLanguagePriority` option. Defaults to `Prefer Fallback`.

#####`language_priority`

An array of languages to set the `LanguagePriority` option of the module.

####Class: `apache::mod::deflate`

Installs and configures mod_deflate. If no parameters are provided, a default configuration is applied.

```puppet
  class { '::apache::mod::deflate':
    types => [ 'text/html', 'text/css' ],
    notes => {
      'Input' => 'instream',
      'Ratio' => 'ratio',
    },
  }
```

#####`types`

An array of mime types that will be deflated.

#####`notes`

A hash where the key represents the type and the value represents the note name.

####Defined Type: `apache::vhost`

The Apache module allows a lot of flexibility in the setup and configuration of virtual hosts. This flexibility is due, in part, to `vhost`'s being a defined resource type, which allows it to be evaluated multiple times with different parameters.

The `vhost` defined type allows you to have specialized configurations for virtual hosts that have requirements outside the defaults. You can set up a default vhost within the base `::apache` class, as well as set a customized vhost as default. Your customized vhost (priority 10) will be privileged over the base class vhost (15).

If you have a series of specific configurations and do not want a base `::apache` class default vhost, make sure to set the base class `default_vhost` to 'false'.

```puppet
    class { 'apache':
      default_vhost => false,
    }
```

**Parameters within `apache::vhost`:**

#####`access_log`

Specifies whether `*_access.log` directives (`*_file`,`*_pipe`, or `*_syslog`) should be configured. Setting the value to 'false' will choose none. Defaults to 'true'. 

#####`access_log_file`

Sets the `*_access.log` filename that is placed in `$logroot`. Given a vhost, example.com, it defaults to 'example.com_ssl.log' for SSL vhosts and 'example.com_access.log' for non-SSL vhosts.

#####`access_log_pipe`

Specifies a pipe to send access log messages to. Defaults to 'undef'.

#####`access_log_syslog`

Sends all access log messages to syslog. Defaults to 'undef'.

#####`access_log_format`

Specifies the use of either a LogFormat nickname or a custom format string for the access log. Defaults to 'combined'. See [these examples](http://httpd.apache.org/docs/current/mod/mod_log_config.html).

#####`access_log_env_var`

Specifies that only requests with particular environment variables be logged. Defaults to 'undef'.

#####`add_listen`

Determines whether the vhost creates a Listen statement. The default value is 'true'.

Setting `add_listen` to 'false' stops the vhost from creating a Listen statement, and this is important when you combine vhosts that are not passed an `ip` parameter with vhosts that *are* passed the `ip` parameter.

#####`additional_includes`

Specifies paths to additional static, vhost-specific Apache configuration files. Useful for implementing a unique, custom configuration not supported by this module. Can be an array. Defaults to '[]'.

#####`aliases`

Passes a list of hashes to the vhost to create Alias or AliasMatch directives as per the [mod_alias documentation](http://httpd.apache.org/docs/current/mod/mod_alias.html). These hashes are formatted as follows:

```puppet
aliases => [
  { aliasmatch => '^/image/(.*)\.jpg$', 
    path       => '/files/jpg.images/$1.jpg',
  }
  { alias      => '/image',
    path       => '/ftp/pub/image', 
  },
],
```

For `alias` and `aliasmatch` to work, each will need a corresponding context, such as '< Directory /path/to/directory>' or '<Location /path/to/directory>'. The Alias and AliasMatch directives are created in the order specified in the `aliases` parameter. As described in the [`mod_alias` documentation](http://httpd.apache.org/docs/current/mod/mod_alias.html), more specific `alias` or `aliasmatch` parameters should come before the more general ones to avoid shadowing.

*Note:* If `apache::mod::passenger` is loaded and `PassengerHighPerformance => true` is set, then Alias may have issues honoring the `PassengerEnabled => off` statement. See [this article](http://www.conandalton.net/2010/06/passengerenabled-off-not-working.html) for details.

#####`block`

Specifies the list of things Apache will block access to. The default is an empty set, '[]'. Currently, the only option is 'scm', which blocks web access to .svn, .git and .bzr directories.

#####`custom_fragment`

Passes a string of custom configuration directives to be placed at the end of the vhost configuration. Defaults to 'undef'.

#####`default_vhost`

Sets a given `apache::vhost` as the default to serve requests that do not match any other `apache::vhost` definitions. The default value is 'false'.

#####`directories`

See the [`directories` section](#parameter-directories-for-apachevhost).

#####`directoryindex`

Sets the list of resources to look for when a client requests an index of the directory by specifying a '/' at the end of the directory name. [DirectoryIndex](http://httpd.apache.org/docs/current/mod/mod_dir.html#directoryindex) has more information. Defaults to 'undef'.

#####`docroot`

Provides the [DocumentRoot](http://httpd.apache.org/docs/current/mod/core.html#documentroot) directive, which identifies the directory Apache serves files from. Required. 

#####`docroot_group`

Sets group access to the docroot directory. Defaults to 'root'.

#####`docroot_owner`

Sets individual user access to the docroot directory. Defaults to 'root'.

#####`docroot_mode`

Sets access permissions of the docroot directory. Defaults to 'undef'.

#####`manage_docroot`

Whether to manage to docroot directory at all. Defaults to 'true'.

#####`error_log`

Specifies whether `*_error.log` directives should be configured. Defaults to 'true'.

#####`error_log_file`

Points to the `*_error.log` file. Given a vhost, example.com, it defaults to 'example.com_ssl_error.log' for SSL vhosts and 'example.com_access_error.log' for non-SSL vhosts.

#####`error_log_pipe`

Specifies a pipe to send error log messages to. Defaults to 'undef'.

#####`error_log_syslog`

Sends all error log messages to syslog. Defaults to 'undef'.

#####`error_documents`

A list of hashes which can be used to override the [ErrorDocument](https://httpd.apache.org/docs/current/mod/core.html#errordocument) settings for this vhost. Defaults to '[]'. Example:

```puppet
    apache::vhost { 'sample.example.net':
      error_documents => [
        { 'error_code' => '503', 'document' => '/service-unavail' },
        { 'error_code' => '407', 'document' => 'https://example.com/proxy/login' },
      ],
    }
```

#####`ensure`

Specifies if the vhost file is present or absent. Defaults to 'present'.

#####`fallbackresource`

Sets the [FallbackResource](http://httpd.apache.org/docs/current/mod/mod_dir.html#fallbackresource) directive, which specifies an action to take for any URL that doesn't map to anything in your filesystem and would otherwise return 'HTTP 404 (Not Found)'. Valid values must either begin with a / or be 'disabled'. Defaults to 'undef'.

#####`headers`

Adds lines to replace, merge, or remove response headers. See [Header](http://httpd.apache.org/docs/current/mod/mod_headers.html#header) for more information. Can be an array. Defaults to 'undef'.

#####`ip`

Sets the IP address the vhost listens on. Defaults to listen on all IPs.

#####`ip_based`

Enables an [IP-based](http://httpd.apache.org/docs/current/vhosts/ip-based.html) vhost. This parameter inhibits the creation of a NameVirtualHost directive, since those are used to funnel requests to name-based vhosts. Defaults to 'false'.

#####`itk`

Configures [ITK](http://mpm-itk.sesse.net/) in a hash. Keys may be:

* user + group
* `assignuseridexpr`
* `assigngroupidexpr`
* `maxclientvhost`
* `nice`
* `limituidrange` (Linux 3.5.0 or newer)
* `limitgidrange` (Linux 3.5.0 or newer)

Usage will typically look like:

```puppet
    apache::vhost { 'sample.example.net':
      docroot => '/path/to/directory',
      itk     => {
        user  => 'someuser',
        group => 'somegroup',
      },
    }
```

#####`logroot`

Specifies the location of the virtual host's logfiles. Defaults to '/var/log/<apache log location>/'.

#####`log_level`

Specifies the verbosity of the error log. Defaults to 'warn' for the global server configuration and can be overridden on a per-vhost basis. Valid values are 'emerg', 'alert', 'crit', 'error', 'warn', 'notice', 'info' or 'debug'.

#####`no_proxy_uris`

Specifies URLs you do not want to proxy. This parameter is meant to be used in combination with [`proxy_dest`](#proxy_dest).

#####`proxy_preserve_host`

Sets the [ProxyPreserveHost Directive](http://httpd.apache.org/docs/2.2/mod/mod_proxy.html#proxypreservehost).  true Enables the Host: line from an incoming request to be proxied to the host instead of hostname .  false sets this option to off (default).

#####`options`

Sets the [Options](http://httpd.apache.org/docs/current/mod/core.html#options) for the specified virtual host. Defaults to '['Indexes','FollowSymLinks','MultiViews']', as demonstrated below:

```puppet
    apache::vhost { 'site.name.fdqn':
      …
      options => ['Indexes','FollowSymLinks','MultiViews'],
    }
```

*Note:* If you use [`directories`](#parameter-directories-for-apachevhost), 'Options', 'Override', and 'DirectoryIndex' are ignored because they are parameters within `directories`.

#####`override`

Sets the overrides for the specified virtual host. Accepts an array of [AllowOverride](http://httpd.apache.org/docs/current/mod/core.html#allowoverride) arguments. Defaults to '[none]'.

#####`php_admin_flags & values`

Allows per-vhost setting [`php_admin_value`s or `php_admin_flag`s](http://php.net/manual/en/configuration.changes.php). These flags or values cannot be overwritten by a user or an application. Defaults to '[]'.

#####`port`

Sets the port the host is configured on. The module's defaults ensure the host listens on port 80 for non-SSL vhosts and port 443 for SSL vhosts. The host will only listen on the port set in this parameter. 

#####`priority`

Sets the relative load-order for Apache HTTPD VirtualHost configuration files. Defaults to '25'.

If nothing matches the priority, the first name-based vhost will be used. Likewise, passing a higher priority will cause the alphabetically first name-based vhost to be used if no other names match.

*Note:* You should not need to use this parameter. However, if you do use it, be aware that the `default_vhost` parameter for `apache::vhost` passes a priority of '15'.

#####`proxy_dest`

Specifies the destination address of a [ProxyPass](http://httpd.apache.org/docs/current/mod/mod_proxy.html#proxypass) configuration. Defaults to 'undef'.

#####`proxy_pass`

Specifies an array of `path => URI` for a [ProxyPass](http://httpd.apache.org/docs/current/mod/mod_proxy.html#proxypass) configuration. Defaults to 'undef'.

```puppet
apache::vhost { 'site.name.fdqn':
  … 
  proxy_pass => [
    { 'path' => '/a', 'url' => 'http://backend-a/' },
    { 'path' => '/b', 'url' => 'http://backend-b/' },
    { 'path' => '/c', 'url' => 'http://backend-a/c' },
  ],
}
```

#####`rack_base_uris`

Specifies the resource identifiers for a rack configuration. The file paths specified will be listed as rack application roots for [Phusion Passenger](http://www.modrails.com/documentation/Users%20guide%20Apache.html#_railsbaseuri_and_rackbaseuri) in the _rack.erb template. Defaults to 'undef'.

#####`redirect_dest`

Specifies the address to redirect to. Defaults to 'undef'.

#####`redirect_source`

Specifies the source URIs that will redirect to the destination specified in `redirect_dest`. If more than one item for redirect is supplied, the source and destination must be the same length and the items will be order-dependent. 

```puppet
    apache::vhost { 'site.name.fdqn':
      …
      redirect_source => ['/images','/downloads'],
      redirect_dest   => ['http://img.example.com/','http://downloads.example.com/'],
    }
```

#####`redirect_status`

Specifies the status to append to the redirect. Defaults to 'undef'.

```puppet
    apache::vhost { 'site.name.fdqn':
      …
      redirect_status => ['temp','permanent'],
    }
```

#####`redirectmatch_regexp` & `redirectmatch_status`

Determines which server status should be raised for a given regular expression. Entered as an array. Defaults to 'undef'.

```puppet
    apache::vhost { 'site.name.fdqn':
      …
      redirectmatch_status => ['404','404'],
      redirectmatch_regexp => ['\.git(/.*|$)/','\.svn(/.*|$)'],
    }
```

#####`request_headers`

Modifies collected [request headers](http://httpd.apache.org/docs/current/mod/mod_headers.html#requestheader) in various ways, including adding additional request headers, removing request headers, etc. Defaults to 'undef'.

```puppet
    apache::vhost { 'site.name.fdqn':
      …
      request_headers => [
        'append MirrorID "mirror 12"',
        'unset MirrorID',
      ],
    }
```

#####`rewrites`

Creates URL rewrite rules. Expects an array of hashes, and the hash keys can be any of 'comment', 'rewrite_base', 'rewrite_cond', or 'rewrite_rule'. Defaults to 'undef'. 

For example, you can specify that anyone trying to access index.html will be served welcome.html

```puppet
    apache::vhost { 'site.name.fdqn':
      …
      rewrites => [ { rewrite_rule => ['^index\.html$ welcome.html'] } ]
    }
```

The parameter allows rewrite conditions that, when true, will execute the associated rule. For instance, if you wanted to rewrite URLs only if the visitor is using IE

```puppet
    apache::vhost { 'site.name.fdqn':
      …
      rewrites => [
        {
          comment      => 'redirect IE',
          rewrite_cond => ['%{HTTP_USER_AGENT} ^MSIE'],
          rewrite_rule => ['^index\.html$ welcome.html'],
        },
      ],
    }
```

You can also apply multiple conditions. For instance, rewrite index.html to welcome.html only when the browser is Lynx or Mozilla (version 1 or 2)

```puppet
    apache::vhost { 'site.name.fdqn':
      …
      rewrites => [
        {
          comment      => 'Lynx or Mozilla v1/2',
          rewrite_cond => ['%{HTTP_USER_AGENT} ^Lynx/ [OR]', '%{HTTP_USER_AGENT} ^Mozilla/[12]'],
          rewrite_rule => ['^index\.html$ welcome.html'],
        },
      ],
    }
```

Multiple rewrites and conditions are also possible

```puppet
    apache::vhost { 'site.name.fdqn':
      …
      rewrites => [
        {
          comment      => 'Lynx or Mozilla v1/2',
          rewrite_cond => ['%{HTTP_USER_AGENT} ^Lynx/ [OR]', '%{HTTP_USER_AGENT} ^Mozilla/[12]'],
          rewrite_rule => ['^index\.html$ welcome.html'],
        },
        {
          comment      => 'Internet Explorer',
          rewrite_cond => ['%{HTTP_USER_AGENT} ^MSIE'],
          rewrite_rule => ['^index\.html$ /index.IE.html [L]'],
        },
        {
          rewrite_base => /apps/,
          rewrite_rule => ['^index\.cgi$ index.php', '^index\.html$ index.php', '^index\.asp$ index.html'],
        },
     ], 
    }
```

Refer to the [`mod_rewrite` documentation](http://httpd.apache.org/docs/current/mod/mod_rewrite.html) for more details on what is possible with rewrite rules and conditions.

#####`scriptalias`

Defines a directory of CGI scripts to be aliased to the path '/cgi-bin', for example: '/usr/scripts'. Defaults to 'undef'.

#####`scriptaliases`

Passes an array of hashes to the vhost to create either ScriptAlias or ScriptAliasMatch statements as per the [`mod_alias` documentation](http://httpd.apache.org/docs/current/mod/mod_alias.html). These hashes are formatted as follows:

```puppet
    scriptaliases => [
      {
        alias => '/myscript',
        path  => '/usr/share/myscript',
      },
      {
        aliasmatch => '^/foo(.*)',
        path       => '/usr/share/fooscripts$1',
      },
      {
        aliasmatch => '^/bar/(.*)',
        path       => '/usr/share/bar/wrapper.sh/$1',
      },
      {
        alias => '/neatscript',
        path  => '/usr/share/neatscript',
      },
    ]
```

The ScriptAlias and ScriptAliasMatch directives are created in the order specified. As with [Alias and AliasMatch](#aliases) directives, more specific aliases should come before more general ones to avoid shadowing.

#####`serveradmin`

Specifies the email address Apache will display when it renders one of its error pages. Defaults to 'undef'.

#####`serveraliases`

Sets the [ServerAliases](http://httpd.apache.org/docs/current/mod/core.html#serveralias) of the site. Defaults to '[]'.

#####`servername`

Sets the servername corresponding to the hostname you connect to the virtual host at. Defaults to the title of the resource.

#####`setenv`

Used by HTTPD to set environment variables for vhosts. Defaults to '[]'.

#####`setenvif`

Used by HTTPD to conditionally set environment variables for vhosts. Defaults to '[]'.

#####`suphp_addhandler`, `suphp_configpath`, & `suphp_engine`

Set up a virtual host with [suPHP](http://suphp.org/DocumentationView.html?file=apache/CONFIG). 

`suphp_addhandler` defaults to 'php5-script' on RedHat and FreeBSD, and 'x-httpd-php' on Debian.

`suphp_configpath` defaults to 'undef' on RedHat and FreeBSD, and '/etc/php5/apache2' on Debian.

`suphp_engine` allows values 'on' or 'off'. Defaults to 'off'

To set up a virtual host with suPHP

```puppet
    apache::vhost { 'suphp.example.com':
      port                => '80',
      docroot             => '/home/appuser/myphpapp',
      suphp_addhandler    => 'x-httpd-php',
      suphp_engine        => 'on',
      suphp_configpath    => '/etc/php5/apache2',
      directories         => { path => '/home/appuser/myphpapp',
        'suphp'           => { user => 'myappuser', group => 'myappgroup' },
      }
    }
```

#####`vhost_name`

Enables name-based virtual hosting. If no IP is passed to the virtual host but the vhost is assigned a port, then the vhost name will be 'vhost_name:port'. If the virtual host has no assigned IP or port, the vhost name will be set to the title of the resource. Defaults to '*'.

#####`virtual_docroot` 

Sets up a virtual host with a wildcard alias subdomain mapped to a directory with the same name. For example, 'http://example.com' would map to '/var/www/example.com'. Defaults to 'false'. 

```puppet
    apache::vhost { 'subdomain.loc':
      vhost_name       => '*',
      port             => '80',
      virtual_docroot' => '/var/www/%-2+',
      docroot          => '/var/www',
      serveraliases    => ['*.loc',],
    }
```

#####`wsgi_daemon_process`, `wsgi_daemon_process_options`, `wsgi_process_group`, `wsgi_script_aliases`, & `wsgi_pass_authorization`

Set up a virtual host with [WSGI](https://code.google.com/p/modwsgi/).

`wsgi_daemon_process` sets the name of the WSGI daemon. It is a hash, accepting [these keys](http://modwsgi.readthedocs.org/en/latest/configuration-directives/WSGIDaemonProcess.html), and it defaults to 'undef'.

`wsgi_daemon_process_options` is optional and defaults to 'undef'.

`wsgi_process_group` sets the group ID the virtual host will run under. Defaults to 'undef'.

`wsgi_script_aliases` requires a hash of web paths to filesystem .wsgi paths. Defaults to 'undef'.

`wsgi_pass_authorization` the WSGI application handles authorisation instead of Apache when set to 'On'. For more information see [here] (http://modwsgi.readthedocs.org/en/latest/configuration-directives/WSGIPassAuthorization.html).  Defaults to 'undef' where apache will set the defaults setting to 'Off'.

To set up a virtual host with WSGI

```puppet
    apache::vhost { 'wsgi.example.com':
      port                        => '80',
      docroot                     => '/var/www/pythonapp',
      wsgi_daemon_process         => 'wsgi',
      wsgi_daemon_process_options =>
        { processes    => '2', 
          threads      => '15', 
          display-name => '%{GROUP}',
         },
      wsgi_process_group          => 'wsgi',
      wsgi_script_aliases         => { '/' => '/var/www/demo.wsgi' },
    }
```

####Parameter `directories` for `apache::vhost`

The `directories` parameter within the `apache::vhost` class passes an array of hashes to the vhost to create [Directory](http://httpd.apache.org/docs/current/mod/core.html#directory), [File](http://httpd.apache.org/docs/current/mod/core.html#files), and [Location](http://httpd.apache.org/docs/current/mod/core.html#location) directive blocks. These blocks take the form, '< Directory /path/to/directory>...< /Directory>'.

Each hash passed to `directories` must contain `path` as one of the keys.  You may also pass in `provider` which, if missing, defaults to 'directory'. (A full list of acceptable keys is below.) General usage will look something like

```puppet
    apache::vhost { 'sample.example.net':
      docroot     => '/path/to/directory',
      directories => [
        { path => '/path/to/directory', <key> => <value> },
        { path => '/path/to/another/directory', <key> => <value> },
      ],
    }
```

*Note:* At least one directory should match the `docroot` parameter. Once you start declaring directories, `apache::vhost` assumes that all required Directory blocks will be declared. If not defined, a single default Directory block will be created that matches the `docroot` parameter.

The `provider` key can be set to 'directory', 'files', or 'location'. If the path starts with a [~](https://httpd.apache.org/docs/current/mod/core.html#files), HTTPD will interpret this as the equivalent of DirectoryMatch, FilesMatch, or LocationMatch.

```puppet
    apache::vhost { 'files.example.net':
      docroot     => '/var/www/files',
      directories => [
        { 'path'     => '/var/www/files', 
          'provider' => 'files', 
          'deny'     => 'from all' 
         },
      ],
    }
```

Available handlers, represented as keys, should be placed within the  `directory`,`'files`, or `location` hashes.  This looks like

```puppet
  apache::vhost { 'sample.example.net':
      docroot     => '/path/to/directory',
      directories => [ { path => '/path/to/directory', handler => value } ],
}
```

Any handlers you do not set in these hashes will be considered 'undefined' within Puppet and will not be added to the virtual host, resulting in the module using their default values. Currently this is the list of supported handlers:

######`addhandlers`

Sets [AddHandler](http://httpd.apache.org/docs/current/mod/mod_mime.html#addhandler) directives, which map filename extensions to the specified handler. Accepts a list of hashes, with `extensions` serving to list the extensions being managed by the handler, and takes the form: `{ handler => 'handler-name', extensions => ['extension']}`. 

```puppet
    apache::vhost { 'sample.example.net':
      docroot     => '/path/to/directory',
      directories => [ 
        { path        => '/path/to/directory',
          addhandlers => [{ handler => 'cgi-script', extensions => ['.cgi']}],
        }, 
      ],
    }
```

######`allow`

Sets an [Allow](http://httpd.apache.org/docs/2.2/mod/mod_authz_host.html#allow) directive, which groups authorizations based on hostnames or IPs. **Deprecated:** This parameter is being deprecated due to a change in Apache. It will only work with Apache 2.2 and lower. You can use it as a single string for one rule or as an array for more than one.

```puppet
    apache::vhost { 'sample.example.net':
      docroot     => '/path/to/directory',
      directories => [ 
        { path  => '/path/to/directory', 
          allow => 'from example.org', 
        }, 
      ],
    }
```

######`allow_override`

Sets the types of directives allowed in [.htaccess](http://httpd.apache.org/docs/current/mod/core.html#allowoverride) files. Accepts an array.

```puppet
    apache::vhost { 'sample.example.net':
      docroot      => '/path/to/directory',
      directories  => [ 
        { path           => '/path/to/directory', 
          allow_override => ['AuthConfig', 'Indexes'], 
        }, 
      ],
    }
```

######`auth_basic_authoritative`

Sets the value for [AuthBasicAuthoritative](https://httpd.apache.org/docs/current/mod/mod_auth_basic.html#authbasicauthoritative), which determines whether authorization and authentication are passed to lower level Apache modules.

######`auth_basic_fake`

Sets the value for [AuthBasicFake](http://httpd.apache.org/docs/current/mod/mod_auth_basic.html#authbasicfake), which statically configures authorization credentials for a given directive block.

######`auth_basic_provider`

Sets the value for [AuthBasicProvider] (http://httpd.apache.org/docs/current/mod/mod_auth_basic.html#authbasicprovider), which sets the authentication provider for a given location.

######`auth_digest_algorithm`

Sets the value for [AuthDigestAlgorithm](http://httpd.apache.org/docs/current/mod/mod_auth_digest.html#authdigestalgorithm), which selects the algorithm used to calculate the challenge and response hashes.

######`auth_digest_domain`

Sets the value for [AuthDigestDomain](http://httpd.apache.org/docs/current/mod/mod_auth_digest.html#authdigestdomain), which allows you to specify one or more URIs in the same protection space for digest authentication.

######`auth_digest_nonce_lifetime`

Sets the value for [AuthDigestNonceLifetime](http://httpd.apache.org/docs/current/mod/mod_auth_digest.html#authdigestnoncelifetime), which controls how long the server nonce is valid.

######`auth_digest_provider`

Sets the value for [AuthDigestProvider](http://httpd.apache.org/docs/current/mod/mod_auth_digest.html#authdigestprovider), which sets the authentication provider for a given location.

######`auth_digest_qop`

Sets the value for [AuthDigestQop](http://httpd.apache.org/docs/current/mod/mod_auth_digest.html#authdigestqop), which determines the quality-of-protection to use in digest authentication.

######`auth_digest_shmem_size`

Sets the value for [AuthAuthDigestShmemSize](http://httpd.apache.org/docs/current/mod/mod_auth_digest.html#authdigestshmemsize), which defines the amount of shared memory allocated to the server for keeping track of clients.

######`auth_group_file`

Sets the value for [AuthGroupFile](https://httpd.apache.org/docs/current/mod/mod_authz_groupfile.html#authgroupfile), which sets the name of the text file containing the list of user groups for authorization.

######`auth_name`

Sets the value for [AuthName](http://httpd.apache.org/docs/current/mod/mod_authn_core.html#authname), which sets the name of the authorization realm.

######`auth_require`

Sets the entity name you're requiring to allow access. Read more about [Require](http://httpd.apache.org/docs/current/mod/mod_authz_host.html#requiredirectives).

######`auth_type`

Sets the value for [AuthType](http://httpd.apache.org/docs/current/mod/mod_authn_core.html#authtype), which guides the type of user authentication.

######`auth_user_file`

Sets the value for [AuthUserFile](http://httpd.apache.org/docs/current/mod/mod_authn_file.html#authuserfile), which sets the name of the text file containing the users/passwords for authentication.

######`custom_fragment`

Pass a string of custom configuration directives to be placed at the end of the directory configuration.

```puppet
  apache::vhost { 'monitor':
    … 
    custom_fragment => '
  <Location /balancer-manager>
    SetHandler balancer-manager
    Order allow,deny
    Allow from all
  </Location>
  <Location /server-status>
    SetHandler server-status
    Order allow,deny
    Allow from all
  </Location>
  ProxyStatus On',
}
```

######`deny`

Sets a [Deny](http://httpd.apache.org/docs/2.2/mod/mod_authz_host.html#deny) directive, specifying which hosts are denied access to the server. **Deprecated:** This parameter is being deprecated due to a change in Apache. It will only work with Apache 2.2 and lower. 

```puppet
    apache::vhost { 'sample.example.net':
      docroot     => '/path/to/directory',
      directories => [ 
        { path => '/path/to/directory', 
          deny => 'from example.org', 
        }, 
      ],
    }
```

######`error_documents`

An array of hashes used to override the [ErrorDocument](https://httpd.apache.org/docs/current/mod/core.html#errordocument) settings for the directory. 

```puppet
    apache::vhost { 'sample.example.net':
      directories => [ 
        { path            => '/srv/www',
          error_documents => [
            { 'error_code' => '503', 
              'document'   => '/service-unavail',
            },
          ],
        },
      ],
    }
```

######`headers`

Adds lines for [Header](http://httpd.apache.org/docs/current/mod/mod_headers.html#header) directives.

```puppet
    apache::vhost { 'sample.example.net':
      docroot     => '/path/to/directory',
      directories => {
        path    => '/path/to/directory',
        headers => 'Set X-Robots-Tag "noindex, noarchive, nosnippet"',
      },
    }
```

######`index_options`

Allows configuration settings for [directory indexing](http://httpd.apache.org/docs/current/mod/mod_autoindex.html#indexoptions).

```puppet
    apache::vhost { 'sample.example.net':
      docroot     => '/path/to/directory',
      directories => [ 
        { path          => '/path/to/directory', 
          options       => ['Indexes','FollowSymLinks','MultiViews'], 
          index_options => ['IgnoreCase', 'FancyIndexing', 'FoldersFirst', 'NameWidth=*', 'DescriptionWidth=*', 'SuppressHTMLPreamble'],
        },
      ],
    }
```

######`index_order_default`

Sets the [default ordering](http://httpd.apache.org/docs/current/mod/mod_autoindex.html#indexorderdefault) of the directory index.

```puppet
    apache::vhost { 'sample.example.net':
      docroot     => '/path/to/directory',
      directories => [ 
        { path                => '/path/to/directory', 
          order               => 'Allow,Deny', 
          index_order_default => ['Descending', 'Date'],
        }, 
      ],
    }
```

######`options`

Lists the [Options](http://httpd.apache.org/docs/current/mod/core.html#options) for the given Directory block.

```puppet
    apache::vhost { 'sample.example.net':
      docroot     => '/path/to/directory',
      directories => [ 
        { path    => '/path/to/directory', 
          options => ['Indexes','FollowSymLinks','MultiViews'], 
        },
      ],
    }
```

######`order`

Sets the order of processing Allow and Deny statements as per [Apache core documentation](httpd.apache.org/docs/2.2/mod/mod_authz_host.html#order). **Deprecated:** This parameter is being deprecated due to a change in Apache. It will only work with Apache 2.2 and lower.

```puppet
    apache::vhost { 'sample.example.net':
      docroot     => '/path/to/directory',
      directories => [ 
        { path  => '/path/to/directory', 
          order => 'Allow,Deny', 
        },
      ],
    }
```

######`satisfy`

Sets a `Satisfy` directive as per the [Apache Core documentation](http://httpd.apache.org/docs/2.2/mod/core.html#satisfy). **Deprecated:** This parameter is being deprecated due to a change in Apache. It will only work with Apache 2.2 and lower.

```puppet
    apache::vhost { 'sample.example.net':
      docroot     => '/path/to/directory',
      directories => [
        { path    => '/path/to/directory',
          satisfy => 'Any',
        }
      ],
    }

######`sethandler`

Sets a `SetHandler` directive as per the [Apache Core documentation](http://httpd.apache.org/docs/2.2/mod/core.html#sethandler). An example:

```puppet
    apache::vhost { 'sample.example.net':
      docroot     => '/path/to/directory',
      directories => [ 
        { path       => '/path/to/directory', 
          sethandler => 'None', 
        }
      ],
    }
```

######`passenger_enabled`

Sets the value for the [PassengerEnabled](http://www.modrails.com/documentation/Users%20guide%20Apache.html#PassengerEnabled) directory to 'on' or 'off'. Requires `apache::mod::passenger` to be included.

```puppet
    apache::vhost { 'sample.example.net':
      docroot     => '/path/to/directory',
      directories => [ 
        { path              => '/path/to/directory', 
          passenger_enabled => 'on',
        }, 
      ],
    }
```

*Note:* Be aware that there is an [issue](http://www.conandalton.net/2010/06/passengerenabled-off-not-working.html) using the PassengerEnabled directive with the PassengerHighPerformance directive.

######`php_admin_value` and `php_admin_flag`

`php_admin_value` sets the value of the directory, and `php_admin_flag` uses a boolean to configure the directory. Further information can be found [here](http://php.net/manual/en/configuration.changes.php).

######`ssl_options`

String or list of [SSLOptions](https://httpd.apache.org/docs/current/mod/mod_ssl.html#ssloptions), which configure SSL engine run-time options. This handler takes precedence over SSLOptions set in the parent block of the vhost.

```puppet
    apache::vhost { 'secure.example.net':
      docroot     => '/path/to/directory',
      directories => [
        { path        => '/path/to/directory', 
          ssl_options => '+ExportCertData', 
        },
        { path        => '/path/to/different/dir', 
          ssl_options => [ '-StdEnvVars', '+ExportCertData'],
        },
      ],
    }
```

######`suphp`

A hash containing the 'user' and 'group' keys for the [suPHP_UserGroup](http://www.suphp.org/DocumentationView.html?file=apache/CONFIG) setting. It must be used with `suphp_engine => on` in the vhost declaration, and may only be passed within `directories`.

```puppet
    apache::vhost { 'secure.example.net':
      docroot     => '/path/to/directory',
      directories => [
        { path  => '/path/to/directory', 
          suphp => 
            { user  =>  'myappuser', 
              group => 'myappgroup', 
            },
        },
      ],
    }
```

####SSL parameters for `apache::vhost`

All of the SSL parameters for `::vhost` will default to whatever is set in the base `apache` class. Use the below parameters to tweak individual SSL settings for specific vhosts.

#####`ssl`

Enables SSL for the virtual host. SSL vhosts only respond to HTTPS queries. Valid values are 'true' or 'false'. Defaults to 'false'. 

#####`ssl_ca`

Specifies the SSL certificate authority. Defaults to 'undef'.

#####`ssl_cert`

Specifies the SSL certification. Defaults are based on your OS: '/etc/pki/tls/certs/localhost.crt' for RedHat, '/etc/ssl/certs/ssl-cert-snakeoil.pem' for Debian, and '/usr/local/etc/apache22/server.crt' for FreeBSD.

#####`ssl_protocol`

Specifies [SSLProtocol](http://httpd.apache.org/docs/current/mod/mod_ssl.html#sslprotocol). Defaults to 'undef'. 

If you do not use this parameter, it will use the HTTPD default from ssl.conf.erb, 'all -SSLv2'.

#####`ssl_cipher`

Specifies [SSLCipherSuite](http://httpd.apache.org/docs/current/mod/mod_ssl.html#sslciphersuite). Defaults to 'undef'.

If you do not use this parameter, it will use the HTTPD default from ssl.conf.erb, 'HIGH:MEDIUM:!aNULL:!MD5'.

#####`ssl_honorcipherorder`

Sets [SSLHonorCipherOrder](http://httpd.apache.org/docs/current/mod/mod_ssl.html#sslhonorcipherorder), which is used to prefer the server's cipher preference order. Defaults to 'On' in the base `apache` config.

#####`ssl_certs_dir`

Specifies the location of the SSL certification directory. Defaults to '/etc/ssl/certs' on Debian, '/etc/pki/tls/certs' on RedHat, and '/usr/local/etc/apache22' on FreeBSD.

#####`ssl_chain`

Specifies the SSL chain. Defaults to 'undef'. (This default will work out of the box but must be updated in the base `apache` class with your specific certificate information before being used in production.)

#####`ssl_crl`

Specifies the certificate revocation list to use. Defaults to 'undef'. (This default will work out of the box but must be updated in the base `apache` class with your specific certificate information before being used in production.)

#####`ssl_crl_path`

Specifies the location of the certificate revocation list. Defaults to 'undef'. (This default will work out of the box but must be updated in the base `apache` class with your specific certificate information before being used in production.)

#####`ssl_key`

Specifies the SSL key. Defaults are based on your operating system: '/etc/pki/tls/private/localhost.key' for RedHat, '/etc/ssl/private/ssl-cert-snakeoil.key' for Debian, and '/usr/local/etc/apache22/server.key' for FreeBSD. (This default will work out of the box but must be updated in the base `apache` class with your specific certificate information before being used in production.)

#####`ssl_verify_client`

Sets the [SSLVerifyClient](http://httpd.apache.org/docs/current/mod/mod_ssl.html#sslverifyclient) directive, which sets the certificate verification level for client authentication. Valid values are: 'none', 'optional', 'require', and 'optional_no_ca'. Defaults to 'undef'.

```puppet
    apache::vhost { 'sample.example.net':
      …
      ssl_verify_client => 'optional',
    }
```

#####`ssl_verify_depth`

Sets the [SSLVerifyDepth](http://httpd.apache.org/docs/current/mod/mod_ssl.html#sslverifydepth) directive, which specifies the maximum depth of CA certificates in client certificate verification. Defaults to 'undef'.

```puppet
    apache::vhost { 'sample.example.net':
      …
      ssl_verify_depth => 1,
    }
```

#####`ssl_options`

Sets the [SSLOptions](http://httpd.apache.org/docs/current/mod/mod_ssl.html#ssloptions) directive, which configures various SSL engine run-time options. This is the global setting for the given vhost and can be a string or an array. Defaults to 'undef'. 

A string:

```puppet
    apache::vhost { 'sample.example.net':
      …
      ssl_options => '+ExportCertData',
    }
```

An array:

```puppet
    apache::vhost { 'sample.example.net':
      …
      ssl_options => [ '+StrictRequire', '+ExportCertData' ],
    }
```

#####`ssl_proxyengine`

Specifies whether or not to use [SSLProxyEngine](http://httpd.apache.org/docs/current/mod/mod_ssl.html#sslproxyengine). Valid values are 'true' and 'false'. Defaults to 'false'.

####Defined Type: FastCGI Server

This type is intended for use with mod_fastcgi. It allows you to define one or more external FastCGI servers to handle specific file types.

Ex:

```puppet
apache::fastcgi::server { 'php':
  host       => '127.0.0.1:9000',
  timeout    => 15,
  flush      => false,
  faux_path  => '/var/www/php.fcgi',
  fcgi_alias => '/php.fcgi',
  file_type  => 'application/x-httpd-php'
}
```

Within your virtual host, you can then configure the specified file type to be handled by the fastcgi server specified above.

```puppet
apache::vhost { 'www':
  ...
  custom_fragment = 'AddType application/x-httpd-php .php'
  ...
}
```

#####`host`

The hostname or IP address and TCP port number (1-65535) of the FastCGI server.

#####`timeout`

The number of seconds of FastCGI application inactivity allowed before the request is aborted and the event is logged (at the error LogLevel). The inactivity timer applies only as long as a connection is pending with the FastCGI application. If a request is queued to an application, but the application doesn't respond (by writing and flushing) within this period, the request will be aborted. If communication is complete with the application but incomplete with the client (the response is buffered), the timeout does not apply.

#####`flush`

Force a write to the client as data is received from the application. By default, mod_fastcgi buffers data in order to free the application as quickly as possible.

#####`faux_path`

`faux_path` does not have to exist in the local filesystem. URIs that Apache resolves to this filename will be handled by this external FastCGI application.

#####`alias`

A unique alias. This is used internally to link the action with the FastCGI server.

#####`file_type`

The MIME-type of the file's that will be processed by the FastCGI server. 

###Virtual Host Examples

The apache module allows you to set up pretty much any configuration of virtual host you might need. This section will address some common configurations, but look at the [Tests section](https://github.com/puppetlabs/puppetlabs-apache/tree/master/tests) for even more examples.

Configure a vhost with a server administrator

```puppet
    apache::vhost { 'third.example.com':
      port        => '80',
      docroot     => '/var/www/third',
      serveradmin => 'admin@example.com',
    }
```

- - -

Set up a vhost with aliased servers

```puppet
    apache::vhost { 'sixth.example.com':
      serveraliases => [
        'sixth.example.org',
        'sixth.example.net',
      ],
      port          => '80',
      docroot       => '/var/www/fifth',
    }
```

- - -

Configure a vhost with a cgi-bin

```puppet
    apache::vhost { 'eleventh.example.com':
      port        => '80',
      docroot     => '/var/www/eleventh',
      scriptalias => '/usr/lib/cgi-bin',
    }
```

- - -

Set up a vhost with a rack configuration

```puppet
    apache::vhost { 'fifteenth.example.com':
      port           => '80',
      docroot        => '/var/www/fifteenth',
      rack_base_uris => ['/rackapp1', '/rackapp2'],
    }
```

- - -

Set up a mix of SSL and non-SSL vhosts at the same domain

```puppet
    #The non-ssl vhost
    apache::vhost { 'first.example.com non-ssl':
      servername => 'first.example.com',
      port       => '80',
      docroot    => '/var/www/first',
    }

    #The SSL vhost at the same domain
    apache::vhost { 'first.example.com ssl':
      servername => 'first.example.com',
      port       => '443',
      docroot    => '/var/www/first',
      ssl        => true,
    }
```

- - -

Configure a vhost to redirect non-SSL connections to SSL

```puppet
    apache::vhost { 'sixteenth.example.com non-ssl':
      servername      => 'sixteenth.example.com',
      port            => '80',
      docroot         => '/var/www/sixteenth',
      redirect_status => 'permanent',
      redirect_dest   => 'https://sixteenth.example.com/'
    }
    apache::vhost { 'sixteenth.example.com ssl':
      servername => 'sixteenth.example.com',
      port       => '443',
      docroot    => '/var/www/sixteenth',
      ssl        => true,
    }
```

- - -

Set up IP-based vhosts on any listen port and have them respond to requests on specific IP addresses. In this example, we will set listening on ports 80 and 81. This is required because the example vhosts are not declared with a port parameter.

```puppet
    apache::listen { '80': }
    apache::listen { '81': }
```

Then we will set up the IP-based vhosts

```puppet
    apache::vhost { 'first.example.com':
      ip       => '10.0.0.10',
      docroot  => '/var/www/first',
      ip_based => true,
    }
    apache::vhost { 'second.example.com':
      ip       => '10.0.0.11',
      docroot  => '/var/www/second',
      ip_based => true,
    }
```

- - -

Configure a mix of name-based and IP-based vhosts. First, we will add two IP-based vhosts on 10.0.0.10, one SSL and one non-SSL

```puppet
    apache::vhost { 'The first IP-based vhost, non-ssl':
      servername => 'first.example.com',
      ip         => '10.0.0.10',
      port       => '80',
      ip_based   => true,
      docroot    => '/var/www/first',
    }
    apache::vhost { 'The first IP-based vhost, ssl':
      servername => 'first.example.com',
      ip         => '10.0.0.10',
      port       => '443',
      ip_based   => true,
      docroot    => '/var/www/first-ssl',
      ssl        => true,
    }
```

Then, we will add two name-based vhosts listening on 10.0.0.20

```puppet
    apache::vhost { 'second.example.com':
      ip      => '10.0.0.20',
      port    => '80',
      docroot => '/var/www/second',
    }
    apache::vhost { 'third.example.com':
      ip      => '10.0.0.20',
      port    => '80',
      docroot => '/var/www/third',
    }
```

If you want to add two name-based vhosts so that they will answer on either 10.0.0.10 or 10.0.0.20, you **MUST** declare `add_listen => 'false'` to disable the otherwise automatic 'Listen 80', as it will conflict with the preceding IP-based vhosts.

```puppet
    apache::vhost { 'fourth.example.com':
      port       => '80',
      docroot    => '/var/www/fourth',
      add_listen => false,
    }
    apache::vhost { 'fifth.example.com':
      port       => '80',
      docroot    => '/var/www/fifth',
      add_listen => false,
    }
```

###Load Balancing

####Defined Type: `apache::balancer`

`apache::balancer` creates an Apache balancer cluster. Each balancer cluster needs one or more balancer members, which are declared with [`apache::balancermember`](#defined-type-apachebalancermember). 

One `apache::balancer` defined resource should be defined for each Apache load balanced set of servers. The `apache::balancermember` resources for all balancer members can be exported and collected on a single Apache load balancer server using exported resources.

**Parameters within `apache::balancer`:**

#####`name`

Sets the balancer cluster's title. This parameter will also set the title of the conf.d file.

#####`proxy_set`

Configures key-value pairs as [ProxySet](http://httpd.apache.org/docs/current/mod/mod_proxy.html#proxyset) lines. Accepts a hash, and defaults to '{}'.

#####`collect_exported`

Determines whether or not to use exported resources. Valid values 'true' and 'false', defaults to 'true'. 

If you statically declare all of your backend servers, you should set this to 'false' to rely on existing declared balancer member resources. Also make sure to use `apache::balancermember` with array arguments.

If you wish to dynamically declare your backend servers via [exported resources](http://docs.puppetlabs.com/guides/exported_resources.html) collected on a central node, you must set this parameter to 'true' in order to collect the exported balancer member resources that were exported by the balancer member nodes.

If you choose not to use exported resources, all balancer members will be configured in a single puppet run. If you are using exported resources, Puppet has to run on the balanced nodes, then run on the balancer.

####Defined Type: `apache::balancermember`

Defines members of [mod_proxy_balancer](http://httpd.apache.org/docs/current/mod/mod_proxy_balancer.html), which will set up a balancer member inside a listening service configuration block in etc/apache/apache.cfg on the load balancer.

**Parameters within `apache::balancermember`:**

#####`name`

Sets the title of the resource. This name will also set the name of the concat fragment.

#####`balancer_cluster`

Sets the Apache service's instance name. This must match the name of a declared `apache::balancer` resource. Required.

#####`url`

Specifies the URL used to contact the balancer member server. Defaults to 'http://${::fqdn}/'.

#####`options`

An array of [options](http://httpd.apache.org/docs/2.2/mod/mod_proxy.html#balancermember) to be specified after the URL. Accepts any key-value pairs available to [ProxyPass](http://httpd.apache.org/docs/2.2/mod/mod_proxy.html#proxypass).

####Examples

To load balance with exported resources, export the `balancermember` from the balancer member

```puppet
      @@apache::balancermember { "${::fqdn}-puppet00":
        balancer_cluster => 'puppet00',
        url              => "ajp://${::fqdn}:8009"
        options          => ['ping=5', 'disablereuse=on', 'retry=5', 'ttl=120'],
      }
```

Then, on the proxy server, create the balancer cluster

```puppet
      apache::balancer { 'puppet00': }
```

To load balance without exported resources, declare the following on the proxy

```puppet
    apache::balancer { 'puppet00': }
    apache::balancermember { "${::fqdn}-puppet00":
        balancer_cluster => 'puppet00',
        url              => "ajp://${::fqdn}:8009"
        options          => ['ping=5', 'disablereuse=on', 'retry=5', 'ttl=120'],
      }
```

Then declare `apache::balancer` and `apache::balancermember` on the proxy server.

If you need to use ProxySet in the balancer config

```puppet
      apache::balancer { 'puppet01':
        proxy_set => {'stickysession' => 'JSESSIONID'},
      }
```

##Reference

###Classes

####Public Classes

* [`apache`](#class-apache): Guides the basic setup of Apache.
* `apache::dev`: Installs Apache development libraries. (*Note:* On FreeBSD, you must declare `apache::package` or `apache` before `apache::dev`.)
* [`apache::mod::[name]`](#classes-apachemodname): Enables specific Apache HTTPD modules.
 
####Private Classes

* `apache::confd::no_accf`: Creates the no-accf.conf configuration file in conf.d, required by FreeBSD's Apache 2.4.
* `apache::default_confd_files`: Includes conf.d files for FreeBSD.
* `apache::default_mods`: Installs the Apache modules required to run the default configuration.
* `apache::package`: Installs and configures basic Apache packages.
* `apache::params`: Manages Apache parameters.
* `apache::service`: Manages the Apache daemon.

###Defined Types

####Public Defined Types

* `apache::balancer`: Creates an Apache balancer cluster.
* `apache::balancermember`: Defines members of [mod_proxy_balancer](http://httpd.apache.org/docs/current/mod/mod_proxy_balancer.html).
* `apache::listen`: Based on the title, controls which ports Apache binds to for listening. Adds [Listen](http://httpd.apache.org/docs/current/bind.html) directives to ports.conf in the Apache HTTPD configuration directory. Titles take the form '<port>', '<ipv4>:<port>', or '<ipv6>:<port>'.
* `apache::mod`: Used to enable arbitrary Apache HTTPD modules for which there is no specific `apache::mod::[name]` class.
* `apache::namevirtualhost`: Enables name-based hosting of a virtual host. Adds all [NameVirtualHost](http://httpd.apache.org/docs/current/vhosts/name-based.html) directives to the `ports.conf` file in the Apache HTTPD configuration directory. Titles take the form '\*', '*:<port>', '\_default_:<port>, '<ip>', or '<ip>:<port>'.
* `apache::vhost`: Allows specialized configurations for virtual hosts that have requirements outside the defaults. 

####Private Defined Types

* `apache::peruser::multiplexer`: Enables the [Peruser](http://www.freebsd.org/cgi/url.cgi?ports/www/apache22-peruser-mpm/pkg-descr) module for FreeBSD only.
* `apache::peruser::processor`: Enables the [Peruser](http://www.freebsd.org/cgi/url.cgi?ports/www/apache22-peruser-mpm/pkg-descr) module for FreeBSD only.

###Templates

The Apache module relies heavily on templates to enable the `vhost` and `apache::mod` defined types. These templates are built based on Facter facts around your operating system. Unless explicitly called out, most templates are not meant for configuration.

##Limitations

###Ubuntu 10.04

The `apache::vhost::WSGIImportScript` parameter creates a statement inside the VirtualHost which is unsupported on older versions of Apache, causing this to fail.  This will be remedied in a future refactoring.

###RHEL/CentOS 5

The `apache::mod::passenger` and `apache::mod::proxy_html` classes are untested since repositories are missing compatible packages.   

###RHEL/CentOS 7

The `apache::mod::passenger` class is untested as the repository does not have packages for EL7 yet.  The fact that passenger packages aren't available also makes us unable to test the `rack_base_uri` parameter in `apache::vhost`.

###General

This module is CI tested on Centos 5 & 6, Ubuntu 12.04 & 14.04, Debian 7, and RHEL 5, 6 & 7 platforms against both the OSS and Enterprise version of Puppet. 

The module contains support for other distributions and operating systems, such as FreeBSD and Amazon Linux, but is not formally tested on those and regressions may occur.

###SELinux and Custom Paths

If you are running with SELinux in enforcing mode and want to use custom paths for your `logroot`, `mod_dir`, `vhost_dir`, and `docroot`, you will need to manage the context for the files yourself.

Something along the lines of:

```puppet
        exec { 'set_apache_defaults':
          command => 'semanage fcontext -a -t httpd_sys_content_t "/custom/path(/.*)?"',
          path    => '/bin:/usr/bin/:/sbin:/usr/sbin',
          require => Package['policycoreutils-python'],
        }
        package { 'policycoreutils-python': ensure => installed }
        exec { 'restorecon_apache':
          command => 'restorecon -Rv /apache_spec',
          path    => '/bin:/usr/bin/:/sbin:/usr/sbin',
          before  => Service['httpd'],
          require => Class['apache'],
        }
        class { 'apache': }
        host { 'test.server': ip => '127.0.0.1' }
        file { '/custom/path': ensure => directory, }
        file { '/custom/path/include': ensure => present, content => '#additional_includes' }
        apache::vhost { 'test.server':
          docroot             => '/custom/path',
          additional_includes => '/custom/path/include',
        }
```

You need to set the contexts using `semanage fcontext` not `chcon` because `file {...}` resources will reset the context to the values in the database if the resource isn't specifying the context.

##Development

###Contributing

Puppet Labs modules on the Puppet Forge are open projects, and community contributions are essential for keeping them great. We can’t access the huge number of platforms and myriad of hardware, software, and deployment configurations that Puppet is intended to serve.

We want to keep it as easy as possible to contribute changes so that our modules work in your environment. There are a few guidelines that we need contributors to follow so that we can have a chance of keeping on top of things.

You can read the complete module contribution guide [on the Puppet Labs wiki.](http://projects.puppetlabs.com/projects/module-site/wiki/Module_contributing)

###Running tests

This project contains tests for both [rspec-puppet](http://rspec-puppet.com/) and [beaker-rspec](https://github.com/puppetlabs/beaker-rspec) to verify functionality. For in-depth information please see their respective documentation.

Quickstart:

    gem install bundler
    bundle install
    bundle exec rake spec
    bundle exec rspec spec/acceptance
    RS_DEBUG=yes bundle exec rspec spec/acceptance
# Passenger

Just enabling the Passenger module is insufficient for the use of Passenger in
production. Passenger should be tunable to better fit the environment in which
it is run while being aware of the resources it required.

To this end the Apache passenger module has been modified to apply system wide
Passenger tuning declarations to `passenger.conf`. Declarations specific to a
virtual host should be passed through when defining a `vhost` (e.g.
`rack_base_uris` parameter on the `apache::vhost` type, check `README.md`).

Also, general apache module loading parameters can be supplied to enable using
a customized passenger module in place of a default-package-based version of
the module.

# Operating system support and Passenger versions

The most important configuration directive for the Apache Passenger module is
`PassengerRoot`. Its value depends on the Passenger version used (2.x, 3.x or
4.x) and on the operating system package from which the Apache Passenger module
is installed.

The following table summarises the current *default versions* and
`PassengerRoot` settings for the operating systems supported by
puppetlabs-apache:

OS               | Passenger version  | `PassengerRoot` 
Debian 7         | 3.0.13             | /usr
Ubuntu 12.04     | 2.2.11             | /usr
Ubuntu 14.04     | 4.0.37             | /usr/lib/ruby/vendor_ruby/phusion_passenger/locations.ini 
RHEL with EPEL6  | 3.0.21             | /usr/lib/ruby/gems/1.8/gems/passenger-3.0.21 

As mentioned in `README.md` there are no compatible packages available for
RHEL/CentOS 5 or RHEL/CentOS 7.

## Configuration files and locations on RHEL/CentOS

Notice two important points:

1. The Passenger version packaged in the EPEL repositories may change over time.
2. The value of `PassengerRoot` depends on the Passenger version installed.

To prevent the puppetlabs-apache module from having to keep up with these
package versions the Passenger configuration files installed by the
packages are left untouched by this module. All configuration is placed in an
extra configuration file managed by puppetlabs-apache.

This means '/etc/httpd/conf.d/passenger.conf' is installed by the
`mod_passenger` package and contains correct values for `PassengerRoot` and
`PassengerRuby`. Puppet will ignore this file. Additional configuration
directives as described in the remainder of this document are placed in
'/etc/httpd/conf.d/passenger_extra.conf', managed by Puppet.

This pertains *only* to RHEL/CentOS, *not* Debian and Ubuntu.

## Third-party and custom Passenger packages and versions

The Passenger version distributed by the default OS packages may be too old to
be useful. Newer versions may be installed via Gems, from source or from
third-party OS packages.

Most notably the Passenger developers officially provide Debian packages for a
variety of Debian and Ubuntu releases in the [Passenger APT
repository](https://oss-binaries.phusionpassenger.com/apt/passenger). Read more
about [installing these packages in the offical user
guide](http://www.modrails.com/documentation/Users%20guide%20Apache.html#install_on_debian_ubuntu).

If you install custom Passenger packages and newer version make sure to set the
directives `PassengerRoot`, `PassengerRuby` and/or `PassengerDefaultRuby`
correctly, or Passenger and Apache will fail to function properly.

For Passenger 4.x packages on Debian and Ubuntu the `PassengerRoot` directive
should almost universally be set to
`/usr/lib/ruby/vendor_ruby/phusion_passenger/locations.ini`.

# Parameters for `apache::mod::passenger`

The following class parameters configure Passenger in a global, server-wide
context.

Example:

```puppet
class { 'apache::mod::passenger':
  passenger_root             => '/usr/lib/ruby/vendor_ruby/phusion_passenger/locations.ini',
  passenger_default_ruby     => '/usr/bin/ruby1.9.3',
  passenger_high_performance => 'on',
  rails_autodetect           => 'off',
  mod_lib_path               => '/usr/lib/apache2/custom_modules',
}
```

The general form is using the all lower-case version of the configuration
directive, with underscores instead of CamelCase.

## Parameters used with passenger.conf

If you pass a default value to `apache::mod::passenger` it will be ignored and
not passed through to the configuration file. 

### passenger_root

The location to the Phusion Passenger root directory. This configuration option
is essential to Phusion Passenger, and allows Phusion Passenger to locate its
own data files. 

The default depends on the Passenger version and the means of installation. See
the above section on operating system support, versions and packages for more
information.

http://www.modrails.com/documentation/Users%20guide%20Apache.html#_passengerroot_lt_directory_gt

### passenger_default_ruby

This option specifies the default Ruby interpreter to use for web apps as well
as for all sorts of internal Phusion Passenger helper scripts, e.g. the one
used by PassengerPreStart.

This directive was introduced in Passenger 4.0.0 and will not work in versions
< 4.x. Do not set this parameter if your Passenger version is older than 4.0.0.

Defaults to `undef` for all operating systems except Ubuntu 14.04, where it is
set to '/usr/bin/ruby'.

http://www.modrails.com/documentation/Users%20guide%20Apache.html#PassengerDefaultRuby

### passenger_ruby

This directive is the same as `passenger_default_ruby` for Passenger versions
< 4.x and must be used instead of `passenger_default_ruby` for such versions.

It makes no sense to set `PassengerRuby` for Passenger >= 4.x. That
directive should only be used to override the value of `PassengerDefaultRuby`
on a non-global context, i.e. in `<VirtualHost>`, `<Directory>`, `<Location>`
and so on.

Defaults to `/usr/bin/ruby` for all supported operating systems except Ubuntu
14.04, where it is set to `undef`.

http://www.modrails.com/documentation/Users%20guide%20Apache.html#PassengerRuby

### passenger_high_performance

Default is `off`. When turned `on` Passenger runs in a higher performance mode
that can be less compatible with other Apache modules.

http://www.modrails.com/documentation/Users%20guide%20Apache.html#PassengerHighPerformance

### passenger_max_pool_size

Sets the maximum number of Passenger application processes that may
simultaneously run. The default value is 6.

http://www.modrails.com/documentation/Users%20guide%20Apache.html#_passengermaxpoolsize_lt_integer_gt

### passenger_pool_idle_time

The maximum number of seconds a Passenger Application process will be allowed
to remain idle before being shut down. The default value is 300.

http://www.modrails.com/documentation/Users%20guide%20Apache.html#PassengerPoolIdleTime

### passenger_max_requests

The maximum number of request a Passenger application will process before being
restarted. The default value is 0, which indicates that a process will only
shut down if the Pool Idle Time (see above) expires.

http://www.modrails.com/documentation/Users%20guide%20Apache.html#PassengerMaxRequests

### passenger_stat_throttle_rate

Sets how often Passenger performs file system checks, at most once every _x_
seconds. Default is 0, which means the checks are performed with every request.

http://www.modrails.com/documentation/Users%20guide%20Apache.html#_passengerstatthrottlerate_lt_integer_gt

### rack_autodetect

Should Passenger automatically detect if the document root of a virtual host is
a Rack application. Not set by default (`undef`). Note that this directive has
been removed in Passenger 4.0.0 and `PassengerEnabled` should be used instead.
Use this directive only on Passenger < 4.x.

http://www.modrails.com/documentation/Users%20guide%20Apache.html#_rackautodetect_lt_on_off_gt

### rails_autodetect

Should Passenger automatically detect if the document root of a virtual host is
a Rails application.  Not set by default (`undef`). Note that this directive
has been removed in Passenger 4.0.0 and `PassengerEnabled` should be used
instead. Use this directive only on Passenger < 4.x.

http://www.modrails.com/documentation/Users%20guide%20Apache.html#_railsautodetect_lt_on_off_gt

### passenger_use_global_queue

Allows toggling of PassengerUseGlobalQueue.  NOTE: PassengerUseGlobalQueue is
the default in Passenger 4.x and the versions >= 4.x have disabled this
configuration option altogether.  Use with caution.

## Parameters used to load the module

Unlike the tuning parameters specified above, the following parameters are only
used when loading customized passenger modules.

### mod_package

Allows overriding the default package name used for the passenger module
package.

### mod_package_ensure

Allows overriding the package installation setting used by puppet when
installing the passenger module. The default is 'present'.

### mod_id

Allows overriding the value used by apache to identify the passenger module.
The default is 'passenger_module'.

### mod_lib_path

Allows overriding the directory path used by apache when loading the passenger
module. The default is the value of `$apache::params::lib_path`.

### mod_lib

Allows overriding the library file name used by apache when loading the
passenger module. The default is 'mod_passenger.so'.

### mod_path

Allows overriding the full path to the library file used by apache when loading
the passenger module. The default is the concatenation of the `mod_lib_path`
and `mod_lib` parameters.

# Dependencies

RedHat-based systems will need to configure additional package repositories in
order to install Passenger, specifically:

* [Extra Packages for Enterprise Linux](https://fedoraproject.org/wiki/EPEL)
* [Phusion Passenger](http://passenger.stealthymonkeys.com)

Configuration of these repositories is beyond the scope of this module and is
left to the user.

# Attribution

The Passenger tuning parameters for the `apache::mod::passenger` Puppet class
was modified by Aaron Hicks (hicksa@landcareresearch.co.nz) for work on the
NeSI Project and the Tuakiri New Zealand Access Federation as a fork from the
PuppetLabs Apache module on GitHub.

* https://github.com/puppetlabs/puppetlabs-apache
* https://github.com/nesi/puppetlabs-apache
* http://www.nesi.org.nz//
* https://tuakiri.ac.nz/confluence/display/Tuakiri/Home

# Copyright and License

Copyright (C) 2012 [Puppet Labs](https://www.puppetlabs.com/) Inc

Puppet Labs can be contacted at: info@puppetlabs.com

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
require 'puppetlabs_spec_helper/rake_tasks'
require 'puppet-lint/tasks/puppet-lint'

PuppetLint.configuration.fail_on_warnings
PuppetLint.configuration.send('disable_80chars')
PuppetLint.configuration.send('disable_class_inherits_from_params_class')
PuppetLint.configuration.send('disable_class_parameter_defaults')
PuppetLint.configuration.send('disable_documentation')
PuppetLint.configuration.send('disable_single_quote_string_with_variables')
PuppetLint.configuration.send('disable_only_variable_string')
PuppetLint.configuration.ignore_paths = ["spec/**/*.pp", "pkg/**/*.pp"]
# Configuration file for the httpd service.

#
# The default processing model (MPM) is the process-based
# 'prefork' model.  A thread-based model, 'worker', is also
# available, but does not work with some modules (such as PHP).
# The service must be stopped before changing this variable.
#
#HTTPD=/usr/sbin/httpd.worker

#
# To pass additional options (for instance, -D definitions) to the
# httpd binary at startup, set OPTIONS here.
#
#OPTIONS=
#OPTIONS=-DDOWN

#
# By default, the httpd process is started in the C locale; to 
# change the locale in which the server runs, the HTTPD_LANG
# variable can be set.
#
#HTTPD_LANG=C
export SHORTHOST=`hostname -s`
class Puppet::Provider::A2mod < Puppet::Provider
  def self.prefetch(mods)
    instances.each do |prov|
      if mod = mods[prov.name]
        mod.provider = prov
      end
    end
  end

  def flush
    @property_hash.clear
  end

  def properties
    if @property_hash.empty?
      @property_hash = query || {:ensure => :absent}
      @property_hash[:ensure] = :absent if @property_hash.empty?
    end
    @property_hash.dup
  end

  def query
    self.class.instances.each do |mod|
      if mod.name == self.name or mod.name.downcase == self.name
        return mod.properties
      end
    end
    nil
  end

  def exists?
    properties[:ensure] != :absent
  end
end
require 'puppet/provider/a2mod'

Puppet::Type.type(:a2mod).provide(:a2mod, :parent => Puppet::Provider::A2mod) do
    desc "Manage Apache 2 modules on Debian and Ubuntu"

    optional_commands :encmd => "a2enmod"
    optional_commands :discmd => "a2dismod"
    commands :apache2ctl => "apache2ctl"

    confine :osfamily => :debian
    defaultfor :operatingsystem => [:debian, :ubuntu]

    def self.instances
      modules = apache2ctl("-M").lines.collect { |line|
        m = line.match(/(\w+)_module \(shared\)$/)
        m[1] if m
      }.compact

      modules.map do |mod|
        new(
          :name     => mod,
          :ensure   => :present,
          :provider => :a2mod
        )
      end
    end

    def create
        encmd resource[:name]
    end

    def destroy
        discmd resource[:name]
    end
end
require 'puppet/util/filetype'
Puppet::Type.type(:a2mod).provide(:gentoo, :parent => Puppet::Provider) do
  desc "Manage Apache 2 modules on Gentoo"

  confine :operatingsystem => :gentoo
  defaultfor :operatingsystem => :gentoo

  attr_accessor :property_hash

  def create
    @property_hash[:ensure] = :present
  end

  def exists?
    (!(@property_hash[:ensure].nil?) and @property_hash[:ensure] == :present)
  end

  def destroy
    @property_hash[:ensure] = :absent
  end

  def flush
    self.class.flush
  end

  class << self
    attr_reader :conf_file
  end

  def self.clear
    @mod_resources = []
    @modules       = []
    @other_args    = ""
  end

  def self.initvars
    @conf_file     = "/etc/conf.d/apache2"
    @filetype      = Puppet::Util::FileType.filetype(:flat).new(conf_file)
    @mod_resources = []
    @modules       = []
    @other_args    = ""
  end

  self.initvars

  # Retrieve an array of all existing modules
  def self.modules
    if @modules.length <= 0
      # Locate the APACHE_OPTS variable
      records = filetype.read.split(/\n/)
      apache2_opts = records.grep(/^\s*APACHE2_OPTS=/).first

      # Extract all defines
      while apache2_opts.sub!(/-D\s+(\w+)/, '')
        @modules << $1.downcase
      end

      # Hang on to any remaining options.
      if apache2_opts.match(/APACHE2_OPTS="(.+)"/)
        @other_args = $1.strip
      end

      @modules.sort!.uniq!
    end

    @modules
  end

  def self.prefetch(resources={})
    # Match resources with existing providers
    instances.each do |provider|
      if resource = resources[provider.name]
        resource.provider = provider
      end
    end

    # Store all resources using this provider for flushing
    resources.each do |name, resource|
      @mod_resources << resource
    end
  end

  def self.instances
    modules.map {|mod| new(:name => mod, :provider => :gentoo, :ensure => :present)}
  end

  def self.flush

    mod_list       = modules
    mods_to_remove = @mod_resources.select {|mod| mod.should(:ensure) == :absent}.map {|mod| mod[:name]}
    mods_to_add    = @mod_resources.select {|mod| mod.should(:ensure) == :present}.map {|mod| mod[:name]}

    mod_list -= mods_to_remove
    mod_list += mods_to_add
    mod_list.sort!.uniq!

    if modules != mod_list
      opts = @other_args + " "
      opts << mod_list.map {|mod| "-D #{mod.upcase}"}.join(" ")
      opts.strip!
      opts.gsub!(/\s+/, ' ')

      apache2_opts = %Q{APACHE2_OPTS="#{opts}"}
      Puppet.debug("Writing back \"#{apache2_opts}\" to #{conf_file}")

      records = filetype.read.split(/\n/)

      opts_index = records.find_index {|i| i.match(/^\s*APACHE2_OPTS/)}
      records[opts_index] = apache2_opts

      filetype.backup
      filetype.write(records.join("\n"))
      @modules = mod_list
    end
  end
end
Puppet::Type.type(:a2mod).provide :modfix do
    desc "Dummy provider for A2mod.

    Fake nil resources when there is no crontab binary available. Allows
    puppetd to run on a bootstrapped machine before a Cron package has been
    installed. Workaround for: http://projects.puppetlabs.com/issues/2384
    "

    def self.instances
        []
    end
end
require 'puppet/provider/a2mod'

Puppet::Type.type(:a2mod).provide(:redhat, :parent => Puppet::Provider::A2mod) do
  desc "Manage Apache 2 modules on RedHat family OSs"

  commands :apachectl => "apachectl"

  confine :osfamily => :redhat
  defaultfor :osfamily => :redhat

  require 'pathname'

  # modpath: Path to default apache modules directory /etc/httpd/mod.d
  # modfile: Path to module load configuration file; Default: resides under modpath directory
  # libfile: Path to actual apache module library. Added in modfile LoadModule

  attr_accessor :modfile, :libfile
  class << self
    attr_accessor :modpath
    def preinit
      @modpath = "/etc/httpd/mod.d"
    end
  end

  self.preinit

  def create
    File.open(modfile,'w') do |f|
      f.puts "LoadModule #{resource[:identifier]} #{libfile}"
    end
  end

  def destroy
    File.delete(modfile)
  end

  def self.instances
    modules = apachectl("-M").lines.collect { |line|
      m = line.match(/(\w+)_module \(shared\)$/)
      m[1] if m
    }.compact

    modules.map do |mod|
      new(
        :name     => mod,
        :ensure   => :present,
        :provider => :redhat
      )
    end
  end

  def modfile
    modfile ||= "#{self.class.modpath}/#{resource[:name]}.load"
  end

  # Set libfile path: If absolute path is passed, then maintain it. Else, make it default from 'modules' dir.
  def libfile
    libfile = Pathname.new(resource[:lib]).absolute? ? resource[:lib] : "modules/#{resource[:lib]}"
  end
end
Puppet::Type.newtype(:a2mod) do
    @doc = "Manage Apache 2 modules"

    ensurable

    newparam(:name) do
       Puppet.warning "The a2mod provider is deprecated, please use apache::mod instead"
       desc "The name of the module to be managed"

       isnamevar

    end

    newparam(:lib) do
      desc "The name of the .so library to be loaded"

      defaultto { "mod_#{@resource[:name]}.so" }
    end
 
    newparam(:identifier) do
      desc "Module identifier string used by LoadModule. Default: module-name_module"

      # http://httpd.apache.org/docs/2.2/mod/module-dict.html#ModuleIdentifier

      defaultto { "#{resource[:name]}_module" }
    end

    autorequire(:package) { catalog.resource(:package, 'httpd')}

end
# == Define Resource Type: apache::balancer
#
# This type will create an apache balancer cluster file inside the conf.d
# directory. Each balancer cluster needs one or more balancer members (that can
# be declared with the apache::balancermember defined resource type). Using
# storeconfigs, you can export the apache::balancermember resources on all
# balancer members, and then collect them on a single apache load balancer
# server.
#
# === Requirement/Dependencies:
#
# Currently requires the puppetlabs/concat module on the Puppet Forge and uses
# storeconfigs on the Puppet Master to export/collect resources from all
# balancer members.
#
# === Parameters
#
# [*name*]
# The namevar of the defined resource type is the balancer clusters name.
# This name is also used in the name of the conf.d file
#
# [*proxy_set*]
# Hash, default empty. If given, each key-value pair will be used as a ProxySet
# line in the configuration.
#
# [*collect_exported*]
# Boolean, default 'true'. True means 'collect exported @@balancermember
# resources' (for the case when every balancermember node exports itself),
# false means 'rely on the existing declared balancermember resources' (for the
# case when you know the full set of balancermembers in advance and use
# apache::balancermember with array arguments, which allows you to deploy
# everything in 1 run)
#
#
# === Examples
#
# Exporting the resource for a balancer member:
#
# apache::balancer { 'puppet00': }
#
define apache::balancer (
  $proxy_set = {},
  $collect_exported = true,
) {
  include concat::setup
  include ::apache::mod::proxy_balancer

  $target = "${::apache::params::confd_dir}/balancer_${name}.conf"

  concat { $target:
    owner  => '0',
    group  => '0',
    mode   => '0644',
    notify => Service['httpd'],
  }

  concat::fragment { "00-${name}-header":
    ensure  => present,
    target  => $target,
    order   => '01',
    content => "<Proxy balancer://${name}>\n",
  }

  if $collect_exported {
    Apache::Balancermember <<| balancer_cluster == $name |>>
  }
  # else: the resources have been created and they introduced their
  # concat fragments. We don't have to do anything about them.

  concat::fragment { "01-${name}-proxyset":
    ensure  => present,
    target  => $target,
    order   => '19',
    content => inline_template("<% proxy_set.keys.sort.each do |key| %> Proxyset <%= key %>=<%= proxy_set[key] %>\n<% end %>"),
  }

  concat::fragment { "01-${name}-footer":
    ensure  => present,
    target  => $target,
    order   => '20',
    content => "</Proxy>\n",
  }
}
# == Define Resource Type: apache::balancermember
#
# This type will setup a balancer member inside a listening service
# configuration block in /etc/apache/apache.cfg on the load balancer.
# currently it only has the ability to specify the instance name, url and an
# array of options. More features can be added as needed. The best way to
# implement this is to export this resource for all apache balancer member
# servers, and then collect them on the main apache load balancer.
#
# === Requirement/Dependencies:
#
# Currently requires the puppetlabs/concat module on the Puppet Forge and
# uses storeconfigs on the Puppet Master to export/collect resources
# from all balancer members.
#
# === Parameters
#
# [*name*]
# The title of the resource is arbitrary and only utilized in the concat
# fragment name.
#
# [*balancer_cluster*]
# The apache service's instance name (or, the title of the apache::balancer
# resource). This must match up with a declared apache::balancer resource.
#
# [*url*]
# The url used to contact the balancer member server.
#
# [*options*]
# An array of options to be specified after the url.
#
# === Examples
#
# Exporting the resource for a balancer member:
#
# @@apache::balancermember { 'apache':
#   balancer_cluster => 'puppet00',
#   url              => "ajp://${::fqdn}:8009"
#   options          => ['ping=5', 'disablereuse=on', 'retry=5', 'ttl=120'],
# }
#
define apache::balancermember(
  $balancer_cluster,
  $url = "http://${::fqdn}/",
  $options = [],
) {

  concat::fragment { "BalancerMember ${url}":
    ensure  => present,
    target  => "${::apache::params::confd_dir}/balancer_${balancer_cluster}.conf",
    content => inline_template(" BalancerMember ${url} <%= @options.join ' ' %>\n"),
  }
}
class apache::confd::no_accf {
  # Template uses no variables
  file { 'no-accf.conf':
    ensure  => 'file',
    path    => "${::apache::confd_dir}/no-accf.conf",
    content => template('apache/confd/no-accf.conf.erb'),
    require => Exec["mkdir ${::apache::confd_dir}"],
    before  => File[$::apache::confd_dir],
  }
}
class apache::default_confd_files (
  $all = true,
) {
  # The rest of the conf.d/* files only get loaded if we want them
  if $all {
    case $::osfamily {
      'freebsd': {
        include ::apache::confd::no_accf
      }
      default: {
        # do nothing
      }
    }
  }
}
class apache::default_mods (
  $all            = true,
  $mods           = undef,
  $apache_version = $::apache::apache_version
) {
  # These are modules required to run the default configuration.
  # They are not configurable at this time, so we just include
  # them to make sure it works.
  case $::osfamily {
    'redhat', 'freebsd': {
      ::apache::mod { 'log_config': }
      if versioncmp($apache_version, '2.4') >= 0 {
        # Lets fork it
        ::apache::mod { 'systemd': }
        ::apache::mod { 'unixd': }
      }
    }
    default: {}
  }
  ::apache::mod { 'authz_host': }

  # The rest of the modules only get loaded if we want all modules enabled
  if $all {
    case $::osfamily {
      'debian': {
        include ::apache::mod::reqtimeout
        if versioncmp($apache_version, '2.4') >= 0 {
          ::apache::mod { 'authn_core': }
        }
      }
      'redhat': {
        include ::apache::mod::actions
        include ::apache::mod::cache
        include ::apache::mod::mime
        include ::apache::mod::mime_magic
        include ::apache::mod::vhost_alias
        include ::apache::mod::suexec
        include ::apache::mod::rewrite
        include ::apache::mod::speling
        ::apache::mod { 'auth_digest': }
        ::apache::mod { 'authn_anon': }
        ::apache::mod { 'authn_dbm': }
        ::apache::mod { 'authz_dbm': }
        ::apache::mod { 'authz_owner': }
        ::apache::mod { 'expires': }
        ::apache::mod { 'ext_filter': }
        ::apache::mod { 'include': }
        ::apache::mod { 'logio': }
        ::apache::mod { 'substitute': }
        ::apache::mod { 'usertrack': }
        ::apache::mod { 'version': }

        if versioncmp($apache_version, '2.4') >= 0 {
          ::apache::mod { 'authn_core': }
        }
        else {
          ::apache::mod { 'authn_alias': }
          ::apache::mod { 'authn_default': }
        }
      }
      'freebsd': {
        include ::apache::mod::actions
        include ::apache::mod::cache
        include ::apache::mod::disk_cache
        include ::apache::mod::headers
        include ::apache::mod::info
        include ::apache::mod::mime_magic
        include ::apache::mod::reqtimeout
        include ::apache::mod::rewrite
        include ::apache::mod::userdir
        include ::apache::mod::vhost_alias
        include ::apache::mod::speling

        ::apache::mod { 'asis': }
        ::apache::mod { 'auth_digest': }
        ::apache::mod { 'authn_alias': }
        ::apache::mod { 'authn_anon': }
        ::apache::mod { 'authn_dbm': }
        ::apache::mod { 'authn_default': }
        ::apache::mod { 'authz_dbm': }
        ::apache::mod { 'authz_owner': }
        ::apache::mod { 'cern_meta': }
        ::apache::mod { 'charset_lite': }
        ::apache::mod { 'dumpio': }
        ::apache::mod { 'expires': }
        ::apache::mod { 'file_cache': }
        ::apache::mod { 'filter':}
        ::apache::mod { 'imagemap':}
        ::apache::mod { 'include': }
        ::apache::mod { 'logio': }
        ::apache::mod { 'unique_id': }
        ::apache::mod { 'usertrack': }
        ::apache::mod { 'version': }
      }
      default: {}
    }
    case $::apache::mpm_module {
      'prefork': {
        include ::apache::mod::cgi
      }
      'worker': {
        include ::apache::mod::cgid
      }
      default: {
        # do nothing
      }
    }
    include ::apache::mod::alias
    include ::apache::mod::autoindex
    include ::apache::mod::dav
    include ::apache::mod::dav_fs
    include ::apache::mod::deflate
    include ::apache::mod::dir
    include ::apache::mod::mime
    include ::apache::mod::negotiation
    include ::apache::mod::setenvif
    ::apache::mod { 'auth_basic': }
    ::apache::mod { 'authn_file': }

      if versioncmp($apache_version, '2.4') >= 0 {
      # authz_core is needed for 'Require' directive
      ::apache::mod { 'authz_core':
        id => 'authz_core_module',
      }

      # filter is needed by mod_deflate
      ::apache::mod { 'filter': }

      # lots of stuff seems to break without access_compat
      ::apache::mod { 'access_compat': }
    } else {
      ::apache::mod { 'authz_default': }
    }

    ::apache::mod { 'authz_groupfile': }
    ::apache::mod { 'authz_user': }
    ::apache::mod { 'env': }
  } elsif $mods {
    ::apache::default_mods::load { $mods: }

    if versioncmp($apache_version, '2.4') >= 0 {
      # authz_core is needed for 'Require' directive
      ::apache::mod { 'authz_core':
        id => 'authz_core_module',
      }

      # filter is needed by mod_deflate
      ::apache::mod { 'filter': }
    }
  } else {
    if versioncmp($apache_version, '2.4') >= 0 {
      # authz_core is needed for 'Require' directive
      ::apache::mod { 'authz_core':
        id => 'authz_core_module',
      }

      # filter is needed by mod_deflate
      ::apache::mod { 'filter': }
    }
  }
}
# private define
define apache::default_mods::load ($module = $title) {
  if defined("apache::mod::${module}") {
    include "::apache::mod::${module}"
  } else {
    ::apache::mod { $module: }
  }
}
class apache::dev {
  if $::osfamily == 'FreeBSD' and !defined(Class['apache::package']) {
    fail('apache::dev requires apache::package; please include apache or apache::package class first')
  }
  include ::apache::params
  $packages = $::apache::params::dev_packages
  package { $packages:
    ensure  => present,
    require => Package['httpd'],
  }
}
define apache::fastcgi::server (
  $host          = '127.0.0.1:9000',
  $timeout       = 15,
  $flush         = false,
  $faux_path     = "/var/www/${name}.fcgi",
  $fcgi_alias    = "/${name}.fcgi",
  $file_type     = 'application/x-httpd-php'
) {
  include apache::mod::fastcgi

  Apache::Mod['fastcgi'] -> Apache::Fastcgi::Server[$title]

  file { "fastcgi-pool-${name}.conf":
    ensure  => present,
    path    => "${::apache::confd_dir}/fastcgi-pool-${name}.conf",
    owner   => 'root',
    group   => $::apache::params::root_group,
    mode    => '0644',
    content => template('apache/fastcgi/server.erb'),
    require => Exec["mkdir ${::apache::confd_dir}"],
    before  => File[$::apache::confd_dir],
    notify  => Class['apache::service'],
  }
}
# Class: apache
#
# This class installs Apache
#
# Parameters:
#
# Actions:
#   - Install Apache
#   - Manage Apache service
#
# Requires:
#
# Sample Usage:
#
class apache (
  $service_name         = $::apache::params::service_name,
  $default_mods         = true,
  $default_vhost        = true,
  $default_confd_files  = true,
  $default_ssl_vhost    = false,
  $default_ssl_cert     = $::apache::params::default_ssl_cert,
  $default_ssl_key      = $::apache::params::default_ssl_key,
  $default_ssl_chain    = undef,
  $default_ssl_ca       = undef,
  $default_ssl_crl_path = undef,
  $default_ssl_crl      = undef,
  $ip                   = undef,
  $service_enable       = true,
  $service_ensure       = 'running',
  $purge_configs        = true,
  $purge_vhost_dir      = undef,
  $serveradmin          = 'root@localhost',
  $sendfile             = 'On',
  $error_documents      = false,
  $timeout              = '120',
  $httpd_dir            = $::apache::params::httpd_dir,
  $server_root          = $::apache::params::server_root,
  $confd_dir            = $::apache::params::confd_dir,
  $vhost_dir            = $::apache::params::vhost_dir,
  $vhost_enable_dir     = $::apache::params::vhost_enable_dir,
  $mod_dir              = $::apache::params::mod_dir,
  $mod_enable_dir       = $::apache::params::mod_enable_dir,
  $mpm_module           = $::apache::params::mpm_module,
  $conf_template        = $::apache::params::conf_template,
  $servername           = $::apache::params::servername,
  $manage_user          = true,
  $manage_group         = true,
  $user                 = $::apache::params::user,
  $group                = $::apache::params::group,
  $keepalive            = $::apache::params::keepalive,
  $keepalive_timeout    = $::apache::params::keepalive_timeout,
  $max_keepalive_requests = $apache::params::max_keepalive_requests,
  $logroot              = $::apache::params::logroot,
  $log_level            = $::apache::params::log_level,
  $log_formats          = {},
  $ports_file           = $::apache::params::ports_file,
  $apache_version       = $::apache::version::default,
  $server_tokens        = 'OS',
  $server_signature     = 'On',
  $trace_enable         = 'On',
  $package_ensure       = 'installed',
) inherits ::apache::params {
  validate_bool($default_vhost)
  validate_bool($default_ssl_vhost)
  validate_bool($default_confd_files)
  # true/false is sufficient for both ensure and enable
  validate_bool($service_enable)

  $valid_mpms_re = $apache_version ? {
    '2.4'   => '(event|itk|peruser|prefork|worker)',
    default => '(event|itk|prefork|worker)'
  }

  if $mpm_module {
    validate_re($mpm_module, $valid_mpms_re)
  }

  # NOTE: on FreeBSD it's mpm module's responsibility to install httpd package.
  # NOTE: the same strategy may be introduced for other OSes. For this, you
  # should delete the 'if' block below and modify all MPM modules' manifests
  # such that they include apache::package class (currently event.pp, itk.pp,
  # peruser.pp, prefork.pp, worker.pp).
  if $::osfamily != 'FreeBSD' {
    package { 'httpd':
      ensure => $package_ensure,
      name   => $::apache::params::apache_name,
      notify => Class['Apache::Service'],
    }
  }
  validate_re($sendfile, [ '^[oO]n$' , '^[oO]ff$' ])

  # declare the web server user and group
  # Note: requiring the package means the package ought to create them and not puppet
  validate_bool($manage_user)
  if $manage_user {
    user { $user:
      ensure  => present,
      gid     => $group,
      require => Package['httpd'],
    }
  }
  validate_bool($manage_group)
  if $manage_group {
    group { $group:
      ensure  => present,
      require => Package['httpd']
    }
  }

  $valid_log_level_re = '(emerg|alert|crit|error|warn|notice|info|debug)'

  validate_re($log_level, $valid_log_level_re,
  "Log level '${log_level}' is not one of the supported Apache HTTP Server log levels.")

  class { '::apache::service':
    service_name   => $service_name,
    service_enable => $service_enable,
    service_ensure => $service_ensure,
  }

  # Set purge vhostd appropriately
  if $purge_vhost_dir == undef {
    $_purge_vhost_dir = $purge_configs
  } else {
    $_purge_vhost_dir = $purge_vhost_dir
  }

  Exec {
    path => '/bin:/sbin:/usr/bin:/usr/sbin',
  }

  exec { "mkdir ${confd_dir}":
    creates => $confd_dir,
    require => Package['httpd'],
  }
  file { $confd_dir:
    ensure  => directory,
    recurse => true,
    purge   => $purge_configs,
    notify  => Class['Apache::Service'],
    require => Package['httpd'],
  }

  if ! defined(File[$mod_dir]) {
    exec { "mkdir ${mod_dir}":
      creates => $mod_dir,
      require => Package['httpd'],
    }
    # Don't purge available modules if an enable dir is used
    $purge_mod_dir = $purge_configs and !$mod_enable_dir
    file { $mod_dir:
      ensure  => directory,
      recurse => true,
      purge   => $purge_mod_dir,
      notify  => Class['Apache::Service'],
      require => Package['httpd'],
    }
  }

  if $mod_enable_dir and ! defined(File[$mod_enable_dir]) {
    $mod_load_dir = $mod_enable_dir
    exec { "mkdir ${mod_enable_dir}":
      creates => $mod_enable_dir,
      require => Package['httpd'],
    }
    file { $mod_enable_dir:
      ensure  => directory,
      recurse => true,
      purge   => $purge_configs,
      notify  => Class['Apache::Service'],
      require => Package['httpd'],
    }
  } else {
    $mod_load_dir = $mod_dir
  }

  if ! defined(File[$vhost_dir]) {
    exec { "mkdir ${vhost_dir}":
      creates => $vhost_dir,
      require => Package['httpd'],
    }
    file { $vhost_dir:
      ensure  => directory,
      recurse => true,
      purge   => $_purge_vhost_dir,
      notify  => Class['Apache::Service'],
      require => Package['httpd'],
    }
  }

  if $vhost_enable_dir and ! defined(File[$vhost_enable_dir]) {
    $vhost_load_dir = $vhost_enable_dir
    exec { "mkdir ${vhost_load_dir}":
      creates => $vhost_load_dir,
      require => Package['httpd'],
    }
    file { $vhost_enable_dir:
      ensure  => directory,
      recurse => true,
      purge   => $_purge_vhost_dir,
      notify  => Class['Apache::Service'],
      require => Package['httpd'],
    }
  } else {
    $vhost_load_dir = $vhost_dir
  }

  concat { $ports_file:
    owner   => 'root',
    group   => $::apache::params::root_group,
    mode    => '0644',
    notify  => Class['Apache::Service'],
    require => Package['httpd'],
  }
  concat::fragment { 'Apache ports header':
    ensure  => present,
    target  => $ports_file,
    content => template('apache/ports_header.erb')
  }

  if $::apache::params::conf_dir and $::apache::params::conf_file {
    case $::osfamily {
      'debian': {
        $docroot              = '/var/www'
        $pidfile              = '${APACHE_PID_FILE}'
        $error_log            = 'error.log'
        $error_documents_path = '/usr/share/apache2/error'
        $scriptalias          = '/usr/lib/cgi-bin'
        $access_log_file      = 'access.log'
      }
      'redhat': {
        $docroot              = '/var/www/html'
        $pidfile              = 'run/httpd.pid'
        $error_log            = 'error_log'
        $error_documents_path = '/var/www/error'
        $scriptalias          = '/var/www/cgi-bin'
        $access_log_file      = 'access_log'
      }
      'freebsd': {
        $docroot              = '/usr/local/www/apache22/data'
        $pidfile              = '/var/run/httpd.pid'
        $error_log            = 'httpd-error.log'
        $error_documents_path = '/usr/local/www/apache22/error'
        $scriptalias          = '/usr/local/www/apache22/cgi-bin'
        $access_log_file      = 'httpd-access.log'
      }
      default: {
        fail("Unsupported osfamily ${::osfamily}")
      }
    }

    $apxs_workaround = $::osfamily ? {
      'freebsd' => true,
      default   => false
    }

    # Template uses:
    # - $pidfile
    # - $user
    # - $group
    # - $logroot
    # - $error_log
    # - $sendfile
    # - $mod_dir
    # - $ports_file
    # - $confd_dir
    # - $vhost_dir
    # - $error_documents
    # - $error_documents_path
    # - $apxs_workaround
    # - $keepalive
    # - $keepalive_timeout
    # - $max_keepalive_requests
    # - $server_root
    # - $server_tokens
    # - $server_signature
    # - $trace_enable
    file { "${::apache::params::conf_dir}/${::apache::params::conf_file}":
      ensure  => file,
      content => template($conf_template),
      notify  => Class['Apache::Service'],
      require => Package['httpd'],
    }

    # preserve back-wards compatibility to the times when default_mods was
    # only a boolean value. Now it can be an array (too)
    if is_array($default_mods) {
      class { '::apache::default_mods':
        all  => false,
        mods => $default_mods,
      }
    } else {
      class { '::apache::default_mods':
        all => $default_mods,
      }
    }
    class { '::apache::default_confd_files':
      all => $default_confd_files
    }
    if $mpm_module {
      class { "::apache::mod::${mpm_module}": }
    }

    $default_vhost_ensure = $default_vhost ? {
      true  => 'present',
      false => 'absent'
    }
    $default_ssl_vhost_ensure = $default_ssl_vhost ? {
      true  => 'present',
      false => 'absent'
    }

    ::apache::vhost { 'default':
      ensure          => $default_vhost_ensure,
      port            => 80,
      docroot         => $docroot,
      scriptalias     => $scriptalias,
      serveradmin     => $serveradmin,
      access_log_file => $access_log_file,
      priority        => '15',
      ip              => $ip,
    }
    $ssl_access_log_file = $::osfamily ? {
      'freebsd' => $access_log_file,
      default   => "ssl_${access_log_file}",
    }
    ::apache::vhost { 'default-ssl':
      ensure          => $default_ssl_vhost_ensure,
      port            => 443,
      ssl             => true,
      docroot         => $docroot,
      scriptalias     => $scriptalias,
      serveradmin     => $serveradmin,
      access_log_file => $ssl_access_log_file,
      priority        => '15',
      ip              => $ip,
    }
  }
}
define apache::listen {
  $listen_addr_port = $name

  # Template uses: $listen_addr_port
  concat::fragment { "Listen ${listen_addr_port}":
    ensure  => present,
    target  => $::apache::ports_file,
    content => template('apache/listen.erb'),
  }
}
define apache::mod (
  $package        = undef,
  $package_ensure = 'present',
  $lib            = undef,
  $lib_path       = $::apache::params::lib_path,
  $id             = undef,
  $path           = undef,
  $loadfile_name  = undef,
  $loadfiles      = undef,
) {
  if ! defined(Class['apache']) {
    fail('You must include the apache base class before using any apache defined resources')
  }

  $mod = $name
  #include apache #This creates duplicate resources in rspec-puppet
  $mod_dir = $::apache::mod_dir

  # Determine if we have special lib
  $mod_libs = $::apache::params::mod_libs
  $mod_lib = $mod_libs[$mod] # 2.6 compatibility hack
  if $lib {
    $_lib = $lib
  } elsif $mod_lib {
    $_lib = $mod_lib
  } else {
    $_lib = "mod_${mod}.so"
  }

  # Determine if declaration specified a path to the module
  if $path {
    $_path = $path
  } else {
    $_path = "${lib_path}/${_lib}"
  }

  if $id {
    $_id = $id
  } else {
    $_id = "${mod}_module"
  }

  if $loadfile_name {
    $_loadfile_name = $loadfile_name
  } else {
    $_loadfile_name = "${mod}.load"
  }

  # Determine if we have a package
  $mod_packages = $::apache::params::mod_packages
  $mod_package = $mod_packages[$mod] # 2.6 compatibility hack
  if $package {
    $_package = $package
  } elsif $mod_package {
    $_package = $mod_package
  } else {
    $_package = undef
  }
  if $_package and ! defined(Package[$_package]) {
    # note: FreeBSD/ports uses apxs tool to activate modules; apxs clutters
    # httpd.conf with 'LoadModule' directives; here, by proper resource
    # ordering, we ensure that our version of httpd.conf is reverted after
    # the module gets installed.
    $package_before = $::osfamily ? {
      'freebsd' => [
        File[$_loadfile_name],
        File["${::apache::params::conf_dir}/${::apache::params::conf_file}"]
      ],
      default => File[$_loadfile_name],
    }
    # $_package may be an array
    package { $_package:
      ensure  => $package_ensure,
      require => Package['httpd'],
      before  => $package_before,
    }
  }

  file { "${_loadfile_name}":
    ensure  => file,
    path    => "${mod_dir}/${_loadfile_name}",
    owner   => 'root',
    group   => $::apache::params::root_group,
    mode    => '0644',
    content => template('apache/mod/load.erb'),
    require => [
      Package['httpd'],
      Exec["mkdir ${mod_dir}"],
    ],
    before  => File[$mod_dir],
    notify  => Service['httpd'],
  }

  if $::osfamily == 'Debian' {
    $enable_dir = $::apache::mod_enable_dir
    file{ "${_loadfile_name} symlink":
      ensure  => link,
      path    => "${enable_dir}/${_loadfile_name}",
      target  => "${mod_dir}/${_loadfile_name}",
      owner   => 'root',
      group   => $::apache::params::root_group,
      mode    => '0644',
      require => [
        File[$_loadfile_name],
        Exec["mkdir ${enable_dir}"],
      ],
      before  => File[$enable_dir],
      notify  => Service['httpd'],
    }
    # Each module may have a .conf file as well, which should be
    # defined in the class apache::mod::module
    # Some modules do not require this file.
    if defined(File["${mod}.conf"]) {
      file{ "${mod}.conf symlink":
        ensure  => link,
        path    => "${enable_dir}/${mod}.conf",
        target  => "${mod_dir}/${mod}.conf",
        owner   => 'root',
        group   => $::apache::params::root_group,
        mode    => '0644',
        require => [
          File["${mod}.conf"],
          Exec["mkdir ${enable_dir}"],
        ],
        before  => File[$enable_dir],
        notify  => Service['httpd'],
      }
    }
  }
}
class apache::mod::actions {
  apache::mod { 'actions': }
}
class apache::mod::alias(
  $apache_version = $apache::apache_version
) {
  $icons_path = $::osfamily ? {
    'debian'  => '/usr/share/apache2/icons',
    'redhat'  => '/var/www/icons',
    'freebsd' => '/usr/local/www/apache22/icons',
  }
  apache::mod { 'alias': }
  # Template uses $icons_path
  file { 'alias.conf':
    ensure  => file,
    path    => "${::apache::mod_dir}/alias.conf",
    content => template('apache/mod/alias.conf.erb'),
    require => Exec["mkdir ${::apache::mod_dir}"],
    before  => File[$::apache::mod_dir],
    notify  => Service['httpd'],
  }
}
class apache::mod::auth_basic {
  ::apache::mod { 'auth_basic': }
}
class apache::mod::auth_kerb {
  ::apache::mod { 'auth_kerb': }
}


class apache::mod::authnz_ldap (
  $verifyServerCert = true,
) {
  include '::apache::mod::ldap'
  ::apache::mod { 'authnz_ldap': }

  validate_bool($verifyServerCert)

  # Template uses:
  # - $verifyServerCert
  file { 'authnz_ldap.conf':
    ensure  => file,
    path    => "${::apache::mod_dir}/authnz_ldap.conf",
    content => template('apache/mod/authnz_ldap.conf.erb'),
    require => Exec["mkdir ${::apache::mod_dir}"],
    before  => File[$::apache::mod_dir],
    notify  => Service['httpd'],
  }
}
class apache::mod::autoindex {
  ::apache::mod { 'autoindex': }
  # Template uses no variables
  file { 'autoindex.conf':
    ensure  => file,
    path    => "${::apache::mod_dir}/autoindex.conf",
    content => template('apache/mod/autoindex.conf.erb'),
    require => Exec["mkdir ${::apache::mod_dir}"],
    before  => File[$::apache::mod_dir],
    notify  => Service['httpd'],
  }
}
class apache::mod::cache {
  ::apache::mod { 'cache': }
}
class apache::mod::cgi {
  Class['::apache::mod::prefork'] -> Class['::apache::mod::cgi']
  ::apache::mod { 'cgi': }
}
class apache::mod::cgid {
  Class['::apache::mod::worker'] -> Class['::apache::mod::cgid']

  # Debian specifies it's cgid sock path, but RedHat uses the default value
  # with no config file
  $cgisock_path = $::osfamily ? {
    'debian'  => '${APACHE_RUN_DIR}/cgisock',
    'freebsd' => 'cgisock',
    default   => undef,
  }
  ::apache::mod { 'cgid': }
  if $cgisock_path {
    # Template uses $cgisock_path
    file { 'cgid.conf':
      ensure  => file,
      path    => "${::apache::mod_dir}/cgid.conf",
      content => template('apache/mod/cgid.conf.erb'),
      require => Exec["mkdir ${::apache::mod_dir}"],
      before  => File[$::apache::mod_dir],
      notify  => Service['httpd'],
    }
  }
}
class apache::mod::dav {
  ::apache::mod { 'dav': }
}
class apache::mod::dav_fs {
  $dav_lock = $::osfamily ? {
    'debian'  => '${APACHE_LOCK_DIR}/DAVLock',
    'freebsd' => '/usr/local/var/DavLock',
    default   => '/var/lib/dav/lockdb',
  }

  Class['::apache::mod::dav'] -> Class['::apache::mod::dav_fs']
  ::apache::mod { 'dav_fs': }

  # Template uses: $dav_lock
  file { 'dav_fs.conf':
    ensure  => file,
    path    => "${::apache::mod_dir}/dav_fs.conf",
    content => template('apache/mod/dav_fs.conf.erb'),
    require => Exec["mkdir ${::apache::mod_dir}"],
    before  => File[$::apache::mod_dir],
    notify  => Service['httpd'],
  }
}
class apache::mod::dav_svn (
  $authz_svn_enabled = false,
) {
    Class['::apache::mod::dav'] -> Class['::apache::mod::dav_svn']
    include ::apache::mod::dav
    ::apache::mod { 'dav_svn': }

    if $authz_svn_enabled {
      ::apache::mod { 'authz_svn':
        loadfile_name => $::osfamily ? {
          'Debian' => undef,
          default  => 'dav_svn_authz_svn.load',
        },
        require       => Apache::Mod['dav_svn'],
      }
    }
}
class apache::mod::deflate (
  $types = [
    'text/html text/plain text/xml',
    'text/css',
    'application/x-javascript application/javascript application/ecmascript',
    'application/rss+xml'
  ],
  $notes = {
    'Input'  => 'instream',
    'Output' => 'outstream',
    'Ratio'  => 'ratio'
  }
) {
  ::apache::mod { 'deflate': }

  file { 'deflate.conf':
    ensure  => file,
    path    => "${::apache::mod_dir}/deflate.conf",
    content => template('apache/mod/deflate.conf.erb'),
    require => Exec["mkdir ${::apache::mod_dir}"],
    before  => File[$::apache::mod_dir],
    notify  => Service['httpd'],
  }
}
class apache::mod::dev {
  # Development packages are not apache modules
  warning('apache::mod::dev is deprecated; please use apache::dev')
  include ::apache::dev
}
# Note: this sets the global DirectoryIndex directive, it may be necessary to consider being able to modify the apache::vhost to declare DirectoryIndex statements in a vhost configuration
# Parameters:
# - $indexes provides a string for the DirectoryIndex directive http://httpd.apache.org/docs/current/mod/mod_dir.html#directoryindex
class apache::mod::dir (
  $dir     = 'public_html',
  $indexes = ['index.html','index.html.var','index.cgi','index.pl','index.php','index.xhtml'],
) {
  validate_array($indexes)
  ::apache::mod { 'dir': }

  # Template uses
  # - $indexes
  file { 'dir.conf':
    ensure  => file,
    path    => "${::apache::mod_dir}/dir.conf",
    content => template('apache/mod/dir.conf.erb'),
    require => Exec["mkdir ${::apache::mod_dir}"],
    before  => File[$::apache::mod_dir],
    notify  => Service['httpd'],
  }
}
class apache::mod::disk_cache {
  $cache_root = $::osfamily ? {
    'debian'  => '/var/cache/apache2/mod_disk_cache',
    'redhat'  => '/var/cache/mod_proxy',
    'freebsd' => '/var/cache/mod_disk_cache',
  }
  if $::osfamily != 'FreeBSD' {
    # FIXME: investigate why disk_cache was dependent on proxy
    # NOTE: on FreeBSD disk_cache is compiled by default but proxy is not
    Class['::apache::mod::proxy'] -> Class['::apache::mod::disk_cache']
  }
  Class['::apache::mod::cache'] -> Class['::apache::mod::disk_cache']

  apache::mod { 'disk_cache': }
  # Template uses $cache_proxy
  file { 'disk_cache.conf':
    ensure  => file,
    path    => "${::apache::mod_dir}/disk_cache.conf",
    content => template('apache/mod/disk_cache.conf.erb'),
    require => Exec["mkdir ${::apache::mod_dir}"],
    before  => File[$::apache::mod_dir],
    notify  => Service['httpd'],
  }
}
class apache::mod::event (
  $startservers        = '2',
  $maxclients          = '150',
  $minsparethreads     = '25',
  $maxsparethreads     = '75',
  $threadsperchild     = '25',
  $maxrequestsperchild = '0',
  $serverlimit         = '25',
  $apache_version      = $::apache::apache_version,
) {
  if defined(Class['apache::mod::itk']) {
    fail('May not include both apache::mod::event and apache::mod::itk on the same node')
  }
  if defined(Class['apache::mod::peruser']) {
    fail('May not include both apache::mod::event and apache::mod::peruser on the same node')
  }
  if defined(Class['apache::mod::prefork']) {
    fail('May not include both apache::mod::event and apache::mod::prefork on the same node')
  }
  if defined(Class['apache::mod::worker']) {
    fail('May not include both apache::mod::event and apache::mod::worker on the same node')
  }
  File {
    owner => 'root',
    group => $::apache::params::root_group,
    mode  => '0644',
  }

  # Template uses:
  # - $startservers
  # - $maxclients
  # - $minsparethreads
  # - $maxsparethreads
  # - $threadsperchild
  # - $maxrequestsperchild
  # - $serverlimit
  file { "${::apache::mod_dir}/event.conf":
    ensure  => file,
    content => template('apache/mod/event.conf.erb'),
    require => Exec["mkdir ${::apache::mod_dir}"],
    before  => File[$::apache::mod_dir],
    notify  => Service['httpd'],
  }

  case $::osfamily {
    'redhat': {
      if versioncmp($apache_version, '2.4') >= 0 {
        apache::mpm{ 'event':
          apache_version => $apache_version,
        }
      }
    }
    'debian','freebsd' : {
      apache::mpm{ 'event':
        apache_version => $apache_version,
      }
    }
    default: {
      fail("Unsupported osfamily ${::osfamily}")
    }
  }
}
class apache::mod::expires {
  ::apache::mod { 'expires': }
}
class apache::mod::fastcgi {

  # Debian specifies it's fastcgi lib path, but RedHat uses the default value
  # with no config file
  $fastcgi_lib_path = $::apache::params::fastcgi_lib_path

  ::apache::mod { 'fastcgi': }

  if $fastcgi_lib_path {
    # Template uses:
    # - $fastcgi_server
    # - $fastcgi_socket
    # - $fastcgi_dir
    file { 'fastcgi.conf':
      ensure  => file,
      path    => "${::apache::mod_dir}/fastcgi.conf",
      content => template('apache/mod/fastcgi.conf.erb'),
      require => Exec["mkdir ${::apache::mod_dir}"],
      before  => File[$::apache::mod_dir],
      notify  => Service['httpd'],
    }
  }

}
class apache::mod::fcgid(
  $options = {},
) {
  ::apache::mod { 'fcgid': }

  # Template uses:
  # - $options
  file { 'fcgid.conf':
    ensure  => file,
    path    => "${::apache::mod_dir}/fcgid.conf",
    content => template('apache/mod/fcgid.conf.erb'),
    require => Exec["mkdir ${::apache::mod_dir}"],
    before  => File[$::apache::mod_dir],
    notify  => Service['httpd'],
  }
}
class apache::mod::headers {
  ::apache::mod { 'headers': }
}
class apache::mod::include {
  ::apache::mod { 'include': }
}
class apache::mod::info (
  $allow_from      = ['127.0.0.1','::1'],
  $apache_version  = $::apache::apache_version,
  $restrict_access = true,
){
  apache::mod { 'info': }
  # Template uses
  # $allow_from
  # $apache_version
  file { 'info.conf':
    ensure  => file,
    path    => "${::apache::mod_dir}/info.conf",
    content => template('apache/mod/info.conf.erb'),
    require => Exec["mkdir ${::apache::mod_dir}"],
    before  => File[$::apache::mod_dir],
    notify  => Service['httpd'],
  }
}
class apache::mod::itk (
  $startservers        = '8',
  $minspareservers     = '5',
  $maxspareservers     = '20',
  $serverlimit         = '256',
  $maxclients          = '256',
  $maxrequestsperchild = '4000',
  $apache_version      = $::apache::apache_version,
) {
  if defined(Class['apache::mod::event']) {
    fail('May not include both apache::mod::itk and apache::mod::event on the same node')
  }
  if defined(Class['apache::mod::peruser']) {
    fail('May not include both apache::mod::itk and apache::mod::peruser on the same node')
  }
  if defined(Class['apache::mod::prefork']) {
    fail('May not include both apache::mod::itk and apache::mod::prefork on the same node')
  }
  if defined(Class['apache::mod::worker']) {
    fail('May not include both apache::mod::itk and apache::mod::worker on the same node')
  }
  File {
    owner => 'root',
    group => $::apache::params::root_group,
    mode  => '0644',
  }

  # Template uses:
  # - $startservers
  # - $minspareservers
  # - $maxspareservers
  # - $serverlimit
  # - $maxclients
  # - $maxrequestsperchild
  file { "${::apache::mod_dir}/itk.conf":
    ensure  => file,
    content => template('apache/mod/itk.conf.erb'),
    require => Exec["mkdir ${::apache::mod_dir}"],
    before  => File[$::apache::mod_dir],
    notify  => Service['httpd'],
  }

  case $::osfamily {
    'debian', 'freebsd': {
      apache::mpm{ 'itk':
        apache_version => $apache_version,
      }
    }
    default: {
      fail("Unsupported osfamily ${::osfamily}")
    }
  }
}
class apache::mod::ldap (
  $apache_version = $::apache::apache_version,
){
  ::apache::mod { 'ldap': }
  # Template uses $apache_version
  file { 'ldap.conf':
    ensure  => file,
    path    => "${::apache::mod_dir}/ldap.conf",
    content => template('apache/mod/ldap.conf.erb'),
    require => Exec["mkdir ${::apache::mod_dir}"],
    before  => File[$::apache::mod_dir],
    notify  => Service['httpd'],
  }
}
class apache::mod::mime (
  $mime_support_package = $::apache::params::mime_support_package,
  $mime_types_config    = $::apache::params::mime_types_config,
) {
  apache::mod { 'mime': }
  # Template uses $mime_types_config
  file { 'mime.conf':
    ensure  => file,
    path    => "${::apache::mod_dir}/mime.conf",
    content => template('apache/mod/mime.conf.erb'),
    require => Exec["mkdir ${::apache::mod_dir}"],
    before  => File[$::apache::mod_dir],
    notify  => Service['httpd'],
  }
  if $mime_support_package {
    package { $mime_support_package:
      ensure => 'installed',
      before => File['mime.conf'],
    }
  }
}
class apache::mod::mime_magic (
  $magic_file = "${::apache::params::conf_dir}/magic"
) {
  apache::mod { 'mime_magic': }
  # Template uses $magic_file
  file { 'mime_magic.conf':
    ensure  => file,
    path    => "${::apache::mod_dir}/mime_magic.conf",
    content => template('apache/mod/mime_magic.conf.erb'),
    require => Exec["mkdir ${::apache::mod_dir}"],
    before  => File[$::apache::mod_dir],
    notify  => Service['httpd'],
  }
}
class apache::mod::negotiation (
  $force_language_priority = 'Prefer Fallback',
  $language_priority = [ 'en', 'ca', 'cs', 'da', 'de', 'el', 'eo', 'es', 'et',
                        'fr', 'he', 'hr', 'it', 'ja', 'ko', 'ltz', 'nl', 'nn',
                        'no', 'pl', 'pt', 'pt-BR', 'ru', 'sv', 'zh-CN',
                        'zh-TW' ],
) {
  if !is_array($force_language_priority) and !is_string($force_language_priority) {
    fail('force_languague_priority must be a string or array of strings')
  }
  if !is_array($language_priority) and !is_string($language_priority) {
    fail('force_languague_priority must be a string or array of strings')
  }

  ::apache::mod { 'negotiation': }
  # Template uses no variables
  file { 'negotiation.conf':
    ensure  => file,
    path    => "${::apache::mod_dir}/negotiation.conf",
    content => template('apache/mod/negotiation.conf.erb'),
    require => Exec["mkdir ${::apache::mod_dir}"],
    before  => File[$::apache::mod_dir],
    notify  => Service['httpd'],
  }
}
class apache::mod::nss (
  $transfer_log = "${::apache::params::logroot}/access.log",
  $error_log    = "${::apache::params::logroot}/error.log",
  $passwd_file  = undef
) {
  include ::apache::mod::mime

  apache::mod { 'nss': }

  $httpd_dir = $::apache::httpd_dir

  # Template uses:
  # $transfer_log
  # $error_log
  # $http_dir
  # passwd_file
  file { 'nss.conf':
    ensure  => file,
    path    => "${::apache::mod_dir}/nss.conf",
    content => template('apache/mod/nss.conf.erb'),
    require => Exec["mkdir ${::apache::mod_dir}"],
    before  => File[$::apache::mod_dir],
    notify  => Service['httpd'],
  }
}
class apache::mod::pagespeed (
  $inherit_vhost_config          = 'on',
  $filter_xhtml                  = false,
  $cache_path                    = '/var/cache/mod_pagespeed/',
  $log_dir                       = '/var/log/pagespeed',
  $memache_servers               = [],
  $rewrite_level                 = 'CoreFilters',
  $disable_filters               = [],
  $enable_filters                = [],
  $forbid_filters                = [],
  $rewrite_deadline_per_flush_ms = 10,
  $additional_domains            = undef,
  $file_cache_size_kb            = 102400,
  $file_cache_clean_interval_ms  = 3600000,
  $lru_cache_per_process         = 1024,
  $lru_cache_byte_limit          = 16384,
  $css_flatten_max_bytes         = 2048,
  $css_inline_max_bytes          = 2048,
  $css_image_inline_max_bytes    = 2048,
  $image_inline_max_bytes        = 2048,
  $js_inline_max_bytes           = 2048,
  $css_outline_min_bytes         = 3000,
  $js_outline_min_bytes          = 3000,
  $inode_limit                   = 500000,
  $image_max_rewrites_at_once    = 8,
  $num_rewrite_threads           = 4,
  $num_expensive_rewrite_threads = 4,
  $collect_statistics            = 'on',
  $statistics_logging            = 'on',
  $allow_view_stats              = [],
  $allow_pagespeed_console       = [],
  $allow_pagespeed_message       = [],
  $message_buffer_size           = 100000,
  $additional_configuration      = {},
  $apache_version                = $::apache::apache_version,
){

  $_lib = $::apache::apache_version ? {
    '2.4'   => 'mod_pagespeed_ap24.so',
    default => undef
  }

  apache::mod { 'pagespeed':
    lib => $_lib,
  }

  file { 'pagespeed.conf':
    ensure  => file,
    path    => "${::apache::mod_dir}/pagespeed.conf",
    content => template('apache/mod/pagespeed.conf.erb'),
    require => Exec["mkdir ${::apache::mod_dir}"],
    before  => File[$::apache::mod_dir],
    notify  => Service['httpd'],
  }
}
class apache::mod::passenger (
  $passenger_conf_file            = $::apache::params::passenger_conf_file,
  $passenger_conf_package_file    = $::apache::params::passenger_conf_package_file,
  $passenger_high_performance     = undef,
  $passenger_pool_idle_time       = undef,
  $passenger_max_requests         = undef,
  $passenger_stat_throttle_rate   = undef,
  $rack_autodetect                = undef,
  $rails_autodetect               = undef,
  $passenger_root                 = $::apache::params::passenger_root,
  $passenger_ruby                 = $::apache::params::passenger_ruby,
  $passenger_default_ruby         = $::apache::params::passenger_default_ruby,
  $passenger_max_pool_size        = undef,
  $passenger_use_global_queue     = undef,
  $mod_package                    = undef,
  $mod_package_ensure             = undef,
  $mod_lib                        = undef,
  $mod_lib_path                   = undef,
  $mod_id                         = undef,
  $mod_path                       = undef,
) {
  # Managed by the package, but declare it to avoid purging
  if $passenger_conf_package_file {
    file { 'passenger_package.conf':
      path => "${::apache::mod_dir}/${passenger_conf_package_file}",
    }
  } else {
    # Remove passenger_extra.conf left over from before Passenger support was
    # reworked for Debian. This is a temporary fix for users running this
    # module from master after release 1.0.1 It will be removed in two
    # releases from now.
    $passenger_package_conf_ensure = $::osfamily ? {
      'Debian' => 'absent',
      default  => undef,
    }

    file { 'passenger_package.conf':
      ensure => $passenger_package_conf_ensure,
      path   => "${::apache::mod_dir}/passenger_extra.conf",
    }
  }

  $_package = $mod_package
  $_package_ensure = $mod_package_ensure
  $_lib = $mod_lib
  if $::osfamily == 'FreeBSD' {
    if $mod_lib_path {
      $_lib_path = $mod_lib_path
    } else {
      $_lib_path = "${passenger_root}/buildout/apache2"
    }
  } else {
    $_lib_path = $mod_lib_path
  }

  $_id = $mod_id
  $_path = $mod_path
  ::apache::mod { 'passenger':
    package        => $_package,
    package_ensure => $_package_ensure,
    lib            => $_lib,
    lib_path       => $_lib_path,
    id             => $_id,
    path           => $_path,
  }

  # Template uses:
  # - $passenger_root
  # - $passenger_ruby
  # - $passenger_default_ruby
  # - $passenger_max_pool_size
  # - $passenger_high_performance
  # - $passenger_max_requests
  # - $passenger_stat_throttle_rate
  # - $passenger_use_global_queue
  # - $rack_autodetect
  # - $rails_autodetect
  file { 'passenger.conf':
    ensure  => file,
    path    => "${::apache::mod_dir}/${passenger_conf_file}",
    content => template('apache/mod/passenger.conf.erb'),
    require => Exec["mkdir ${::apache::mod_dir}"],
    before  => File[$::apache::mod_dir],
    notify  => Service['httpd'],
  }
}
class apache::mod::perl {
  ::apache::mod { 'perl': }
}
class apache::mod::peruser (
  $minspareprocessors = '2',
  $minprocessors = '2',
  $maxprocessors = '10',
  $maxclients = '150',
  $maxrequestsperchild = '1000',
  $idletimeout = '120',
  $expiretimeout = '120',
  $keepalive = 'Off',
) {
  if defined(Class['apache::mod::event']) {
    fail('May not include both apache::mod::peruser and apache::mod::event on the same node')
  }
  if defined(Class['apache::mod::itk']) {
    fail('May not include both apache::mod::peruser and apache::mod::itk on the same node')
  }
  if defined(Class['apache::mod::prefork']) {
    fail('May not include both apache::mod::peruser and apache::mod::prefork on the same node')
  }
  if defined(Class['apache::mod::worker']) {
    fail('May not include both apache::mod::peruser and apache::mod::worker on the same node')
  }
  File {
    owner => 'root',
    group => $::apache::params::root_group,
    mode  => '0644',
  }

  $mod_dir = $::apache::mod_dir

  # Template uses:
  # - $minspareprocessors
  # - $minprocessors
  # - $maxprocessors
  # - $maxclients
  # - $maxrequestsperchild
  # - $idletimeout
  # - $expiretimeout
  # - $keepalive
  # - $mod_dir
  file { "${::apache::mod_dir}/peruser.conf":
    ensure  => file,
    content => template('apache/mod/peruser.conf.erb'),
    require => Exec["mkdir ${::apache::mod_dir}"],
    before  => File[$::apache::mod_dir],
    notify  => Service['httpd'],
  }
  file { "${::apache::mod_dir}/peruser":
    ensure  => directory,
    require => File[$::apache::mod_dir],
  }
  file { "${::apache::mod_dir}/peruser/multiplexers":
    ensure  => directory,
    require => File["${::apache::mod_dir}/peruser"],
  }
  file { "${::apache::mod_dir}/peruser/processors":
    ensure  => directory,
    require => File["${::apache::mod_dir}/peruser"],
  }

  ::apache::peruser::multiplexer { '01-default': }

  case $::osfamily {
    'freebsd' : {
      class { '::apache::package':
        mpm_module => 'peruser'
      }
    }
    default: {
      fail("Unsupported osfamily ${::osfamily}")
    }
  }
}
class apache::mod::php (
  $package_name   = undef,
  $package_ensure = 'present',
  $path           = undef,
  $extensions     = ['.php'],
  $content        = undef,
  $template       = 'apache/mod/php5.conf.erb',
  $source         = undef,
) {
  if ! defined(Class['apache::mod::prefork']) {
    fail('apache::mod::php requires apache::mod::prefork; please enable mpm_module => \'prefork\' on Class[\'apache\']')
  }
  validate_array($extensions)

  if $source and ($content or $template != 'apache/mod/php5.conf.erb') {
    warning('source and content or template parameters are provided. source parameter will be used')
  } elsif $content and $template != 'apache/mod/php5.conf.erb' {
    warning('content and template parameters are provided. content parameter will be used')
  }

  $manage_content = $source ? {
    undef   => $content ? {
      undef   => template($template),
      default => $content,
    },
    default => undef,
  }

  ::apache::mod { 'php5':
    package        => $package_name,
    package_ensure => $package_ensure,
    path           => $path,
  }

  include ::apache::mod::mime
  include ::apache::mod::dir
  Class['::apache::mod::mime'] -> Class['::apache::mod::dir'] -> Class['::apache::mod::php']

  # Template uses $extensions
  file { 'php5.conf':
    ensure  => file,
    path    => "${::apache::mod_dir}/php5.conf",
    owner   => 'root',
    group   => 'root',
    mode    => '0644',
    content => $manage_content,
    source  => $source,
    require => [
      Class['::apache::mod::prefork'],
      Exec["mkdir ${::apache::mod_dir}"],
    ],
    before  => File[$::apache::mod_dir],
    notify  => Service['httpd'],
  }
}
class apache::mod::prefork (
  $startservers        = '8',
  $minspareservers     = '5',
  $maxspareservers     = '20',
  $serverlimit         = '256',
  $maxclients          = '256',
  $maxrequestsperchild = '4000',
  $apache_version      = $::apache::apache_version,
) {
  if defined(Class['apache::mod::event']) {
    fail('May not include both apache::mod::prefork and apache::mod::event on the same node')
  }
  if defined(Class['apache::mod::itk']) {
    fail('May not include both apache::mod::prefork and apache::mod::itk on the same node')
  }
  if defined(Class['apache::mod::peruser']) {
    fail('May not include both apache::mod::prefork and apache::mod::peruser on the same node')
  }
  if defined(Class['apache::mod::worker']) {
    fail('May not include both apache::mod::prefork and apache::mod::worker on the same node')
  }
  File {
    owner => 'root',
    group => $::apache::params::root_group,
    mode  => '0644',
  }

  # Template uses:
  # - $startservers
  # - $minspareservers
  # - $maxspareservers
  # - $serverlimit
  # - $maxclients
  # - $maxrequestsperchild
  file { "${::apache::mod_dir}/prefork.conf":
    ensure  => file,
    content => template('apache/mod/prefork.conf.erb'),
    require => Exec["mkdir ${::apache::mod_dir}"],
    before  => File[$::apache::mod_dir],
    notify  => Service['httpd'],
  }

  case $::osfamily {
    'redhat': {
      if versioncmp($apache_version, '2.4') >= 0 {
        ::apache::mpm{ 'prefork':
          apache_version => $apache_version,
        }
      }
      else {
        file_line { '/etc/sysconfig/httpd prefork enable':
          ensure  => present,
          path    => '/etc/sysconfig/httpd',
          line    => '#HTTPD=/usr/sbin/httpd.worker',
          match   => '#?HTTPD=/usr/sbin/httpd.worker',
          require => Package['httpd'],
          notify  => Service['httpd'],
        }
      }
    }
    'debian', 'freebsd' : {
      ::apache::mpm{ 'prefork':
        apache_version => $apache_version,
      }
    }
    default: {
      fail("Unsupported osfamily ${::osfamily}")
    }
  }
}
class apache::mod::proxy (
  $proxy_requests = 'Off',
  $allow_from = undef,
  $apache_version = $::apache::apache_version,
) {
  ::apache::mod { 'proxy': }
  # Template uses $proxy_requests, $apache_version
  file { 'proxy.conf':
    ensure  => file,
    path    => "${::apache::mod_dir}/proxy.conf",
    content => template('apache/mod/proxy.conf.erb'),
    require => Exec["mkdir ${::apache::mod_dir}"],
    before  => File[$::apache::mod_dir],
    notify  => Service['httpd'],
  }
}
class apache::mod::proxy_ajp {
  Class['::apache::mod::proxy'] -> Class['::apache::mod::proxy_ajp']
  ::apache::mod { 'proxy_ajp': }
}
class apache::mod::proxy_balancer {

  include ::apache::mod::proxy
  include ::apache::mod::proxy_http

  Class['::apache::mod::proxy'] -> Class['::apache::mod::proxy_balancer']
  Class['::apache::mod::proxy_http'] -> Class['::apache::mod::proxy_balancer']
  ::apache::mod { 'proxy_balancer': }

}
class apache::mod::proxy_html {
  Class['::apache::mod::proxy'] -> Class['::apache::mod::proxy_html']
  Class['::apache::mod::proxy_http'] -> Class['::apache::mod::proxy_html']

  # Add libxml2
  case $::osfamily {
    /RedHat|FreeBSD/: {
      ::apache::mod { 'xml2enc': }
      $loadfiles = undef
    }
    'Debian': {
      $gnu_path = $::hardwaremodel ? {
        'i686'  => 'i386',
        default => $::hardwaremodel,
      }
      $loadfiles = $::apache::params::distrelease ? {
        '6'     => ['/usr/lib/libxml2.so.2'],
        '10'    => ['/usr/lib/libxml2.so.2'],
        default => ["/usr/lib/${gnu_path}-linux-gnu/libxml2.so.2"],
      }
    }
  }

  ::apache::mod { 'proxy_html':
    loadfiles => $loadfiles,
  }

  # Template uses $icons_path
  file { 'proxy_html.conf':
    ensure  => file,
    path    => "${::apache::mod_dir}/proxy_html.conf",
    content => template('apache/mod/proxy_html.conf.erb'),
    require => Exec["mkdir ${::apache::mod_dir}"],
    before  => File[$::apache::mod_dir],
    notify  => Service['httpd'],
  }
}
class apache::mod::proxy_http {
  Class['::apache::mod::proxy'] -> Class['::apache::mod::proxy_http']
  ::apache::mod { 'proxy_http': }
}
class apache::mod::python {
  ::apache::mod { 'python': }
}


class apache::mod::reqtimeout {
  ::apache::mod { 'reqtimeout': }
  # Template uses no variables
  file { 'reqtimeout.conf':
    ensure  => file,
    path    => "${::apache::mod_dir}/reqtimeout.conf",
    content => template('apache/mod/reqtimeout.conf.erb'),
    require => Exec["mkdir ${::apache::mod_dir}"],
    before  => File[$::apache::mod_dir],
    notify  => Service['httpd'],
  }
}
class apache::mod::rewrite {
  include ::apache::params
  ::apache::mod { 'rewrite': }
}
class apache::mod::rpaf (
  $sethostname = true,
  $proxy_ips   = [ '127.0.0.1' ],
  $header      = 'X-Forwarded-For'
) {
  ::apache::mod { 'rpaf': }

  # Template uses:
  # - $sethostname
  # - $proxy_ips
  # - $header
  file { 'rpaf.conf':
    ensure  => file,
    path    => "${::apache::mod_dir}/rpaf.conf",
    content => template('apache/mod/rpaf.conf.erb'),
    require => Exec["mkdir ${::apache::mod_dir}"],
    before  => File[$::apache::mod_dir],
    notify  => Service['httpd'],
  }
}
class apache::mod::setenvif {
  ::apache::mod { 'setenvif': }
  # Template uses no variables
  file { 'setenvif.conf':
    ensure  => file,
    path    => "${::apache::mod_dir}/setenvif.conf",
    content => template('apache/mod/setenvif.conf.erb'),
    require => Exec["mkdir ${::apache::mod_dir}"],
    before  => File[$::apache::mod_dir],
    notify  => Service['httpd'],
  }
}
class apache::mod::speling {
  ::apache::mod { 'speling': }
}
class apache::mod::ssl (
  $ssl_compression = false,
  $ssl_options     = [ 'StdEnvVars' ],
  $ssl_cipher      = 'HIGH:MEDIUM:!aNULL:!MD5',
  $apache_version  = $::apache::apache_version,
) {
  $session_cache = $::osfamily ? {
    'debian'  => '${APACHE_RUN_DIR}/ssl_scache(512000)',
    'redhat'  => '/var/cache/mod_ssl/scache(512000)',
    'freebsd' => '/var/run/ssl_scache(512000)',
  }

  case $::osfamily {
    'debian': {
      if versioncmp($apache_version, '2.4') >= 0 {
        $ssl_mutex = 'default'
      } elsif $::operatingsystem == 'Ubuntu' and $::operatingsystemrelease == '10.04' {
        $ssl_mutex = 'file:/var/run/apache2/ssl_mutex'
      } else {
        $ssl_mutex = 'file:${APACHE_RUN_DIR}/ssl_mutex'
      }
    }
    'redhat': {
      $ssl_mutex = 'default'
    }
    'freebsd': {
      $ssl_mutex = 'default'
    }
    default: {
      fail("Unsupported osfamily ${::osfamily}")
    }
  }

  ::apache::mod { 'ssl': }

  if versioncmp($apache_version, '2.4') >= 0 {
    ::apache::mod { 'socache_shmcb': }
  }

  # Template uses
  #
  # $ssl_compression
  # $ssl_options
  # $session_cache,
  # $ssl_mutex
  # $apache_version
  #
  file { 'ssl.conf':
    ensure  => file,
    path    => "${::apache::mod_dir}/ssl.conf",
    content => template('apache/mod/ssl.conf.erb'),
    require => Exec["mkdir ${::apache::mod_dir}"],
    before  => File[$::apache::mod_dir],
    notify  => Service['httpd'],
  }
}
# Class: apache::mod::status
#
# This class enables and configures Apache mod_status
# See: http://httpd.apache.org/docs/current/mod/mod_status.html
#
# Parameters:
# - $allow_from is an array of hosts, ip addresses, partial network numbers
#   or networks in CIDR notation specifying what hosts can view the special
#   /server-status URL.  Defaults to ['127.0.0.1', '::1'].
# - $extended_status track and display extended status information. Valid
#   values are 'On' or 'Off'.  Defaults to 'On'.
#
# Actions:
# - Enable and configure Apache mod_status
#
# Requires:
# - The apache class
#
# Sample Usage:
#
#  # Simple usage allowing access from localhost and a private subnet
#  class { 'apache::mod::status':
#    $allow_from => ['127.0.0.1', '10.10.10.10/24'],
#  }
#
class apache::mod::status (
  $allow_from      = ['127.0.0.1','::1'],
  $extended_status = 'On',
  $apache_version = $::apache::apache_version,
){
  validate_array($allow_from)
  validate_re(downcase($extended_status), '^(on|off)$', "${extended_status} is not supported for extended_status.  Allowed values are 'On' and 'Off'.")
  ::apache::mod { 'status': }
  # Template uses $allow_from, $extended_status, $apache_version
  file { 'status.conf':
    ensure  => file,
    path    => "${::apache::mod_dir}/status.conf",
    content => template('apache/mod/status.conf.erb'),
    require => Exec["mkdir ${::apache::mod_dir}"],
    before  => File[$::apache::mod_dir],
    notify  => Service['httpd'],
  }
}
class apache::mod::suexec {
  ::apache::mod { 'suexec': }
}
class apache::mod::suphp (
){
  ::apache::mod { 'suphp': }

  file {'suphp.conf':
    ensure  => file,
    path    => "${::apache::mod_dir}/suphp.conf",
    content => template('apache/mod/suphp.conf.erb'),
    require => Exec["mkdir ${::apache::mod_dir}"],
    before  => File[$::apache::mod_dir],
    notify  => Service['httpd']
  }
}

class apache::mod::userdir (
  $home = '/home',
  $dir = 'public_html',
  $disable_root = true,
  $apache_version = $::apache::apache_version,
) {
  ::apache::mod { 'userdir': }

  # Template uses $home, $dir, $disable_root, $apache_version
  file { 'userdir.conf':
    ensure  => file,
    path    => "${::apache::mod_dir}/userdir.conf",
    content => template('apache/mod/userdir.conf.erb'),
    require => Exec["mkdir ${::apache::mod_dir}"],
    before  => File[$::apache::mod_dir],
    notify  => Service['httpd'],
  }
}
class apache::mod::vhost_alias {
  ::apache::mod { 'vhost_alias': }
}
class apache::mod::worker (
  $startservers        = '2',
  $maxclients          = '150',
  $minsparethreads     = '25',
  $maxsparethreads     = '75',
  $threadsperchild     = '25',
  $maxrequestsperchild = '0',
  $serverlimit         = '25',
  $threadlimit         = '64',
  $apache_version      = $::apache::apache_version,
) {
  if defined(Class['apache::mod::event']) {
    fail('May not include both apache::mod::worker and apache::mod::event on the same node')
  }
  if defined(Class['apache::mod::itk']) {
    fail('May not include both apache::mod::worker and apache::mod::itk on the same node')
  }
  if defined(Class['apache::mod::peruser']) {
    fail('May not include both apache::mod::worker and apache::mod::peruser on the same node')
  }
  if defined(Class['apache::mod::prefork']) {
    fail('May not include both apache::mod::worker and apache::mod::prefork on the same node')
  }
  File {
    owner => 'root',
    group => $::apache::params::root_group,
    mode  => '0644',
  }

  # Template uses:
  # - $startservers
  # - $maxclients
  # - $minsparethreads
  # - $maxsparethreads
  # - $threadsperchild
  # - $maxrequestsperchild
  # - $serverlimit
  # - $threadLimit
  file { "${::apache::mod_dir}/worker.conf":
    ensure  => file,
    content => template('apache/mod/worker.conf.erb'),
    require => Exec["mkdir ${::apache::mod_dir}"],
    before  => File[$::apache::mod_dir],
    notify  => Service['httpd'],
  }

  case $::osfamily {
    'redhat': {
      if versioncmp($apache_version, '2.4') >= 0 {
        ::apache::mpm{ 'worker':
          apache_version => $apache_version,
        }
      }
      else {
        file_line { '/etc/sysconfig/httpd worker enable':
          ensure  => present,
          path    => '/etc/sysconfig/httpd',
          line    => 'HTTPD=/usr/sbin/httpd.worker',
          match   => '#?HTTPD=/usr/sbin/httpd.worker',
          require => Package['httpd'],
          notify  => Service['httpd'],
        }
      }
    }
    'debian', 'freebsd': {
      ::apache::mpm{ 'worker':
        apache_version => $apache_version,
      }
    }
    default: {
      fail("Unsupported osfamily ${::osfamily}")
    }
  }
}
class apache::mod::wsgi (
  $wsgi_socket_prefix = undef,
  $wsgi_python_path   = undef,
  $wsgi_python_home   = undef,
){
  ::apache::mod { 'wsgi': }

  # Template uses:
  # - $wsgi_socket_prefix
  # - $wsgi_python_path
  # - $wsgi_python_home
  file {'wsgi.conf':
    ensure  => file,
    path    => "${::apache::mod_dir}/wsgi.conf",
    content => template('apache/mod/wsgi.conf.erb'),
    require => Exec["mkdir ${::apache::mod_dir}"],
    before  => File[$::apache::mod_dir],
    notify  => Service['httpd']
  }
}

class apache::mod::xsendfile {
  include ::apache::params
  ::apache::mod { 'xsendfile': }
}
define apache::mpm (
  $lib_path       = $::apache::params::lib_path,
  $apache_version = $::apache::apache_version,
) {
  if ! defined(Class['apache']) {
    fail('You must include the apache base class before using any apache defined resources')
  }

  $mpm     = $name
  $mod_dir = $::apache::mod_dir

  $_lib  = "mod_mpm_${mpm}.so"
  $_path = "${lib_path}/${_lib}"
  $_id   = "mpm_${mpm}_module"

  if versioncmp($apache_version, '2.4') >= 0 {
    file { "${mod_dir}/${mpm}.load":
      ensure  => file,
      path    => "${mod_dir}/${mpm}.load",
      content => "LoadModule ${_id} ${_path}\n",
      require => [
        Package['httpd'],
        Exec["mkdir ${mod_dir}"],
      ],
      before  => File[$mod_dir],
      notify  => Service['httpd'],
    }
  }

  case $::osfamily {
    'debian': {
      file { "${::apache::mod_enable_dir}/${mpm}.conf":
        ensure  => link,
        target  => "${::apache::mod_dir}/${mpm}.conf",
        require => Exec["mkdir ${::apache::mod_enable_dir}"],
        before  => File[$::apache::mod_enable_dir],
        notify  => Service['httpd'],
      }

      if versioncmp($apache_version, '2.4') >= 0 {
        file { "${::apache::mod_enable_dir}/${mpm}.load":
          ensure  => link,
          target  => "${::apache::mod_dir}/${mpm}.load",
          require => Exec["mkdir ${::apache::mod_enable_dir}"],
          before  => File[$::apache::mod_enable_dir],
          notify  => Service['httpd'],
        }
      }

      if versioncmp($apache_version, '2.4') < 0 {
        package { "apache2-mpm-${mpm}":
          ensure => present,
        }
      }
    }
    'freebsd': {
      class { '::apache::package':
        mpm_module => $mpm
      }
    }
    'redhat': {
      # so we don't fail
    }
    default: {
      fail("Unsupported osfamily ${::osfamily}")
    }
  }
}
define apache::namevirtualhost {
  $addr_port = $name

  # Template uses: $addr_port
  concat::fragment { "NameVirtualHost ${addr_port}":
    ensure  => present,
    target  => $::apache::ports_file,
    content => template('apache/namevirtualhost.erb'),
  }
}
class apache::package (
  $ensure     = 'present',
  $mpm_module = $::apache::params::mpm_module,
) inherits ::apache::params {
  case $::osfamily {
    'freebsd' : {
      $all_mpms = [
        'www/apache22',
        'www/apache22-worker-mpm',
        'www/apache22-event-mpm',
        'www/apache22-itk-mpm',
        'www/apache22-peruser-mpm',
      ]
      if $mpm_module {
        $apache_package = $mpm_module ? {
          'prefork' => 'www/apache22',
          default   => "www/apache22-${mpm_module}-mpm"
        }
      } else {
        $apache_package = 'www/apache22'
      }
      $other_mpms = delete($all_mpms, $apache_package)
      # Configure ports to have apache module packages dependent on correct
      # version of apache package (apache22, apache22-worker-mpm, ...)
      file_line { 'APACHE_PORT in /etc/make.conf':
        ensure => $ensure,
        path   => '/etc/make.conf',
        line   => "APACHE_PORT=${apache_package}",
        match  => '^\s*#?\s*APACHE_PORT\s*=\s*',
        before => Package['httpd'],
      }
      # remove other packages
      ensure_resource('package', $other_mpms, {
        ensure  => absent,
        before  => Package['httpd'],
        require => File_line['APACHE_PORT in /etc/make.conf'],
      })
    }
    default: {
      $apache_package = $::apache::params::apache_name
    }
  }
  package { 'httpd':
    ensure => $ensure,
    name   => $apache_package,
    notify => Class['Apache::Service'],
  }
}
# Class: apache::params
#
# This class manages Apache parameters
#
# Parameters:
# - The $user that Apache runs as
# - The $group that Apache runs as
# - The $apache_name is the name of the package and service on the relevant
#   distribution
# - The $php_package is the name of the package that provided PHP
# - The $ssl_package is the name of the Apache SSL package
# - The $apache_dev is the name of the Apache development libraries package
# - The $conf_contents is the contents of the Apache configuration file
#
# Actions:
#
# Requires:
#
# Sample Usage:
#
class apache::params inherits ::apache::version {
  if($::fqdn) {
    $servername = $::fqdn
  } else {
    $servername = $::hostname
  }

  # The default error log level
  $log_level = 'warn'

  if $::osfamily == 'RedHat' or $::operatingsystem == 'amazon' {
    $user                 = 'apache'
    $group                = 'apache'
    $root_group           = 'root'
    $apache_name          = 'httpd'
    $service_name         = 'httpd'
    $httpd_dir            = '/etc/httpd'
    $server_root          = '/etc/httpd'
    $conf_dir             = "${httpd_dir}/conf"
    $confd_dir            = "${httpd_dir}/conf.d"
    $mod_dir              = "${httpd_dir}/conf.d"
    $mod_enable_dir       = undef
    $vhost_dir            = "${httpd_dir}/conf.d"
    $vhost_enable_dir     = undef
    $conf_file            = 'httpd.conf'
    $ports_file           = "${conf_dir}/ports.conf"
    $logroot              = '/var/log/httpd'
    $lib_path             = 'modules'
    $mpm_module           = 'prefork'
    $dev_packages         = 'httpd-devel'
    $default_ssl_cert     = '/etc/pki/tls/certs/localhost.crt'
    $default_ssl_key      = '/etc/pki/tls/private/localhost.key'
    $ssl_certs_dir        = '/etc/pki/tls/certs'
    $passenger_conf_file  = 'passenger_extra.conf'
    $passenger_conf_package_file = 'passenger.conf'
    $passenger_root       = undef
    $passenger_ruby       = undef
    $passenger_default_ruby = undef
    $suphp_addhandler     = 'php5-script'
    $suphp_engine         = 'off'
    $suphp_configpath     = undef
    $mod_packages         = {
      'auth_kerb'   => 'mod_auth_kerb',
      'authnz_ldap' => 'mod_authz_ldap',
      'fastcgi'     => 'mod_fastcgi',
      'fcgid'       => 'mod_fcgid',
      'pagespeed'   => 'mod-pagespeed-stable',
      'passenger'   => 'mod_passenger',
      'perl'        => 'mod_perl',
      'php5'        => $::apache::version::distrelease ? {
        '5'     => 'php53',
        default => 'php',
      },
      'proxy_html'  => 'mod_proxy_html',
      'python'      => 'mod_python',
      'shibboleth'  => 'shibboleth',
      'ssl'         => 'mod_ssl',
      'wsgi'        => 'mod_wsgi',
      'dav_svn'     => 'mod_dav_svn',
      'suphp'       => 'mod_suphp',
      'xsendfile'   => 'mod_xsendfile',
      'nss'         => 'mod_nss',
    }
    $mod_libs             = {
      'php5' => 'libphp5.so',
      'nss'  => 'libmodnss.so',
    }
    $conf_template        = 'apache/httpd.conf.erb'
    $keepalive            = 'Off'
    $keepalive_timeout    = 15
    $max_keepalive_requests = 100
    $fastcgi_lib_path     = undef
    $mime_support_package = 'mailcap'
    $mime_types_config    = '/etc/mime.types'
  } elsif $::osfamily == 'Debian' {
    $user                = 'www-data'
    $group               = 'www-data'
    $root_group          = 'root'
    $apache_name         = 'apache2'
    $service_name        = 'apache2'
    $httpd_dir           = '/etc/apache2'
    $server_root         = '/etc/apache2'
    $conf_dir            = $httpd_dir
    $confd_dir           = "${httpd_dir}/conf.d"
    $mod_dir             = "${httpd_dir}/mods-available"
    $mod_enable_dir      = "${httpd_dir}/mods-enabled"
    $vhost_dir           = "${httpd_dir}/sites-available"
    $vhost_enable_dir    = "${httpd_dir}/sites-enabled"
    $conf_file           = 'apache2.conf'
    $ports_file          = "${conf_dir}/ports.conf"
    $logroot             = '/var/log/apache2'
    $lib_path            = '/usr/lib/apache2/modules'
    $mpm_module          = 'worker'
    $dev_packages        = ['libaprutil1-dev', 'libapr1-dev', 'apache2-prefork-dev']
    $default_ssl_cert    = '/etc/ssl/certs/ssl-cert-snakeoil.pem'
    $default_ssl_key     = '/etc/ssl/private/ssl-cert-snakeoil.key'
    $ssl_certs_dir       = '/etc/ssl/certs'
    $suphp_addhandler    = 'x-httpd-php'
    $suphp_engine        = 'off'
    $suphp_configpath    = '/etc/php5/apache2'
    $mod_packages        = {
      'auth_kerb'   => 'libapache2-mod-auth-kerb',
      'dav_svn'     => 'libapache2-svn',
      'fastcgi'     => 'libapache2-mod-fastcgi',
      'fcgid'       => 'libapache2-mod-fcgid',
      'nss'         => 'libapache2-mod-nss',
      'pagespeed'   => 'mod-pagespeed-stable',
      'passenger'   => 'libapache2-mod-passenger',
      'perl'        => 'libapache2-mod-perl2',
      'php5'        => 'libapache2-mod-php5',
      'proxy_html'  => 'libapache2-mod-proxy-html',
      'python'      => 'libapache2-mod-python',
      'rpaf'        => 'libapache2-mod-rpaf',
      'suphp'       => 'libapache2-mod-suphp',
      'wsgi'        => 'libapache2-mod-wsgi',
      'xsendfile'   => 'libapache2-mod-xsendfile',
    }
    $mod_libs             = {
      'php5' => 'libphp5.so',
    }
    $conf_template          = 'apache/httpd.conf.erb'
    $keepalive              = 'Off'
    $keepalive_timeout      = 15
    $max_keepalive_requests = 100
    $fastcgi_lib_path       = '/var/lib/apache2/fastcgi'
    $mime_support_package = 'mime-support'
    $mime_types_config    = '/etc/mime.types'

    #
    # Passenger-specific settings
    #

    $passenger_conf_file         = 'passenger.conf'
    $passenger_conf_package_file = undef

    case $::operatingsystem {
      'Ubuntu': {
        case $::lsbdistrelease {
          '12.04': {
            $passenger_root         = '/usr'
            $passenger_ruby         = '/usr/bin/ruby'
            $passenger_default_ruby = undef
          }
          '14.04': {
            $passenger_root         = '/usr/lib/ruby/vendor_ruby/phusion_passenger/locations.ini'
            $passenger_ruby         = undef
            $passenger_default_ruby = '/usr/bin/ruby'
          }
          default: {
            # The following settings may or may not work on Ubuntu releases not
            # supported by this module.
            $passenger_root         = '/usr'
            $passenger_ruby         = '/usr/bin/ruby'
            $passenger_default_ruby = undef
          }
        }
      }
      'Debian': {
        case $::lsbdistcodename {
          'wheezy': {
            $passenger_root         = '/usr'
            $passenger_ruby         = '/usr/bin/ruby'
            $passenger_default_ruby = undef
          }
          default: {
            # The following settings may or may not work on Debian releases not
            # supported by this module.
            $passenger_root         = '/usr'
            $passenger_ruby         = '/usr/bin/ruby'
            $passenger_default_ruby = undef
          }
        }
      }
    }
  } elsif $::osfamily == 'FreeBSD' {
    $user             = 'www'
    $group            = 'www'
    $root_group       = 'wheel'
    $apache_name      = 'apache22'
    $service_name     = 'apache22'
    $httpd_dir        = '/usr/local/etc/apache22'
    $server_root      = '/usr/local'
    $conf_dir         = $httpd_dir
    $confd_dir        = "${httpd_dir}/Includes"
    $mod_dir          = "${httpd_dir}/Modules"
    $mod_enable_dir   = undef
    $vhost_dir        = "${httpd_dir}/Vhosts"
    $vhost_enable_dir = undef
    $conf_file        = 'httpd.conf'
    $ports_file       = "${conf_dir}/ports.conf"
    $logroot          = '/var/log/apache22'
    $lib_path         = '/usr/local/libexec/apache22'
    $mpm_module       = 'prefork'
    $dev_packages     = undef
    $default_ssl_cert = '/usr/local/etc/apache22/server.crt'
    $default_ssl_key  = '/usr/local/etc/apache22/server.key'
    $ssl_certs_dir    = '/usr/local/etc/apache22'
    $passenger_conf_file = 'passenger.conf'
    $passenger_conf_package_file = undef
    $passenger_root   = '/usr/local/lib/ruby/gems/1.9/gems/passenger-4.0.10'
    $passenger_ruby   = '/usr/bin/ruby'
    $passenger_default_ruby = undef
    $suphp_addhandler = 'php5-script'
    $suphp_engine     = 'off'
    $suphp_configpath = undef
    $mod_packages     = {
      # NOTE: I list here only modules that are not included in www/apache22
      # NOTE: 'passenger' needs to enable APACHE_SUPPORT in make config
      # NOTE: 'php' needs to enable APACHE option in make config
      # NOTE: 'dav_svn' needs to enable MOD_DAV_SVN make config
      # NOTE: not sure where the shibboleth should come from
      # NOTE: don't know where the shibboleth module should come from
      'auth_kerb'  => 'www/mod_auth_kerb2',
      'fcgid'      => 'www/mod_fcgid',
      'passenger'  => 'www/rubygem-passenger',
      'perl'       => 'www/mod_perl2',
      'php5'       => 'lang/php5',
      'proxy_html' => 'www/mod_proxy_html',
      'python'     => 'www/mod_python3',
      'wsgi'       => 'www/mod_wsgi',
      'dav_svn'    => 'devel/subversion',
      'xsendfile'  => 'www/mod_xsendfile',
      'rpaf'       => 'www/mod_rpaf2'
    }
    $mod_libs         = {
      'php5' => 'libphp5.so',
    }
    $conf_template        = 'apache/httpd.conf.erb'
    $keepalive            = 'Off'
    $keepalive_timeout    = 15
    $max_keepalive_requests = 100
    $fastcgi_lib_path     = undef # TODO: revisit
    $mime_support_package = 'misc/mime-support'
    $mime_types_config    = '/usr/local/etc/mime.types'
  } else {
    fail("Class['apache::params']: Unsupported osfamily: ${::osfamily}")
  }
}
define apache::peruser::multiplexer (
  $user = $::apache::user,
  $group = $::apache::group,
  $file = undef,
) {
  if ! $file {
    $filename = "${name}.conf"
  } else {
    $filename = $file
  }
  file { "${::apache::mod_dir}/peruser/multiplexers/${filename}":
    ensure  => file,
    content => "Multiplexer ${user} ${group}\n",
    require => File["${::apache::mod_dir}/peruser/multiplexers"],
    notify  => Service['httpd'],
  }
}
define apache::peruser::processor (
  $user,
  $group,
  $file = undef,
) {
  if ! $file {
    $filename = "${name}.conf"
  } else {
    $filename = $file
  }
  file { "${::apache::mod_dir}/peruser/processors/${filename}":
    ensure  => file,
    content => "Processor ${user} ${group}\n",
    require => File["${::apache::mod_dir}/peruser/processors"],
    notify  => Service['httpd'],
  }
}
# Class: apache::php
#
# This class installs PHP for Apache
#
# Parameters:
# - $php_package
#
# Actions:
#   - Install Apache PHP package
#
# Requires:
#
# Sample Usage:
#
class apache::php {
  warning('apache::php is deprecated; please use apache::mod::php')
  include ::apache::mod::php
}
# Class: apache::proxy
#
# This class enabled the proxy module for Apache
#
# Actions:
#   - Enables Apache Proxy module
#
# Requires:
#
# Sample Usage:
#
class apache::proxy {
  warning('apache::proxy is deprecated; please use apache::mod::proxy')
  include ::apache::mod::proxy
}
# Class: apache::python
#
# This class installs Python for Apache
#
# Parameters:
# - $php_package
#
# Actions:
#   - Install Apache Python package
#
# Requires:
#
# Sample Usage:
#
class apache::python {
  warning('apache::python is deprecated; please use apache::mod::python')
  include ::apache::mod::python
}
# Class: apache::service
#
# Manages the Apache daemon
#
# Parameters:
#
# Actions:
#   - Manage Apache service
#
# Requires:
#
# Sample Usage:
#
#    sometype { 'foo':
#      notify => Class['apache::service'],
#    }
#
#
class apache::service (
  $service_name   = $::apache::params::service_name,
  $service_enable = true,
  $service_ensure = 'running',
) {
  # The base class must be included first because parameter defaults depend on it
  if ! defined(Class['apache::params']) {
    fail('You must include the apache::params class before using any apache defined resources')
  }
  validate_bool($service_enable)

  case $service_ensure {
    true, false, 'running', 'stopped': {
      $_service_ensure = $service_ensure
    }
    default: {
      $_service_ensure = undef
    }
  }

  service { 'httpd':
    ensure => $_service_ensure,
    name   => $service_name,
    enable => $service_enable,
  }
}
# Class: apache::ssl
#
# This class installs Apache SSL capabilities
#
# Parameters:
# - The $ssl_package name from the apache::params class
#
# Actions:
#   - Install Apache SSL capabilities
#
# Requires:
#
# Sample Usage:
#
class apache::ssl {
  warning('apache::ssl is deprecated; please use apache::mod::ssl')
  include ::apache::mod::ssl
}
# Class: apache::version
#
# Try to automatically detect the version by OS
#
class apache::version {
  # This will be 5 or 6 on RedHat, 6 or wheezy on Debian, 12 or quantal on Ubuntu, 3 on Amazon, etc.
  $osr_array = split($::operatingsystemrelease,'[\/\.]')
  $distrelease = $osr_array[0]
  if ! $distrelease {
    fail("Class['apache::params']: Unparsable \$::operatingsystemrelease: ${::operatingsystemrelease}")
  }

  case $::osfamily {
    'RedHat': {
      if ($::operatingsystem == 'Fedora' and $distrelease >= 18) or ($::operatingsystem != 'Fedora' and $distrelease >= 7) {
        $default = '2.4'
      } else {
        $default = '2.2'
      }
    }
    'Debian': {
      if $::operatingsystem == 'Ubuntu' and $::operatingsystemrelease >= 13.10 {
        $default = '2.4'
      } else {
        $default = '2.2'
      }
    }
    'FreeBSD': {
      $default = '2.2'
    }
    default: {
      fail("Class['apache::version']: Unsupported osfamily: ${::osfamily}")
    }
  }
}
# Definition: apache::vhost
#
# This class installs Apache Virtual Hosts
#
# Parameters:
# - The $port to configure the host on
# - The $docroot provides the DocumentRoot variable
# - The $virtual_docroot provides VirtualDocumentationRoot variable
# - The $serveradmin will specify an email address for Apache that it will
#   display when it renders one of it's error pages
# - The $ssl option is set true or false to enable SSL for this Virtual Host
# - The $priority of the site
# - The $servername is the primary name of the virtual host
# - The $serveraliases of the site
# - The $ip to configure the host on, defaulting to *
# - The $options for the given vhost
# - The $override for the given vhost (list of AllowOverride arguments)
# - The $vhost_name for name based virtualhosting, defaulting to *
# - The $logroot specifies the location of the virtual hosts logfiles, default
#   to /var/log/<apache log location>/
# - The $log_level specifies the verbosity of the error log for this vhost. Not
#   set by default for the vhost, instead the global server configuration default
#   of 'warn' is used.
# - The $access_log specifies if *_access.log directives should be configured.
# - The $ensure specifies if vhost file is present or absent.
# - The $headers is a list of Header statement strings as per http://httpd.apache.org/docs/2.2/mod/mod_headers.html#header
# - The $request_headers is a list of RequestHeader statement strings as per http://httpd.apache.org/docs/2.2/mod/mod_headers.html#requestheader
# - $aliases is a list of Alias hashes for mod_alias as per http://httpd.apache.org/docs/current/mod/mod_alias.html
#   each statement is a hash in the form of { alias => '/alias', path => '/real/path/to/directory' }
# - $directories is a lost of hashes for creating <Directory> statements as per http://httpd.apache.org/docs/2.2/mod/core.html#directory
#   each statement is a hash in the form of { path => '/path/to/directory', <directive> => <value>}
#   see README.md for list of supported directives.
#
# Actions:
# - Install Apache Virtual Hosts
#
# Requires:
# - The apache class
#
# Sample Usage:
#
#  # Simple vhost definition:
#  apache::vhost { 'site.name.fqdn':
#    port => '80',
#    docroot => '/path/to/docroot',
#  }
#
#  # Multiple Mod Rewrites:
#  apache::vhost { 'site.name.fqdn':
#    port => '80',
#    docroot => '/path/to/docroot',
#    rewrites => [
#      {
#        comment       => 'force www domain',
#        rewrite_cond => ['%{HTTP_HOST} ^([a-z.]+)?example.com$ [NC]', '%{HTTP_HOST} !^www. [NC]'],
#        rewrite_rule => ['.? http://www.%1example.com%{REQUEST_URI} [R=301,L]']
#      },
#      {
#        comment       => 'prevent image hotlinking',
#        rewrite_cond => ['%{HTTP_REFERER} !^$', '%{HTTP_REFERER} !^http://(www.)?example.com/ [NC]'],
#        rewrite_rule => ['.(gif|jpg|png)$ - [F]']
#      },
#    ]
#  }
#
#  # SSL vhost with non-SSL rewrite:
#  apache::vhost { 'site.name.fqdn':
#    port    => '443',
#    ssl     => true,
#    docroot => '/path/to/docroot',
#  }
#  apache::vhost { 'site.name.fqdn':
#    port            => '80',
#    docroot         => '/path/to/other_docroot',
#    custom_fragment => template("${module_name}/my_fragment.erb"),
#  }
#
define apache::vhost(
    $docroot,
    $manage_docroot              = true,
    $virtual_docroot             = false,
    $port                        = undef,
    $ip                          = undef,
    $ip_based                    = false,
    $add_listen                  = true,
    $docroot_owner               = 'root',
    $docroot_group               = $::apache::params::root_group,
    $docroot_mode                = undef,
    $serveradmin                 = undef,
    $ssl                         = false,
    $ssl_cert                    = $::apache::default_ssl_cert,
    $ssl_key                     = $::apache::default_ssl_key,
    $ssl_chain                   = $::apache::default_ssl_chain,
    $ssl_ca                      = $::apache::default_ssl_ca,
    $ssl_crl_path                = $::apache::default_ssl_crl_path,
    $ssl_crl                     = $::apache::default_ssl_crl,
    $ssl_certs_dir               = $::apache::params::ssl_certs_dir,
    $ssl_protocol                = undef,
    $ssl_cipher                  = undef,
    $ssl_honorcipherorder        = undef,
    $ssl_verify_client           = undef,
    $ssl_verify_depth            = undef,
    $ssl_options                 = undef,
    $ssl_proxyengine             = false,
    $priority                    = undef,
    $default_vhost               = false,
    $servername                  = $name,
    $serveraliases               = [],
    $options                     = ['Indexes','FollowSymLinks','MultiViews'],
    $override                    = ['None'],
    $directoryindex              = '',
    $vhost_name                  = '*',
    $logroot                     = $::apache::logroot,
    $logroot_mode                = undef,
    $log_level                   = undef,
    $access_log                  = true,
    $access_log_file             = undef,
    $access_log_pipe             = undef,
    $access_log_syslog           = undef,
    $access_log_format           = undef,
    $access_log_env_var          = undef,
    $aliases                     = undef,
    $directories                 = undef,
    $error_log                   = true,
    $error_log_file              = undef,
    $error_log_pipe              = undef,
    $error_log_syslog            = undef,
    $error_documents             = [],
    $fallbackresource            = undef,
    $scriptalias                 = undef,
    $scriptaliases               = [],
    $proxy_dest                  = undef,
    $proxy_pass                  = undef,
    $suphp_addhandler            = $::apache::params::suphp_addhandler,
    $suphp_engine                = $::apache::params::suphp_engine,
    $suphp_configpath            = $::apache::params::suphp_configpath,
    $php_admin_flags             = [],
    $php_admin_values            = [],
    $no_proxy_uris               = [],
    $proxy_preserve_host         = false,
    $redirect_source             = '/',
    $redirect_dest               = undef,
    $redirect_status             = undef,
    $redirectmatch_status        = undef,
    $redirectmatch_regexp        = undef,
    $rack_base_uris              = undef,
    $headers                     = undef,
    $request_headers             = undef,
    $rewrites                    = undef,
    $rewrite_base                = undef,
    $rewrite_rule                = undef,
    $rewrite_cond                = undef,
    $setenv                      = [],
    $setenvif                    = [],
    $block                       = [],
    $ensure                      = 'present',
    $wsgi_application_group      = undef,
    $wsgi_daemon_process         = undef,
    $wsgi_daemon_process_options = undef,
    $wsgi_import_script          = undef,
    $wsgi_import_script_options  = undef,
    $wsgi_process_group          = undef,
    $wsgi_script_aliases         = undef,
    $wsgi_pass_authorization     = undef,
    $custom_fragment             = undef,
    $itk                         = undef,
    $action                      = undef,
    $fastcgi_server              = undef,
    $fastcgi_socket              = undef,
    $fastcgi_dir                 = undef,
    $additional_includes         = [],
    $apache_version              = $::apache::apache_version,
    $suexec_user_group           = undef,
  ) {
  # The base class must be included first because it is used by parameter defaults
  if ! defined(Class['apache']) {
    fail('You must include the apache base class before using any apache defined resources')
  }

  $apache_name = $::apache::params::apache_name

  validate_re($ensure, '^(present|absent)$',
  "${ensure} is not supported for ensure.
  Allowed values are 'present' and 'absent'.")
  validate_re($suphp_engine, '^(on|off)$',
  "${suphp_engine} is not supported for suphp_engine.
  Allowed values are 'on' and 'off'.")
  validate_bool($ip_based)
  validate_bool($access_log)
  validate_bool($error_log)
  validate_bool($ssl)
  validate_bool($default_vhost)
  validate_bool($ssl_proxyengine)
  if $rewrites {
    validate_array($rewrites)
    validate_hash($rewrites[0])
  }

  if $suexec_user_group {
    validate_re($suexec_user_group, '^\w+ \w+$',
    "${suexec_user_group} is not supported for suexec_user_group.  Must be 'user group'.")
  }

  # Deprecated backwards-compatibility
  if $rewrite_base {
    warning('Apache::Vhost: parameter rewrite_base is deprecated in favor of rewrites')
  }
  if $rewrite_rule {
    warning('Apache::Vhost: parameter rewrite_rule is deprecated in favor of rewrites')
  }
  if $rewrite_cond {
    warning('Apache::Vhost parameter rewrite_cond is deprecated in favor of rewrites')
  }

  if $wsgi_script_aliases {
    validate_hash($wsgi_script_aliases)
  }
  if $wsgi_daemon_process_options {
    validate_hash($wsgi_daemon_process_options)
  }
  if $wsgi_import_script_options {
    validate_hash($wsgi_import_script_options)
  }
  if $itk {
    validate_hash($itk)
  }

  if $log_level {
    validate_re($log_level, '^(emerg|alert|crit|error|warn|notice|info|debug)$',
    "Log level '${log_level}' is not one of the supported Apache HTTP Server log levels.")
  }

  if $access_log_file and $access_log_pipe {
    fail("Apache::Vhost[${name}]: 'access_log_file' and 'access_log_pipe' cannot be defined at the same time")
  }

  if $error_log_file and $error_log_pipe {
    fail("Apache::Vhost[${name}]: 'error_log_file' and 'error_log_pipe' cannot be defined at the same time")
  }

  if $fallbackresource {
    validate_re($fallbackresource, '^/|disabled', 'Please make sure fallbackresource starts with a / (or is "disabled")')
  }

  if $ssl and $ensure == 'present' {
    include ::apache::mod::ssl
    # Required for the AddType lines.
    include ::apache::mod::mime
  }

  if $virtual_docroot {
    include ::apache::mod::vhost_alias
  }

  if $wsgi_daemon_process {
    include ::apache::mod::wsgi
  }

  if $suexec_user_group {
    include ::apache::mod::suexec
  }

  # This ensures that the docroot exists
  # But enables it to be specified across multiple vhost resources
  if ! defined(File[$docroot]) and $manage_docroot {
    file { $docroot:
      ensure  => directory,
      owner   => $docroot_owner,
      group   => $docroot_group,
      mode    => $docroot_mode,
      require => Package['httpd'],
    }
  }

  # Same as above, but for logroot
  if ! defined(File[$logroot]) and $ensure == 'present' {
    file { $logroot:
      ensure  => directory,
      mode    => $logroot_mode,
      require => Package['httpd'],
    }
  }


  # Is apache::mod::passenger enabled (or apache::mod['passenger'])
  $passenger_enabled = defined(Apache::Mod['passenger'])

  # Define log file names
  if $access_log_file {
    $access_log_destination = "${logroot}/${access_log_file}"
  } elsif $access_log_pipe {
    $access_log_destination = $access_log_pipe
  } elsif $access_log_syslog {
    $access_log_destination = $access_log_syslog
  } else {
    if $ssl {
      $access_log_destination = "${logroot}/${name}_access_ssl.log"
    } else {
      $access_log_destination = "${logroot}/${name}_access.log"
    }
  }

  if $error_log_file {
    $error_log_destination = "${logroot}/${error_log_file}"
  } elsif $error_log_pipe {
    $error_log_destination = $error_log_pipe
  } elsif $error_log_syslog {
    $error_log_destination = $error_log_syslog
  } else {
    if $ssl {
      $error_log_destination = "${logroot}/${name}_error_ssl.log"
    } else {
      $error_log_destination = "${logroot}/${name}_error.log"
    }
  }

  # Set access log format
  if $access_log_format {
    $_access_log_format = "\"${access_log_format}\""
  } else {
    $_access_log_format = 'combined'
  }

  if $access_log_env_var {
    $_access_log_env_var = "env=${access_log_env_var}"
  }

  if $ip {
    if $port {
      $listen_addr_port = "${ip}:${port}"
      $nvh_addr_port = "${ip}:${port}"
    } else {
      $listen_addr_port = undef
      $nvh_addr_port = $ip
      if ! $servername and ! $ip_based {
        fail("Apache::Vhost[${name}]: must pass 'ip' and/or 'port' parameters for name-based vhosts")
      }
    }
  } else {
    if $port {
      $listen_addr_port = $port
      $nvh_addr_port = "${vhost_name}:${port}"
    } else {
      $listen_addr_port = undef
      $nvh_addr_port = $name
      if ! $servername {
        fail("Apache::Vhost[${name}]: must pass 'ip' and/or 'port' parameters, and/or 'servername' parameter")
      }
    }
  }
  if $add_listen {
    if $ip and defined(Apache::Listen[$port]) {
      fail("Apache::Vhost[${name}]: Mixing IP and non-IP Listen directives is not possible; check the add_listen parameter of the apache::vhost define to disable this")
    }
    if ! defined(Apache::Listen[$listen_addr_port]) and $listen_addr_port and $ensure == 'present' {
      ::apache::listen { $listen_addr_port: }
    }
  }
  if ! $ip_based {
    if ! defined(Apache::Namevirtualhost[$nvh_addr_port]) and $ensure == 'present' and (versioncmp($apache_version, '2.4') < 0) {
      ::apache::namevirtualhost { $nvh_addr_port: }
    }
  }

  # Load mod_rewrite if needed and not yet loaded
  if $rewrites or $rewrite_cond {
    if ! defined(Class['apache::mod::rewrite']) {
      include ::apache::mod::rewrite
    }
  }

  # Load mod_alias if needed and not yet loaded
  if ($scriptalias or $scriptaliases != []) or ($redirect_source and $redirect_dest) {
    if ! defined(Class['apache::mod::alias']) {
      include ::apache::mod::alias
    }
  }

  # Load mod_proxy if needed and not yet loaded
  if ($proxy_dest or $proxy_pass) {
    if ! defined(Class['apache::mod::proxy']) {
      include ::apache::mod::proxy
    }
    if ! defined(Class['apache::mod::proxy_http']) {
      include ::apache::mod::proxy_http
    }
  }

  # Load mod_passenger if needed and not yet loaded
  if $rack_base_uris {
    if ! defined(Class['apache::mod::passenger']) {
      include ::apache::mod::passenger
    }
  }

  # Load mod_fastci if needed and not yet loaded
  if $fastcgi_server and $fastcgi_socket {
    if ! defined(Class['apache::mod::fastcgi']) {
      include ::apache::mod::fastcgi
    }
  }

  # Configure the defaultness of a vhost
  if $priority {
    $priority_real = $priority
  } elsif $default_vhost {
    $priority_real = '10'
  } else {
    $priority_real = '25'
  }

  # Check if mod_headers is required to process $headers/$request_headers
  if $headers or $request_headers {
    if ! defined(Class['apache::mod::headers']) {
      include ::apache::mod::headers
    }
  }

  ## Apache include does not always work with spaces in the filename
  $filename = regsubst($name, ' ', '_', 'G')

  ## Create a default directory list if none defined
  if $directories {
    if !is_hash($directories) and !(is_array($directories) and is_hash($directories[0])) {
      fail("Apache::Vhost[${name}]: 'directories' must be either a Hash or an Array of Hashes")
    }
    $_directories = $directories
  } else {
    $_directory = {
      provider       => 'directory',
      path           => $docroot,
      options        => $options,
      allow_override => $override,
      directoryindex => $directoryindex,
    }

    if versioncmp($apache_version, '2.4') >= 0 {
      $_directory_version = {
        require => 'all granted',
      }
    } else {
      $_directory_version = {
        order => 'allow,deny',
        allow => 'from all',
      }
    }

    $_directories = [ merge($_directory, $_directory_version) ]
  }

  # Template uses:
  # - $nvh_addr_port
  # - $servername
  # - $serveradmin
  # - $docroot
  # - $virtual_docroot
  # - $options
  # - $override
  # - $logroot
  # - $name
  # - $aliases
  # - $_directories
  # - $log_level
  # - $access_log
  # - $access_log_destination
  # - $_access_log_format
  # - $_access_log_env_var
  # - $error_log
  # - $error_log_destination
  # - $error_documents
  # - $fallbackresource
  # - $custom_fragment
  # - $additional_includes
  # block fragment:
  #   - $block
  # directories fragment:
  #   - $passenger_enabled
  #   - $php_admin_flags
  #   - $php_admin_values
  #   - $directories (a list of key-value hashes is expected)
  # fastcgi fragment:
  #   - $fastcgi_server
  #   - $fastcgi_socket
  #   - $fastcgi_dir
  # proxy fragment:
  #   - $proxy_dest
  #   - $no_proxy_uris
  #   - $proxy_preserve_host (true to set ProxyPreserveHost to on and false to off
  # rack fragment:
  #   - $rack_base_uris
  # redirect fragment:
  #   - $redirect_source
  #   - $redirect_dest
  #   - $redirect_status
  # header fragment
  #   - $headers
  # requestheader fragment:
  #   - $request_headers
  # rewrite fragment:
  #   - $rewrites
  # scriptalias fragment:
  #   - $scriptalias
  #   - $scriptaliases
  #   - $ssl
  # serveralias fragment:
  #   - $serveraliases
  # setenv fragment:
  #   - $setenv
  #   - $setenvif
  # ssl fragment:
  #   - $ssl
  #   - $ssl_cert
  #   - $ssl_key
  #   - $ssl_chain
  #   - $ssl_certs_dir
  #   - $ssl_ca
  #   - $ssl_crl
  #   - $ssl_crl_path
  #   - $ssl_verify_client
  #   - $ssl_verify_depth
  #   - $ssl_options
  # suphp fragment:
  #   - $suphp_addhandler
  #   - $suphp_engine
  #   - $suphp_configpath
  # wsgi fragment:
  #   - $wsgi_application_group
  #   - $wsgi_daemon_process
  #   - $wsgi_import_script
  #   - $wsgi_process_group
  #   - $wsgi_script_aliases
  file { "${priority_real}-${filename}.conf":
    ensure  => $ensure,
    path    => "${::apache::vhost_dir}/${priority_real}-${filename}.conf",
    content => template('apache/vhost.conf.erb'),
    owner   => 'root',
    group   => $::apache::params::root_group,
    mode    => '0644',
    require => [
      Package['httpd'],
      File[$docroot],
      File[$logroot],
    ],
    notify  => Service['httpd'],
  }
  if $::osfamily == 'Debian' {
    $vhost_enable_dir = $::apache::vhost_enable_dir
    $vhost_symlink_ensure = $ensure ? {
      present => link,
      default => $ensure,
    }
    file{ "${priority_real}-${filename}.conf symlink":
      ensure  => $vhost_symlink_ensure,
      path    => "${vhost_enable_dir}/${priority_real}-${filename}.conf",
      target  => "${::apache::vhost_dir}/${priority_real}-${filename}.conf",
      owner   => 'root',
      group   => $::apache::params::root_group,
      mode    => '0644',
      require => File["${priority_real}-${filename}.conf"],
      notify  => Service['httpd'],
    }
  }
}
{
  "name": "puppetlabs-apache",
  "version": "1.1.1",
  "author": "puppetlabs",
  "summary": "Puppet module for Apache",
  "license": "Apache 2.0",
  "source": "git://github.com/puppetlabs/puppetlabs-apache.git",
  "project_page": "https://github.com/puppetlabs/puppetlabs-apache",
  "issues_url": "https://github.com/puppetlabs/puppetlabs-apache/issues",
  "operatingsystem_support": [
    {
      "operatingsystem": "RedHat",
      "operatingsystemrelease": [
        "5",
        "6",
        "7"
      ]
    },
    {
      "operatingsystem": "CentOS",
      "operatingsystemrelease": [
        "5",
        "6",
        "7"
      ]
    },
    {
      "operatingsystem": "OracleLinux",
      "operatingsystemrelease": [
        "5",
        "6",
        "7"
      ]
    },
    {
      "operatingsystem": "Scientific",
      "operatingsystemrelease": [
        "5",
        "6",
        "7"
      ]
    },
    {
      "operatingsystem": "Debian",
      "operatingsystemrelease": [
        "6",
        "7"
      ]
    },
    {
      "operatingsystem": "Ubuntu",
      "operatingsystemrelease": [
        "10.04",
        "12.04",
        "14.04"
      ]
    }
  ],
  "requirements": [
    {
      "name": "pe",
      "version_requirement": ">= 3.2.0 < 3.4.0"
    },
    {
      "name": "puppet",
      "version_requirement": "3.x"
    }
  ],
  "description": "Module for Apache configuration",
  "dependencies": [
    {
      "name": "puppetlabs/stdlib",
      "version_requirement": ">= 2.4.0"
    },
    {
      "name": "puppetlabs/concat",
      "version_requirement": ">= 1.0.0"
    }
  ]
}
require 'spec_helper_acceptance'
require_relative './version.rb'

describe 'apache parameters', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do

  # Currently this test only does something on FreeBSD.
  describe 'default_confd_files => false' do
    it 'doesnt do anything' do
      pp = "class { 'apache': default_confd_files => false }"
      apply_manifest(pp, :catch_failures => true)
    end

    if fact('osfamily') == 'FreeBSD'
      describe file("#{confd_dir}/no-accf.conf.erb") do
        it { is_expected.not_to be_file }
      end
    end
  end
  describe 'default_confd_files => true' do
    it 'copies conf.d files' do
      pp = "class { 'apache': default_confd_files => true }"
      apply_manifest(pp, :catch_failures => true)
    end

    if fact('osfamily') == 'FreeBSD'
      describe file("#{$confd_dir}/no-accf.conf.erb") do
        it { is_expected.to be_file }
      end
    end
  end

  describe 'when set adds a listen statement' do
    it 'applys cleanly' do
      pp = "class { 'apache': ip => '10.1.1.1', service_ensure => stopped }"
      apply_manifest(pp, :catch_failures => true)
    end

    describe file($ports_file) do
      it { is_expected.to be_file }
      it { is_expected.to contain 'Listen 10.1.1.1' }
    end
  end

  describe 'service tests => true' do
    it 'starts the service' do
      pp = <<-EOS
        class { 'apache':
          service_enable => true,
          service_ensure => running,
        }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe service($service_name) do
      it { is_expected.to be_running }
      it { is_expected.to be_enabled }
    end
  end

  describe 'service tests => false' do
    it 'stops the service' do
      pp = <<-EOS
        class { 'apache':
          service_enable => false,
          service_ensure => stopped,
        }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe service($service_name) do
      it { is_expected.not_to be_running }
      it { is_expected.not_to be_enabled }
    end
  end

  describe 'purge parameters => false' do
    it 'applies cleanly' do
      pp = <<-EOS
        class { 'apache':
          purge_configs   => false,
          purge_vdir      => false,
          purge_vhost_dir => false,
          vhost_dir       => "#{confd_dir}.vhosts"
        }
      EOS
      shell("touch #{$confd_dir}/test.conf")
      shell("mkdir -p #{$confd_dir}.vhosts && touch #{$confd_dir}.vhosts/test.conf")
      apply_manifest(pp, :catch_failures => true)
    end

    # Ensure the files didn't disappear.
    describe file("#{$confd_dir}/test.conf") do
      it { is_expected.to be_file }
    end
    describe file("#{$confd_dir}.vhosts/test.conf") do
      it { is_expected.to be_file }
    end
  end

  if fact('osfamily') != 'Debian'
    describe 'purge parameters => true' do
      it 'applies cleanly' do
        pp = <<-EOS
          class { 'apache':
            purge_configs   => true,
            purge_vdir      => true,
            purge_vhost_dir => true,
            vhost_dir       => "#{confd_dir}.vhosts"
          }
        EOS
        shell("touch #{$confd_dir}/test.conf")
        shell("mkdir -p #{$confd_dir}.vhosts && touch #{$confd_dir}.vhosts/test.conf")
        apply_manifest(pp, :catch_failures => true)
      end

      # File should be gone
      describe file("#{$confd_dir}/test.conf") do
        it { is_expected.not_to be_file }
      end
      describe file("#{$confd_dir}.vhosts/test.conf") do
        it { is_expected.not_to be_file }
      end
    end
  end

  describe 'serveradmin' do
    it 'applies cleanly' do
      pp = "class { 'apache': serveradmin => 'test@example.com' }"
      apply_manifest(pp, :catch_failures => true)
    end

    describe file($vhost) do
      it { is_expected.to be_file }
      it { is_expected.to contain 'ServerAdmin test@example.com' }
    end
  end

  describe 'sendfile' do
    describe 'setup' do
      it 'applies cleanly' do
        pp = "class { 'apache': sendfile => 'On' }"
        apply_manifest(pp, :catch_failures => true)
      end
    end

    describe file($conf_file) do
      it { is_expected.to be_file }
      it { is_expected.to contain 'EnableSendfile On' }
    end

    describe 'setup' do
      it 'applies cleanly' do
        pp = "class { 'apache': sendfile => 'Off' }"
        apply_manifest(pp, :catch_failures => true)
      end
    end

    describe file($conf_file) do
      it { is_expected.to be_file }
      it { is_expected.to contain 'Sendfile Off' }
    end
  end

  describe 'error_documents' do
    describe 'setup' do
      it 'applies cleanly' do
        pp = "class { 'apache': error_documents => true }"
        apply_manifest(pp, :catch_failures => true)
      end
    end

    describe file($conf_file) do
      it { is_expected.to be_file }
      it { is_expected.to contain 'Alias /error/' }
    end
  end

  describe 'timeout' do
    describe 'setup' do
      it 'applies cleanly' do
        pp = "class { 'apache': timeout => '1234' }"
        apply_manifest(pp, :catch_failures => true)
      end
    end

    describe file($conf_file) do
      it { is_expected.to be_file }
      it { is_expected.to contain 'Timeout 1234' }
    end
  end

  describe 'httpd_dir' do
    describe 'setup' do
      it 'applies cleanly' do
        pp = <<-EOS
          class { 'apache': httpd_dir => '/tmp', service_ensure => stopped }
          include 'apache::mod::mime'
        EOS
        apply_manifest(pp, :catch_failures => true)
      end
    end

    describe file("#{$confd_dir}/mime.conf") do
      it { is_expected.to be_file }
      it { is_expected.to contain 'AddLanguage eo .eo' }
    end
  end

  describe 'server_root' do
    describe 'setup' do
      it 'applies cleanly' do
        pp = "class { 'apache': server_root => '/tmp/root', service_ensure => stopped }"
        apply_manifest(pp, :catch_failures => true)
      end
    end

    describe file($conf_file) do
      it { is_expected.to be_file }
      it { is_expected.to contain 'ServerRoot "/tmp/root"' }
    end
  end

  describe 'confd_dir' do
    describe 'setup' do
      it 'applies cleanly' do
        pp = "class { 'apache': confd_dir => '/tmp/root', service_ensure => stopped }"
        apply_manifest(pp, :catch_failures => true)
      end
    end

    if $apache_version == '2.4'
      describe file($conf_file) do
        it { is_expected.to be_file }
        it { is_expected.to contain 'IncludeOptional "/tmp/root/*.conf"' }
      end
    else
      describe file($conf_file) do
        it { is_expected.to be_file }
        it { is_expected.to contain 'Include "/tmp/root/*.conf"' }
      end
    end
  end

  describe 'conf_template' do
    describe 'setup' do
      it 'applies cleanly' do
        pp = "class { 'apache': conf_template => 'another/test.conf.erb', service_ensure => stopped }"
        shell("mkdir -p #{default['distmoduledir']}/another/templates")
        shell("echo 'testcontent' >> #{default['distmoduledir']}/another/templates/test.conf.erb")
        apply_manifest(pp, :catch_failures => true)
      end
    end

    describe file($conf_file) do
      it { is_expected.to be_file }
      it { is_expected.to contain 'testcontent' }
    end
  end

  describe 'servername' do
    describe 'setup' do
      it 'applies cleanly' do
        pp = "class { 'apache': servername => 'test.server', service_ensure => stopped }"
        apply_manifest(pp, :catch_failures => true)
      end
    end

    describe file($conf_file) do
      it { is_expected.to be_file }
      it { is_expected.to contain 'ServerName "test.server"' }
    end
  end

  describe 'user' do
    describe 'setup' do
      it 'applies cleanly' do
        pp = <<-EOS
          class { 'apache':
            manage_user  => true,
            manage_group => true,
            user         => 'testweb',
            group        => 'testweb',
          }
        EOS
        apply_manifest(pp, :catch_failures => true)
      end
    end

    describe user('testweb') do
      it { is_expected.to exist }
      it { is_expected.to belong_to_group 'testweb' }
    end

    describe group('testweb') do
      it { is_expected.to exist }
    end
  end

  describe 'logformats' do
    describe 'setup' do
      it 'applies cleanly' do
        pp = <<-EOS
          class { 'apache':
            log_formats => {
              'vhost_common'   => '%v %h %l %u %t \\\"%r\\\" %>s %b',
              'vhost_combined' => '%v %h %l %u %t \\\"%r\\\" %>s %b \\\"%{Referer}i\\\" \\\"%{User-agent}i\\\"',
            }
          }
        EOS
        apply_manifest(pp, :catch_failures => true)
      end
    end

    describe file($conf_file) do
      it { is_expected.to be_file }
      it { is_expected.to contain 'LogFormat "%v %h %l %u %t \"%r\" %>s %b" vhost_common' }
      it { is_expected.to contain 'LogFormat "%v %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\"" vhost_combined' }
    end
  end


  describe 'keepalive' do
    describe 'setup' do
      it 'applies cleanly' do
        pp = "class { 'apache': keepalive => 'On', keepalive_timeout => '30', max_keepalive_requests => '200' }"
        apply_manifest(pp, :catch_failures => true)
      end
    end

    describe file($conf_file) do
      it { is_expected.to be_file }
      it { is_expected.to contain 'KeepAlive On' }
      it { is_expected.to contain 'KeepAliveTimeout 30' }
      it { is_expected.to contain 'MaxKeepAliveRequests 200' }
    end
  end

  describe 'logging' do
    describe 'setup' do
      it 'applies cleanly' do
        pp = <<-EOS
          if $::osfamily == 'RedHat' and $::selinux == 'true' {
            $semanage_package = $::operatingsystemmajrelease ? {
              '5'     => 'policycoreutils',
              default => 'policycoreutils-python',
            }

            package { $semanage_package: ensure => installed }
            exec { 'set_apache_defaults':
              command => 'semanage fcontext -a -t httpd_log_t "/apache_spec(/.*)?"',
              path    => '/bin:/usr/bin/:/sbin:/usr/sbin',
              require => Package[$semanage_package],
            }
            exec { 'restorecon_apache':
              command => 'restorecon -Rv /apache_spec',
              path    => '/bin:/usr/bin/:/sbin:/usr/sbin',
              before  => Service['httpd'],
              require => Class['apache'],
            }
          }
          file { '/apache_spec': ensure => directory, }
          class { 'apache': logroot => '/apache_spec' }
        EOS
        apply_manifest(pp, :catch_failures => true)
      end
    end

    describe file("/apache_spec/#{$error_log}") do
      it { is_expected.to be_file }
    end
  end

  describe 'ports_file' do
    it 'applys cleanly' do
      pp = <<-EOS
        file { '/apache_spec': ensure => directory, }
        class { 'apache':
          ports_file     => '/apache_spec/ports_file',
          ip             => '10.1.1.1',
          service_ensure => stopped
        }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe file('/apache_spec/ports_file') do
      it { is_expected.to be_file }
      it { is_expected.to contain 'Listen 10.1.1.1' }
    end
  end

  describe 'server_tokens' do
    it 'applys cleanly' do
      pp = <<-EOS
        class { 'apache':
          server_tokens  => 'Minor',
        }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe file($conf_file) do
      it { is_expected.to be_file }
      it { is_expected.to contain 'ServerTokens Minor' }
    end
  end

  describe 'server_signature' do
    it 'applys cleanly' do
      pp = <<-EOS
        class { 'apache':
          server_signature  => 'testsig',
          service_ensure    => stopped,
        }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe file($conf_file) do
      it { is_expected.to be_file }
      it { is_expected.to contain 'ServerSignature testsig' }
    end
  end

  describe 'trace_enable' do
    it 'applys cleanly' do
      pp = <<-EOS
        class { 'apache':
          trace_enable  => 'Off',
        }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe file($conf_file) do
      it { is_expected.to be_file }
      it { is_expected.to contain 'TraceEnable Off' }
    end
  end

  describe 'package_ensure' do
    it 'applys cleanly' do
      pp = <<-EOS
        class { 'apache':
          package_ensure  => present,
        }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe package($package_name) do
      it { is_expected.to be_installed }
    end
  end

end
require 'spec_helper_acceptance'

case fact('osfamily')
when 'RedHat'
  vhostd = '/etc/httpd/conf.d'
when 'Debian'
  vhostd = '/etc/apache2/sites-available'
end

describe 'apache ssl', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do

  describe 'ssl parameters' do
    it 'runs without error' do
      pp = <<-EOS
        class { 'apache':
          service_ensure       => stopped,
          default_ssl_vhost    => true,
          default_ssl_cert     => '/tmp/ssl_cert',
          default_ssl_key      => '/tmp/ssl_key',
          default_ssl_chain    => '/tmp/ssl_chain',
          default_ssl_ca       => '/tmp/ssl_ca',
          default_ssl_crl_path => '/tmp/ssl_crl_path',
          default_ssl_crl      => '/tmp/ssl_crl',
        }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe file("#{vhostd}/15-default-ssl.conf") do
      it { is_expected.to be_file }
      it { is_expected.to contain 'SSLCertificateFile      "/tmp/ssl_cert"' }
      it { is_expected.to contain 'SSLCertificateKeyFile   "/tmp/ssl_key"' }
      it { is_expected.to contain 'SSLCertificateChainFile "/tmp/ssl_chain"' }
      it { is_expected.to contain 'SSLCACertificateFile    "/tmp/ssl_ca"' }
      it { is_expected.to contain 'SSLCARevocationPath     "/tmp/ssl_crl_path"' }
      it { is_expected.to contain 'SSLCARevocationFile     "/tmp/ssl_crl"' }
    end
  end

  describe 'vhost ssl parameters' do
    it 'runs without error' do
      pp = <<-EOS
        class { 'apache':
          service_ensure       => stopped,
        }

        apache::vhost { 'test_ssl':
          docroot              => '/tmp/test',
          ssl                  => true,
          ssl_cert             => '/tmp/ssl_cert',
          ssl_key              => '/tmp/ssl_key',
          ssl_chain            => '/tmp/ssl_chain',
          ssl_ca               => '/tmp/ssl_ca',
          ssl_crl_path         => '/tmp/ssl_crl_path',
          ssl_crl              => '/tmp/ssl_crl',
          ssl_certs_dir        => '/tmp',
          ssl_protocol         => 'test',
          ssl_cipher           => 'test',
          ssl_honorcipherorder => 'test',
          ssl_verify_client    => 'test',
          ssl_verify_depth     => 'test',
          ssl_options          => ['test', 'test1'],
          ssl_proxyengine      => true,
        }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe file("#{vhostd}/25-test_ssl.conf") do
      it { is_expected.to be_file }
      it { is_expected.to contain 'SSLCertificateFile      "/tmp/ssl_cert"' }
      it { is_expected.to contain 'SSLCertificateKeyFile   "/tmp/ssl_key"' }
      it { is_expected.to contain 'SSLCertificateChainFile "/tmp/ssl_chain"' }
      it { is_expected.to contain 'SSLCACertificateFile    "/tmp/ssl_ca"' }
      it { is_expected.to contain 'SSLCARevocationPath     "/tmp/ssl_crl_path"' }
      it { is_expected.to contain 'SSLCARevocationFile     "/tmp/ssl_crl"' }
      it { is_expected.to contain 'SSLProxyEngine On' }
      it { is_expected.to contain 'SSLProtocol             test' }
      it { is_expected.to contain 'SSLCipherSuite          test' }
      it { is_expected.to contain 'SSLHonorCipherOrder     test' }
      it { is_expected.to contain 'SSLVerifyClient         test' }
      it { is_expected.to contain 'SSLVerifyDepth          test' }
      it { is_expected.to contain 'SSLOptions test test1' }
    end
  end

end
require 'spec_helper_acceptance'

describe 'disable selinux:', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
  it "because otherwise apache won't work" do
    apply_manifest(%{
      exec { "setenforce 0":
        path   => "/bin:/sbin:/usr/bin:/usr/sbin",
        onlyif => "which setenforce && getenforce | grep Enforcing",
      }
    }, :catch_failures => true)
  end
end
require 'spec_helper_acceptance'

describe 'apache class', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
  case fact('osfamily')
  when 'RedHat'
    package_name = 'httpd'
    service_name = 'httpd'
  when 'Debian'
    package_name = 'apache2'
    service_name = 'apache2'
  when 'FreeBSD'
    package_name = 'apache22'
    service_name = 'apache22'
  end

  context 'default parameters' do
    it 'should work with no errors' do
      pp = <<-EOS
      class { 'apache': }
      EOS

      # Run it twice and test for idempotency
      apply_manifest(pp, :catch_failures => true)
      expect(apply_manifest(pp, :catch_failures => true).exit_code).to be_zero
    end

    describe package(package_name) do
      it { is_expected.to be_installed }
    end

    describe service(service_name) do
      it { is_expected.to be_enabled }
      it { is_expected.to be_running }
    end
  end

  context 'custom site/mod dir parameters' do
    # Using puppet_apply as a helper
    it 'should work with no errors' do
      pp = <<-EOS
      if $::osfamily == 'RedHat' and $::selinux == 'true' {
        $semanage_package = $::operatingsystemmajrelease ? {
          '5'     => 'policycoreutils',
          default => 'policycoreutils-python',
        }

        package { $semanage_package: ensure => installed }
        exec { 'set_apache_defaults':
          command     => 'semanage fcontext -a -t httpd_sys_content_t "/apache_spec(/.*)?"',
          path        => '/bin:/usr/bin/:/sbin:/usr/sbin',
          subscribe   => Package[$semanage_package],
          refreshonly => true,
        }
        exec { 'restorecon_apache':
          command     => 'restorecon -Rv /apache_spec',
          path        => '/bin:/usr/bin/:/sbin:/usr/sbin',
          before      => Service['httpd'],
          require     => Class['apache'],
          subscribe   => Exec['set_apache_defaults'],
          refreshonly => true,
        }
      }
      file { '/apache_spec': ensure => directory, }
      file { '/apache_spec/apache_custom': ensure => directory, }
      class { 'apache':
        mod_dir   => '/apache_spec/apache_custom/mods',
        vhost_dir => '/apache_spec/apache_custom/vhosts',
      }
      EOS

      # Run it twice and test for idempotency
      apply_manifest(pp, :catch_failures => true)
      apply_manifest(pp, :catch_changes => true)
    end

    describe service(service_name) do
      it { is_expected.to be_enabled }
      it { is_expected.to be_running }
    end
  end
end
require 'spec_helper_acceptance'

case fact('osfamily')
when 'RedHat'
  mod_dir     = '/etc/httpd/conf.d'
  servicename = 'httpd'
when 'Debian'
  mod_dir     = '/etc/apache2/mods-available'
  servicename = 'apache2'
when 'FreeBSD'
  mod_dir     = '/usr/local/etc/apache22/Modules'
  servicename = 'apache22'
end

describe 'apache::default_mods class', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
  describe 'no default mods' do
    # Using puppet_apply as a helper
    it 'should apply with no errors' do
      pp = <<-EOS
        class { 'apache':
          default_mods => false,
        }
      EOS

      # Run it twice and test for idempotency
      apply_manifest(pp, :catch_failures => true)
      expect(apply_manifest(pp, :catch_failures => true).exit_code).to be_zero
    end

    describe service(servicename) do
      it { is_expected.to be_running }
    end
  end

  describe 'no default mods and failing' do
    # Using puppet_apply as a helper
    it 'should apply with errors' do
      pp = <<-EOS
        class { 'apache':
          default_mods => false,
        }
        apache::vhost { 'defaults.example.com':
          docroot => '/var/www/defaults',
          aliases => {
            alias => '/css',
            path  => '/var/www/css',
          },
          setenv  => 'TEST1 one',
        }
      EOS

      apply_manifest(pp, { :expect_failures => true })
    end

    # Are these the same?
    describe service(servicename) do
      it { is_expected.not_to be_running }
    end
    describe "service #{servicename}" do
      it 'should not be running' do
        shell("pidof #{servicename}", {:acceptable_exit_codes => 1})
      end
    end
  end

  describe 'alternative default mods' do
    # Using puppet_apply as a helper
    it 'should apply with no errors' do
      pp = <<-EOS
        class { 'apache':
          default_mods => [
            'info',
            'alias',
            'mime',
            'env',
            'expires',
          ],
        }
        apache::vhost { 'defaults.example.com':
          docroot => '/var/www/defaults',
          aliases => {
            alias => '/css',
            path  => '/var/www/css',
          },
          setenv  => 'TEST1 one',
        }
      EOS

      apply_manifest(pp, :catch_failures => true)
      shell('sleep 10')
      expect(apply_manifest(pp, :catch_failures => true).exit_code).to be_zero
    end

    describe service(servicename) do
      it { is_expected.to be_running }
    end
  end

  describe 'change loadfile name' do
    it 'should apply with no errors' do
      pp = <<-EOS
        class { 'apache': default_mods => false }
        ::apache::mod { 'auth_basic': 
          loadfile_name => 'zz_auth_basic.load',
        }
      EOS
      # Run it twice and test for idempotency
      apply_manifest(pp, :catch_failures => true)
      expect(apply_manifest(pp, :catch_failures => true).exit_code).to be_zero
    end

    describe service(servicename) do
      it { is_expected.to be_running }
    end

    describe file("#{mod_dir}/zz_auth_basic.load") do
      it { is_expected.to be_file }
    end
  end
end
require 'spec_helper_acceptance'

case fact('osfamily')
when 'Debian'
  service_name = 'apache2'
when 'FreeBSD'
  service_name = 'apache22'
else
  # Not implemented yet
  service_name = :skip
end

describe 'apache::mod::itk class', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) or service_name.equal? :skip do
  describe 'running puppet code' do
    # Using puppet_apply as a helper
    it 'should work with no errors' do
      pp = <<-EOS
          class { 'apache':
            mpm_module => 'itk',
          }
      EOS

      # Run it twice and test for idempotency
      apply_manifest(pp, :catch_failures => true)
      expect(apply_manifest(pp, :catch_failures => true).exit_code).to be_zero
    end
  end

  describe service(service_name) do
    it { is_expected.to be_running }
    it { is_expected.to be_enabled }
  end
end
require 'spec_helper_acceptance'

describe 'apache::mod::dav_svn class' do
  case fact('osfamily')
  when 'Debian'
    mod_dir             = '/etc/apache2/mods-available'
    service_name        = 'apache2'
    authz_svn_load_file = 'authz_svn.load'
  when 'RedHat'
    mod_dir             = '/etc/httpd/conf.d'
    service_name        = 'httpd'
    authz_svn_load_file = 'dav_svn_authz_svn.load'
  when 'FreeBSD'
    mod_dir             = '/usr/local/etc/apache22/Modules'
    service_name        = 'apache22'
    authz_svn_load_file = 'dav_svn_authz_svn.load'
  end

  context "default dav_svn config" do
    it 'succeeds in puppeting dav_svn' do
      pp= <<-EOS
        class { 'apache': }
        include apache::mod::dav_svn
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe service(service_name) do
      it { is_expected.to be_enabled }
      it { is_expected.to be_running }
    end

    describe file("#{mod_dir}/dav_svn.load") do
      it { is_expected.to contain "LoadModule dav_svn_module" }
    end
  end

  context "dav_svn with enabled authz_svn config" do
    it 'succeeds in puppeting dav_svn' do
      pp= <<-EOS
        class { 'apache': }
        class { 'apache::mod::dav_svn':
            authz_svn_enabled => true,
        }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe service(service_name) do
      it { is_expected.to be_enabled }
      it { is_expected.to be_running }
    end

    describe file("#{mod_dir}/#{authz_svn_load_file}") do
      it { is_expected.to contain "LoadModule authz_svn_module" }
    end
  end
end
require 'spec_helper_acceptance'

describe 'apache::mod::deflate class' do
  case fact('osfamily')
  when 'Debian'
    mod_dir      = '/etc/apache2/mods-available'
    service_name = 'apache2'
  when 'RedHat'
    mod_dir      = '/etc/httpd/conf.d'
    service_name = 'httpd'
  when 'FreeBSD'
    mod_dir      = '/usr/local/etc/apache22/Modules'
    service_name = 'apache22'
  end

  context "default deflate config" do
    it 'succeeds in puppeting deflate' do
      pp= <<-EOS
        class { 'apache': }
        include apache::mod::deflate
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe service(service_name) do
      it { is_expected.to be_enabled }
      it { is_expected.to be_running }
    end

    describe file("#{mod_dir}/deflate.conf") do
      it { is_expected.to contain "AddOutputFilterByType DEFLATE text/html text/plain text/xml" }
      it { is_expected.to contain "AddOutputFilterByType DEFLATE text/css" }
      it { is_expected.to contain "AddOutputFilterByType DEFLATE application/x-javascript application/javascript application/ecmascript" }
      it { is_expected.to contain "AddOutputFilterByType DEFLATE application/rss+xml" }
      it { is_expected.to contain "DeflateFilterNote Input instream" }
      it { is_expected.to contain "DeflateFilterNote Output outstream" }
      it { is_expected.to contain "DeflateFilterNote Ratio ratio" }
    end
  end
end
require 'spec_helper_acceptance'

describe 'apache::mod::fcgid class', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
  case fact('osfamily')
  when 'Debian'
    # Not implemented
  when 'RedHat'
    context "default fcgid config" do
      it 'succeeds in puppeting fcgid' do
        pp = <<-EOS
          class { 'epel': } # mod_fcgid lives in epel
          class { 'apache': }
          class { 'apache::mod::php': } # For /usr/bin/php-cgi
          class { 'apache::mod::fcgid':
            options => {
              'FcgidIPCDir'  => '/var/run/fcgidsock',
            },
          }
          apache::vhost { 'fcgid.example.com':
            port        => '80',
            docroot     => '/var/www/fcgid',
            directories => {
              path        => '/var/www/fcgid',
              options     => '+ExecCGI',
              addhandlers => {
                handler    => 'fcgid-script',
                extensions => '.php',
              },
              fcgiwrapper => {
                command => '/usr/bin/php-cgi',
                suffix  => '.php',
              }
            },
          }
          file { '/var/www/fcgid/index.php':
            ensure  => file,
            owner   => 'root',
            group   => 'root',
            content => "<?php echo 'Hello world'; ?>\\n",
          }
        EOS
        apply_manifest(pp, :catch_failures => true)
      end

      describe service('httpd') do
        it { is_expected.to be_enabled }
        it { is_expected.to be_running }
      end

      it 'should answer to fcgid.example.com' do
        shell("/usr/bin/curl -H 'Host: fcgid.example.com' 127.0.0.1:80") do |r|
          expect(r.stdout).to match(/^Hello world$/)
          expect(r.exit_code).to eq(0)
        end
      end

      it 'should run a php-cgi process' do
        shell("pgrep -u apache php-cgi", :acceptable_exit_codes => [0])
      end
    end
  end
end
require 'spec_helper_acceptance'

describe 'apache::mod::mime class', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
  case fact('osfamily')
  when 'Debian'
    mod_dir      = '/etc/apache2/mods-available'
    service_name = 'apache2'
  when 'RedHat'
    mod_dir      = '/etc/httpd/conf.d'
    service_name = 'httpd'
  when 'FreeBSD'
    mod_dir      = '/usr/local/etc/apache22/Modules'
    service_name = 'apache22'
  end

  context "default mime config" do
    it 'succeeds in puppeting mime' do
      pp= <<-EOS
        class { 'apache': }
        include apache::mod::mime
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe service(service_name) do
      it { is_expected.to be_enabled }
      it { is_expected.to be_running }
    end

    describe file("#{mod_dir}/mime.conf") do
      it { is_expected.to contain "AddType application/x-compress .Z" }
    end
  end
end
require 'spec_helper_acceptance'

describe 'apache::mod::negotiation class', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
  case fact('osfamily')
  when 'Debian'
    vhost_dir    = '/etc/apache2/sites-enabled'
    mod_dir      = '/etc/apache2/mods-available'
    service_name = 'apache2'
  when 'RedHat'
    vhost_dir    = '/etc/httpd/conf.d'
    mod_dir      = '/etc/httpd/conf.d'
    service_name = 'httpd'
  when 'FreeBSD'
    vhost_dir    = '/usr/local/etc/apache22/Vhosts'
    mod_dir      = '/usr/local/etc/apache22/Modules'
    service_name = 'apache22'
  end

  context "default negotiation config" do
    it 'succeeds in puppeting negotiation' do
      pp= <<-EOS
        class { '::apache': }
        class { '::apache::mod::negotiation': }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe file("#{$mod_dir}/negotiation.conf") do
      it { should contain "LanguagePriority en ca cs da de el eo es et fr he hr it ja ko ltz nl nn no pl pt pt-BR ru sv zh-CN zh-TW
ForceLanguagePriority Prefer Fallback" }
    end

    describe service(service_name) do
      it { should be_enabled }
      it { should be_running }
    end
  end

  context "with alternative force_language_priority" do
    it 'succeeds in puppeting negotiation' do
      pp= <<-EOS
        class { '::apache': }
        class { '::apache::mod::negotiation':
          force_language_priority => 'Prefer',
        }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe file("#{$mod_dir}/negotiation.conf") do
      it { should contain "ForceLanguagePriority Prefer" }
    end

    describe service(service_name) do
      it { should be_enabled }
      it { should be_running }
    end
  end

  context "with alternative language_priority" do
    it 'succeeds in puppeting negotiation' do
      pp= <<-EOS
        class { '::apache': }
        class { '::apache::mod::negotiation':
          language_priority => [ 'en', 'es' ],
        }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe file("#{$mod_dir}/negotiation.conf") do
      it { should contain "LanguagePriority en es" }
    end

    describe service(service_name) do
      it { should be_enabled }
      it { should be_running }
    end
  end
end
require 'spec_helper_acceptance'

describe 'apache::mod::pagespeed class', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
  case fact('osfamily')
  when 'Debian'
    vhost_dir    = '/etc/apache2/sites-enabled'
    mod_dir      = '/etc/apache2/mods-available'
    service_name = 'apache2'
  when 'RedHat'
    vhost_dir    = '/etc/httpd/conf.d'
    mod_dir      = '/etc/httpd/conf.d'
    service_name = 'httpd'
  when 'FreeBSD'
    vhost_dir    = '/usr/local/etc/apache22/Vhosts'
    mod_dir      = '/usr/local/etc/apache22/Modules'
    service_name = 'apache22'
  end

  context "default pagespeed config" do
    it 'succeeds in puppeting pagespeed' do
      pp= <<-EOS
        if $::osfamily == 'Debian' {
          class { 'apt': }

          apt::source { 'mod-pagespeed':
            key         => '7FAC5991',
            key_server  => 'pgp.mit.edu',
            location    => 'http://dl.google.com/linux/mod-pagespeed/deb/',
            release     => 'stable',
            repos       => 'main',
            include_src => false,
            before      => Class['apache'],
          } 
        } elsif $::osfamily == 'RedHat' {
         yumrepo { 'mod-pagespeed':
          baseurl  => "http://dl.google.com/linux/mod-pagespeed/rpm/stable/$::architecture",
            enabled  => 1,
            gpgcheck => 1,
            gpgkey   => 'https://dl-ssl.google.com/linux/linux_signing_key.pub',
            before   => Class['apache'],
          }
        }

        class { 'apache':
          mpm_module => 'prefork',
        }
        class { 'apache::mod::pagespeed':
          enable_filters  => ['remove_comments'],
          disable_filters => ['extend_cache'],
          forbid_filters  => ['rewrite_javascript'],
        }
        apache::vhost { 'pagespeed.example.com':
          port    => '80',
          docroot => '/var/www/pagespeed',
        }
        host { 'pagespeed.example.com': ip => '127.0.0.1', }
        file { '/var/www/pagespeed/index.html':
          ensure  => file,
          content => "<html>\n<!-- comment -->\n<body>\n<p>Hello World!</p>\n</body>\n</html>",
        }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe service(service_name) do
      it { is_expected.to be_enabled }
      it { is_expected.to be_running }
    end

    describe file("#{mod_dir}/pagespeed.conf") do
      it { is_expected.to contain "AddOutputFilterByType MOD_PAGESPEED_OUTPUT_FILTER text/html" }
      it { is_expected.to contain "ModPagespeedEnableFilters remove_comments" }
      it { is_expected.to contain "ModPagespeedDisableFilters extend_cache" }
      it { is_expected.to contain "ModPagespeedForbidFilters rewrite_javascript" }
    end

    it 'should answer to pagespeed.example.com and include <head/> and be stripped of comments by mod_pagespeed' do
      shell("/usr/bin/curl pagespeed.example.com:80") do |r|
        expect(r.stdout).to match(/<head\/>/)
        expect(r.stdout).not_to match(/<!-- comment -->/)
        expect(r.exit_code).to eq(0)
      end
    end
  end
end
require 'spec_helper_acceptance'

describe 'apache::mod::passenger class', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
  case fact('osfamily')
  when 'Debian'
    service_name = 'apache2'
    mod_dir = '/etc/apache2/mods-available/'
    conf_file = "#{mod_dir}passenger.conf"
    load_file = "#{mod_dir}passenger.load"

    case fact('operatingsystem')
    when 'Ubuntu'
      case fact('lsbdistrelease')
      when '10.04'
        passenger_root = '/usr'
        passenger_ruby = '/usr/bin/ruby'
      when '12.04'
        passenger_root = '/usr'
        passenger_ruby = '/usr/bin/ruby'
      when '14.04'
        passenger_root         = '/usr/lib/ruby/vendor_ruby/phusion_passenger/locations.ini'
        passenger_ruby         = '/usr/bin/ruby'
        passenger_default_ruby = '/usr/bin/ruby'
      else
        # This may or may not work on Ubuntu releases other than the above
        passenger_root = '/usr'
        passenger_ruby = '/usr/bin/ruby'
      end
    when 'Debian'
      case fact('lsbdistcodename')
      when 'wheezy'
        passenger_root = '/usr'
        passenger_ruby = '/usr/bin/ruby'
      else
        # This may or may not work on Debian releases other than the above
        passenger_root = '/usr'
        passenger_ruby = '/usr/bin/ruby'
      end
    end

    passenger_module_path = '/usr/lib/apache2/modules/mod_passenger.so'
    rackapp_user = 'www-data'
    rackapp_group = 'www-data'
  when 'RedHat'
    service_name = 'httpd'
    mod_dir = '/etc/httpd/conf.d/'
    conf_file = "#{mod_dir}passenger.conf"
    load_file = "#{mod_dir}passenger.load"
    # sometimes installs as 3.0.12, sometimes as 3.0.19 - so just check for the stable part
    passenger_root = '/usr/lib/ruby/gems/1.8/gems/passenger-3.0.1'
    passenger_ruby = '/usr/bin/ruby'
    passenger_tempdir = '/var/run/rubygem-passenger'
    passenger_module_path = 'modules/mod_passenger.so'
    rackapp_user = 'apache'
    rackapp_group = 'apache'
  end

  pp_rackapp = <<-EOS
          /* a simple ruby rack 'hellow world' app */
          file { '/var/www/passenger':
            ensure  => directory,
            owner   => '#{rackapp_user}',
            group   => '#{rackapp_group}',
            require => Class['apache::mod::passenger'],
          }
          file { '/var/www/passenger/config.ru':
            ensure  => file,
            owner   => '#{rackapp_user}',
            group   => '#{rackapp_group}',
            content => "app = proc { |env| [200, { \\"Content-Type\\" => \\"text/html\\" }, [\\"hello <b>world</b>\\"]] }\\nrun app",
            require => File['/var/www/passenger'] ,
          }
          apache::vhost { 'passenger.example.com':
            port    => '80',
            docroot => '/var/www/passenger/public',
            docroot_group => '#{rackapp_group}' ,
            docroot_owner => '#{rackapp_user}' ,
            custom_fragment => "PassengerRuby  #{passenger_ruby}\\nRailsEnv  development" ,
            require => File['/var/www/passenger/config.ru'] ,
          }
          host { 'passenger.example.com': ip => '127.0.0.1', }
  EOS

  case fact('osfamily')
  when 'Debian'
    context "default passenger config" do
      it 'succeeds in puppeting passenger' do
        pp = <<-EOS
          /* stock apache and mod_passenger */
          class { 'apache': }
          class { 'apache::mod::passenger': }
          #{pp_rackapp}
        EOS
        apply_manifest(pp, :catch_failures => true)
      end

      describe service(service_name) do
        it { is_expected.to be_enabled }
        it { is_expected.to be_running }
      end

      describe file(conf_file) do
        it { is_expected.to contain "PassengerRoot \"#{passenger_root}\"" }

        case fact('operatingsystem')
        when 'Ubuntu'
          case fact('lsbdistrelease')
          when '10.04'
            it { is_expected.to contain "PassengerRuby \"#{passenger_ruby}\"" }
            it { is_expected.not_to contain "/PassengerDefaultRuby/" }
          when '12.04'
            it { is_expected.to contain "PassengerRuby \"#{passenger_ruby}\"" }
            it { is_expected.not_to contain "/PassengerDefaultRuby/" }
          when '14.04'
            it { is_expected.to contain "PassengerDefaultRuby \"#{passenger_ruby}\"" }
            it { is_expected.not_to contain "/PassengerRuby/" }
          else
            # This may or may not work on Ubuntu releases other than the above
            it { is_expected.to contain "PassengerRuby \"#{passenger_ruby}\"" }
            it { is_expected.not_to contain "/PassengerDefaultRuby/" }
          end
        when 'Debian'
          case fact('lsbdistcodename')
          when 'wheezy'
            it { is_expected.to contain "PassengerRuby \"#{passenger_ruby}\"" }
            it { is_expected.not_to contain "/PassengerDefaultRuby/" }
          else
            # This may or may not work on Debian releases other than the above
            it { is_expected.to contain "PassengerRuby \"#{passenger_ruby}\"" }
            it { is_expected.not_to contain "/PassengerDefaultRuby/" }
          end
        end
      end

      describe file(load_file) do
        it { is_expected.to contain "LoadModule passenger_module #{passenger_module_path}" }
      end

      it 'should output status via passenger-memory-stats' do
        shell("sudo /usr/sbin/passenger-memory-stats") do |r|
          expect(r.stdout).to match(/Apache processes/)
          expect(r.stdout).to match(/Nginx processes/)
          expect(r.stdout).to match(/Passenger processes/)

          # passenger-memory-stats output on Ubuntu 14.04 does not contain
          # these two lines
          unless fact('operatingsystem') == 'Ubuntu' && fact('operatingsystemrelease') == '14.04'
            expect(r.stdout).to match(/### Processes: [0-9]+/)
            expect(r.stdout).to match(/### Total private dirty RSS: [0-9\.]+ MB/)
          end

          expect(r.exit_code).to eq(0)
        end
      end

      # passenger-status fails under stock ubuntu-server-12042-x64 + mod_passenger,
      # even when the passenger process is successfully installed and running
      unless fact('operatingsystem') == 'Ubuntu' && fact('operatingsystemrelease') == '12.04'
        it 'should output status via passenger-status' do
          # xml output not available on ubunutu <= 10.04, so sticking with default pool output
          shell("/usr/sbin/passenger-status") do |r|
            # spacing may vary
            expect(r.stdout).to match(/[\-]+ General information [\-]+/)
            if fact('operatingsystem') == 'Ubuntu' && fact('operatingsystemrelease') == '14.04'
              expect(r.stdout).to match(/Max pool size[ ]+: [0-9]+/)
              expect(r.stdout).to match(/Processes[ ]+: [0-9]+/)
              expect(r.stdout).to match(/Requests in top-level queue[ ]+: [0-9]+/)
            else
              expect(r.stdout).to match(/max[ ]+= [0-9]+/)
              expect(r.stdout).to match(/count[ ]+= [0-9]+/)
              expect(r.stdout).to match(/active[ ]+= [0-9]+/)
              expect(r.stdout).to match(/inactive[ ]+= [0-9]+/)
              expect(r.stdout).to match(/Waiting on global queue: [0-9]+/)
            end

            expect(r.exit_code).to eq(0)
          end
        end
      end

      it 'should answer to passenger.example.com' do
        shell("/usr/bin/curl passenger.example.com:80") do |r|
          expect(r.stdout).to match(/^hello <b>world<\/b>$/)
          expect(r.exit_code).to eq(0)
        end
      end

    end

  when 'RedHat'
    # no fedora 18 passenger package yet, and rhel5 packages only exist for ruby 1.8.5
    unless (fact('operatingsystem') == 'Fedora' and fact('operatingsystemrelease').to_f >= 18) or (fact('osfamily') == 'RedHat' and fact('operatingsystemmajrelease') == '5' and fact('rubyversion') != '1.8.5')

      if fact('operatingsystem') == 'RedHat' and fact('operatingsystemmajrelease') == '7'
        pending('test passenger - RHEL7 packages don\'t exist')
      else
        context "default passenger config" do
          it 'succeeds in puppeting passenger' do
            pp = <<-EOS
              /* EPEL and passenger repositories */
              class { 'epel': }
              exec { 'passenger.repo GPG key':
                command => '/usr/bin/curl -o /etc/yum.repos.d/RPM-GPG-KEY-stealthymonkeys.asc http://passenger.stealthymonkeys.com/RPM-GPG-KEY-stealthymonkeys.asc',
                creates => '/etc/yum.repos.d/RPM-GPG-KEY-stealthymonkeys.asc',
              }
              file { 'passenger.repo GPG key':
                ensure  => file,
                path    => '/etc/yum.repos.d/RPM-GPG-KEY-stealthymonkeys.asc',
                require => Exec['passenger.repo GPG key'],
              }
              epel::rpm_gpg_key { 'passenger.stealthymonkeys.com':
                path    => '/etc/yum.repos.d/RPM-GPG-KEY-stealthymonkeys.asc',
                require => [
                  Class['epel'],
                  File['passenger.repo GPG key'],
                ]
              }
              $releasever_string = $operatingsystem ? {
                'Scientific' => '6',
                default      => '$releasever',
              }
              yumrepo { 'passenger':
                baseurl         => "http://passenger.stealthymonkeys.com/rhel/${releasever_string}/\\$basearch" ,
                descr           => "Red Hat Enterprise ${releasever_string} - Phusion Passenger",
                enabled         => 1,
                gpgcheck        => 1,
                gpgkey          => 'http://passenger.stealthymonkeys.com/RPM-GPG-KEY-stealthymonkeys.asc',
                mirrorlist      => 'http://passenger.stealthymonkeys.com/rhel/mirrors',
                require => [
                  Epel::Rpm_gpg_key['passenger.stealthymonkeys.com'],
                ],
              }
              /* apache and mod_passenger */
              class { 'apache':
                  require => [
                    Class['epel'],
                ],
              }
              class { 'apache::mod::passenger':
                require => [
                  Yumrepo['passenger']
                ],
              }
              #{pp_rackapp}
            EOS
            apply_manifest(pp, :catch_failures => true)
          end

          describe service(service_name) do
            it { is_expected.to be_enabled }
            it { is_expected.to be_running }
          end

          describe file(conf_file) do
            it { is_expected.to contain "PassengerRoot #{passenger_root}" }
            it { is_expected.to contain "PassengerRuby #{passenger_ruby}" }
            it { is_expected.to contain "PassengerTempDir #{passenger_tempdir}" }
          end

          describe file(load_file) do
            it { is_expected.to contain "LoadModule passenger_module #{passenger_module_path}" }
          end

          it 'should output status via passenger-memory-stats' do
            shell("sudo /usr/bin/passenger-memory-stats") do |r|
              expect(r.stdout).to match(/Apache processes/)
              expect(r.stdout).to match(/Nginx processes/)
              expect(r.stdout).to match(/Passenger processes/)
              expect(r.stdout).to match(/### Processes: [0-9]+/)
              expect(r.stdout).to match(/### Total private dirty RSS: [0-9\.]+ MB/)

              expect(r.exit_code).to eq(0)
            end
          end

          it 'should output status via passenger-status' do
            shell("PASSENGER_TMPDIR=/var/run/rubygem-passenger /usr/bin/passenger-status") do |r|
              # spacing may vary
              r.stdout.should =~ /[\-]+ General information [\-]+/
              r.stdout.should =~ /max[ ]+= [0-9]+/
              r.stdout.should =~ /count[ ]+= [0-9]+/
              r.stdout.should =~ /active[ ]+= [0-9]+/
              r.stdout.should =~ /inactive[ ]+= [0-9]+/
              r.stdout.should =~ /Waiting on global queue: [0-9]+/

              r.exit_code.should == 0
            end
          end

          it 'should answer to passenger.example.com' do
            shell("/usr/bin/curl passenger.example.com:80") do |r|
              r.stdout.should =~ /^hello <b>world<\/b>$/
              r.exit_code.should == 0
            end
          end
        end
      end
    end
  end
end
require 'spec_helper_acceptance'

describe 'apache::mod::php class', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
  case fact('osfamily')
  when 'Debian'
    vhost_dir    = '/etc/apache2/sites-enabled'
    mod_dir      = '/etc/apache2/mods-available'
    service_name = 'apache2'
  when 'RedHat'
    vhost_dir    = '/etc/httpd/conf.d'
    mod_dir      = '/etc/httpd/conf.d'
    service_name = 'httpd'
  when 'FreeBSD'
    vhost_dir    = '/usr/local/etc/apache22/Vhosts'
    mod_dir      = '/usr/local/etc/apache22/Modules'
    service_name = 'apache22'
  end

  context "default php config" do
    it 'succeeds in puppeting php' do
      pp= <<-EOS
        class { 'apache':
          mpm_module => 'prefork',
        }
        class { 'apache::mod::php': }
        apache::vhost { 'php.example.com':
          port    => '80',
          docroot => '/var/www/php',
        }
        host { 'php.example.com': ip => '127.0.0.1', }
        file { '/var/www/php/index.php':
          ensure  => file,
          content => "<?php phpinfo(); ?>\\n",
        }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe service(service_name) do
      it { is_expected.to be_enabled }
      it { is_expected.to be_running }
    end

    describe file("#{mod_dir}/php5.conf") do
      it { is_expected.to contain "DirectoryIndex index.php" }
    end

    it 'should answer to php.example.com' do
      shell("/usr/bin/curl php.example.com:80") do |r|
        expect(r.stdout).to match(/PHP Version/)
        expect(r.exit_code).to eq(0)
      end
    end
  end

  context "custom extensions, php_admin_flag, and php_admin_value" do
    it 'succeeds in puppeting php' do
      pp= <<-EOS
        class { 'apache':
          mpm_module => 'prefork',
        }
        class { 'apache::mod::php':
          extensions => ['.php','.php5'],
        }
        apache::vhost { 'php.example.com':
          port             => '80',
          docroot          => '/var/www/php',
          php_admin_values => { 'open_basedir' => '/var/www/php/:/usr/share/pear/', },
          php_admin_flags  => { 'engine' => 'on', },
        }
        host { 'php.example.com': ip => '127.0.0.1', }
        file { '/var/www/php/index.php5':
          ensure  => file,
          content => "<?php phpinfo(); ?>\\n",
        }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe service(service_name) do
      it { is_expected.to be_enabled }
      it { is_expected.to be_running }
    end

    describe file("#{vhost_dir}/25-php.example.com.conf") do
      it { is_expected.to contain "  php_admin_flag engine on" }
      it { is_expected.to contain "  php_admin_value open_basedir /var/www/php/:/usr/share/pear/" }
    end

    it 'should answer to php.example.com' do
      shell("/usr/bin/curl php.example.com:80") do |r|
        expect(r.stdout).to match(/\/usr\/share\/pear\//)
        expect(r.exit_code).to eq(0)
      end
    end
  end

  context "provide custom config file" do
    it 'succeeds in puppeting php' do
      pp= <<-EOS
        class {'apache':
          mpm_module => 'prefork',
        }
        class {'apache::mod::php':
          content => '# somecontent',
        }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe file("#{mod_dir}/php5.conf") do
      it { should contain "# somecontent" }
    end
  end

  context "provide content and template config file" do
    it 'succeeds in puppeting php' do
      pp= <<-EOS
        class {'apache':
          mpm_module => 'prefork',
        }
        class {'apache::mod::php':
          content  => '# somecontent',
          template => 'apache/mod/php5.conf.erb',
        }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe file("#{mod_dir}/php5.conf") do
      it { should contain "# somecontent" }
    end
  end

  context "provide source has priority over content" do
    it 'succeeds in puppeting php' do
      pp= <<-EOS
        class {'apache':
          mpm_module => 'prefork',
        }
        class {'apache::mod::php':
          content => '# somecontent',
          source  => 'puppet:///modules/apache/spec',
        }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe file("#{mod_dir}/php5.conf") do
      it { should contain "# This is a file only for spec testing" }
    end
  end

  context "provide source has priority over template" do
    it 'succeeds in puppeting php' do
      pp= <<-EOS
        class {'apache':
          mpm_module => 'prefork',
        }
        class {'apache::mod::php':
          template => 'apache/mod/php5.conf.erb',
          source   => 'puppet:///modules/apache/spec',
        }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe file("#{mod_dir}/php5.conf") do
      it { should contain "# This is a file only for spec testing" }
    end
  end

end
require 'spec_helper_acceptance'

describe 'apache::mod::proxy_html class', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
  case fact('osfamily')
  when 'Debian'
    service_name = 'apache2'
  when 'RedHat'
    service_name = 'httpd'
  when 'FreeBSD'
    service_name = 'apache22'
  end

  context "default proxy_html config" do
    if fact('osfamily') == 'RedHat' and fact('operatingsystemmajrelease') =~ /(5|6)/
      it 'adds epel' do
        pp = "class { 'epel': }"
        apply_manifest(pp, :catch_failures => true)
      end
    end

    it 'succeeds in puppeting proxy_html' do
      pp= <<-EOS
        class { 'apache': }
        class { 'apache::mod::proxy': }
        class { 'apache::mod::proxy_http': }
        # mod_proxy_html doesn't exist in RHEL5
        if $::osfamily == 'RedHat' and $::operatingsystemmajrelease != '5' {
          class { 'apache::mod::proxy_html': }
        }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe service(service_name) do
      it { is_expected.to be_enabled }
      it { is_expected.to be_running }
    end
  end
end
require 'spec_helper_acceptance'

describe 'apache::mod::suphp class', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
  case fact('osfamily')
  when 'Debian'
    context "default suphp config" do
      it 'succeeds in puppeting suphp' do
        pp = <<-EOS
          class { 'apache':
            mpm_module => 'prefork',
          }
          class { 'apache::mod::php': }
          class { 'apache::mod::suphp': }
          apache::vhost { 'suphp.example.com':
            port    => '80',
            docroot => '/var/www/suphp',
          }
          host { 'suphp.example.com': ip => '127.0.0.1', }
          file { '/var/www/suphp/index.php':
            ensure  => file,
            owner   => 'daemon',
            group   => 'daemon',
            content => "<?php echo get_current_user(); ?>\\n",
          }
        EOS
        apply_manifest(pp, :catch_failures => true)
      end

      describe service('apache2') do
        it { is_expected.to be_enabled }
        it { is_expected.to be_running }
      end

      it 'should answer to suphp.example.com' do
        shell("/usr/bin/curl suphp.example.com:80") do |r|
          expect(r.stdout).to match(/^daemon$/)
          expect(r.exit_code).to eq(0)
        end
      end
    end
  when 'RedHat'
    # Not implemented yet
  end
end
HOSTS:
  centos-59-x64:
    roles:
      - master
    platform: el-5-x86_64
    box : centos-59-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-59-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: git
HOSTS:
  centos-64-x64:
    roles:
      - master
      - database
      - dashboard
    platform: el-6-x86_64
    box : centos-64-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: pe
HOSTS:
  centos-64-x64:
    roles:
      - master
    platform: el-6-x86_64
    box : centos-64-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  log_level: debug
  type: git
HOSTS:
  centos-65-x64:
    roles:
      - master
    platform: el-6-x86_64
    box : centos-65-x64-vbox436-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-65-x64-virtualbox-nocm.box
    hypervisor : vagrant
CONFIG:
  type: foss
HOSTS:
  debian-607-x64:
    roles:
      - master
    platform: debian-6-amd64
    box : debian-607-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/debian-607-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  log_level: debug
  type: git
HOSTS:
  debian-70rc1-x64:
    roles:
      - master
    platform: debian-7-amd64
    box : debian-70rc1-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/debian-70rc1-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  log_level: debug
  type: git
HOSTS:
  debian-73-i386:
    roles:
      - master
    platform: debian-7-i386
    box : debian-73-i386-virtualbox-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/debian-73-i386-virtualbox-nocm.box
    hypervisor : vagrant
CONFIG:
  log_level: debug
  type: git
HOSTS:
  debian-73-x64:
    roles:
      - master
    platform: debian-7-amd64
    box : debian-73-x64-virtualbox-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/debian-73-x64-virtualbox-nocm.box
    hypervisor : vagrant
CONFIG:
  log_level: debug
  type: git
HOSTS:
  centos-64-x64:
    roles:
      - master
    platform: el-6-x86_64
    box : centos-64-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  log_level: debug
  type: git
HOSTS:
  fedora-18-x64:
    roles:
      - master
    platform: fedora-18-x86_64
    box : fedora-18-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/fedora-18-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  log_level: debug
  type: git
HOSTS:
  sles-11sp1-x64:
    roles:
      - master
    platform: sles-11-x86_64
    box : sles-11sp1-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/sles-11sp1-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  log_level: debug
  type: git
HOSTS:
  ubuntu-server-10044-x64:
    roles:
      - master
    platform: ubuntu-10.04-amd64
    box : ubuntu-server-10044-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/ubuntu-server-10044-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: foss
HOSTS:
  ubuntu-server-12042-x64:
    roles:
      - master
    platform: ubuntu-12.04-amd64
    box : ubuntu-server-12042-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/ubuntu-server-12042-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: foss
HOSTS:
  ubuntu-server-1310-x64:
    roles:
      - master
    platform: ubuntu-13.10-amd64
    box : ubuntu-server-1310-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/ubuntu-1310-x64-virtualbox-nocm.box
    hypervisor : vagrant
CONFIG:
  log_level   : debug
  type: git
HOSTS:
  ubuntu-server-1404-x64:
    roles:
      - master
    platform: ubuntu-14.04-amd64
    box : puppetlabs/ubuntu-14.04-64-nocm
    box_url : https://vagrantcloud.com/puppetlabs/ubuntu-14.04-64-nocm
    hypervisor : vagrant
CONFIG:
  log_level   : debug
  type: git
require 'spec_helper_acceptance'

case fact('osfamily')
when 'RedHat'
  servicename = 'httpd'
when 'Debian'
  servicename = 'apache2'
when 'FreeBSD'
  servicename = 'apache22'
end

case fact('osfamily')
when 'FreeBSD'
  describe 'apache::mod::event class' do
    describe 'running puppet code' do
      # Using puppet_apply as a helper
      it 'should work with no errors' do
        pp = <<-EOS
          class { 'apache':
            mpm_module => 'event',
          }
        EOS

        # Run it twice and test for idempotency
        apply_manifest(pp, :catch_failures => true)
        expect(apply_manifest(pp, :catch_failures => true).exit_code).to be_zero
      end
    end

    describe service(servicename) do
      it { is_expected.to be_running }
      it { is_expected.to be_enabled }
    end
  end
end

describe 'apache::mod::worker class', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
  describe 'running puppet code' do
    # Using puppet_apply as a helper
    it 'should work with no errors' do
      pp = <<-EOS
        class { 'apache':
          mpm_module => 'worker',
        }
      EOS

      # Run it twice and test for idempotency
      apply_manifest(pp, :catch_failures => true)
      expect(apply_manifest(pp, :catch_failures => true).exit_code).to be_zero
    end
  end

  describe service(servicename) do
    it { is_expected.to be_running }
    it { is_expected.to be_enabled }
  end
end

describe 'apache::mod::prefork class', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
  describe 'running puppet code' do
    # Using puppet_apply as a helper
    it 'should work with no errors' do
      pp = <<-EOS
        class { 'apache':
          mpm_module => 'prefork',
        }
      EOS

      # Run it twice and test for idempotency
      apply_manifest(pp, :catch_failures => true)
      expect(apply_manifest(pp, :catch_failures => true).exit_code).to be_zero
    end
  end

  describe service(servicename) do
    it { is_expected.to be_running }
    it { is_expected.to be_enabled }
  end
end
require 'spec_helper_acceptance'

describe 'apache::service class', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
  describe 'adding dependencies in between the base class and service class' do
    it 'should work with no errors' do
      pp = <<-EOS
      class { 'apache': }
      file { '/tmp/test':
        require => Class['apache'],
        notify  => Class['apache::service'],
      }
      EOS

      # Run it twice and test for idempotency
      apply_manifest(pp, :catch_failures => true)
      expect(apply_manifest(pp, :catch_failures => true).exit_code).to be_zero
    end
  end
end
require 'spec_helper_acceptance'

describe 'unsupported distributions and OSes', :if => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
  it 'should fail' do
    pp = <<-EOS
      class { 'apache': }
      apache::vhost { 'test.lan':
        docroot => '/var/www',
      }
    EOS
    expect(apply_manifest(pp, :expect_failures => true).stderr).to match(/unsupported/i)
  end
end
_osfamily               = fact('osfamily')
_operatingsystem        = fact('operatingsystem')
_operatingsystemrelease = fact('operatingsystemrelease').to_f

case _osfamily
when 'RedHat'
  $confd_dir        = '/etc/httpd/conf.d'
  $conf_file        = '/etc/httpd/conf/httpd.conf'
  $ports_file       = '/etc/httpd/conf/ports.conf'
  $vhost_dir        = '/etc/httpd/conf.d'
  $vhost            = '/etc/httpd/conf.d/15-default.conf'
  $run_dir          = '/var/run/httpd'
  $service_name     = 'httpd'
  $package_name     = 'httpd'
  $error_log        = 'error_log'
  $suphp_handler    = 'php5-script'
  $suphp_configpath = 'undef'

  if (_operatingsystem == 'Fedora' and _operatingsystemrelease >= 18) or (_operatingsystem != 'Fedora' and _operatingsystemrelease >= 7)
    $apache_version = '2.4'
  else
    $apache_version = '2.2'
  end
when 'Debian'
  $confd_dir        = '/etc/apache2/mods-available'
  $conf_file        = '/etc/apache2/apache2.conf'
  $ports_file       = '/etc/apache2/ports.conf'
  $vhost            = '/etc/apache2/sites-available/15-default.conf'
  $vhost_dir        = '/etc/apache2/sites-enabled'
  $run_dir          = '/var/run/apache2'
  $service_name     = 'apache2'
  $package_name     = 'apache2'
  $error_log        = 'error.log'
  $suphp_handler    = 'x-httpd-php'
  $suphp_configpath = '/etc/php5/apache2'

  if _operatingsystem == 'Ubuntu' and _operatingsystemrelease >= 13.10
    $apache_version = '2.4'
  else
    $apache_version = '2.2'
  end
when 'FreeBSD'
  $confd_dir        = '/usr/local/etc/apache22/Includes'
  $conf_file        = '/usr/local/etc/apache22/httpd.conf'
  $ports_file       = '/usr/local/etc/apache22/Includes/ports.conf'
  $vhost            = '/usr/local/etc/apache22/Vhosts/15-default.conf'
  $vhost_dir        = '/usr/local/etc/apache22/Vhosts'
  $run_dir          = '/var/run/apache22'
  $service_name     = 'apache22'
  $package_name     = 'apache22'
  $error_log        = 'http-error.log'

  $apache_version = '2.2'
else
  $apache_version = '0'
end

require 'spec_helper_acceptance'
require_relative './version.rb'

describe 'apache::vhost define', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
  context 'no default vhosts' do
    it 'should create no default vhosts' do
      pp = <<-EOS
        class { 'apache':
          default_vhost => false,
          default_ssl_vhost => false,
          service_ensure => stopped
        }
      EOS

      apply_manifest(pp, :catch_failures => true)
    end

    describe file("#{$vhost_dir}/15-default.conf") do
      it { is_expected.not_to be_file }
    end

    describe file("#{$vhost_dir}/15-default-ssl.conf") do
      it { is_expected.not_to be_file }
    end
  end

  context "default vhost without ssl" do
    it 'should create a default vhost config' do
      pp = <<-EOS
        class { 'apache': }
      EOS

      apply_manifest(pp, :catch_failures => true)
    end

    describe file("#{$vhost_dir}/15-default.conf") do
      it { is_expected.to contain '<VirtualHost \*:80>' }
    end

    describe file("#{$vhost_dir}/15-default-ssl.conf") do
      it { is_expected.not_to be_file }
    end
  end

  context 'default vhost with ssl' do
    it 'should create default vhost configs' do
      pp = <<-EOS
        file { '#{$run_dir}':
          ensure  => 'directory',
          recurse => true,
        }

        class { 'apache':
          default_ssl_vhost => true,
          require => File['#{$run_dir}'],
        }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe file("#{$vhost_dir}/15-default.conf") do
      it { is_expected.to contain '<VirtualHost \*:80>' }
    end

    describe file("#{$vhost_dir}/15-default-ssl.conf") do
      it { is_expected.to contain '<VirtualHost \*:443>' }
      it { is_expected.to contain "SSLEngine on" }
    end
  end

  context 'new vhost on port 80' do
    it 'should configure an apache vhost' do
      pp = <<-EOS
        class { 'apache': }
        file { '#{$run_dir}':
          ensure  => 'directory',
          recurse => true,
        }

        apache::vhost { 'first.example.com':
          port    => '80',
          docroot => '/var/www/first',
          require => File['#{$run_dir}'],
        }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe file("#{$vhost_dir}/25-first.example.com.conf") do
      it { is_expected.to contain '<VirtualHost \*:80>' }
      it { is_expected.to contain "ServerName first.example.com" }
    end
  end

  context 'new proxy vhost on port 80' do
    it 'should configure an apache proxy vhost' do
      pp = <<-EOS
        class { 'apache': }
        apache::vhost { 'proxy.example.com':
          port    => '80',
          docroot => '/var/www/proxy',
          proxy_pass => [
            { 'path' => '/foo', 'url' => 'http://backend-foo/'},
          ],
        proxy_preserve_host   => true,
        }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe file("#{$vhost_dir}/25-proxy.example.com.conf") do
      it { is_expected.to contain '<VirtualHost \*:80>' }
      it { is_expected.to contain "ServerName proxy.example.com" }
      it { is_expected.to contain "ProxyPass" }
      it { is_expected.to contain "ProxyPreserveHost On" }
      it { is_expected.not_to contain "<Proxy \*>" }
    end
  end

  context 'new vhost on port 80' do
    it 'should configure two apache vhosts' do
      pp = <<-EOS
        class { 'apache': }
        apache::vhost { 'first.example.com':
          port    => '80',
          docroot => '/var/www/first',
        }
        host { 'first.example.com': ip => '127.0.0.1', }
        file { '/var/www/first/index.html':
          ensure  => file,
          content => "Hello from first\\n",
        }
        apache::vhost { 'second.example.com':
          port    => '80',
          docroot => '/var/www/second',
        }
        host { 'second.example.com': ip => '127.0.0.1', }
        file { '/var/www/second/index.html':
          ensure  => file,
          content => "Hello from second\\n",
        }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe service($service_name) do
      it { is_expected.to be_enabled }
      it { is_expected.to be_running }
    end

    it 'should answer to first.example.com' do
      shell("/usr/bin/curl first.example.com:80", {:acceptable_exit_codes => 0}) do |r|
        expect(r.stdout).to eq("Hello from first\n")
      end
    end

    it 'should answer to second.example.com' do
      shell("/usr/bin/curl second.example.com:80", {:acceptable_exit_codes => 0}) do |r|
        expect(r.stdout).to eq("Hello from second\n")
      end
    end
  end

  context 'apache_directories' do
    describe 'readme example, adapted' do
      it 'should configure a vhost with Files' do
        pp = <<-EOS
          class { 'apache': }

          if versioncmp($apache::apache_version, '2.4') >= 0 {
            $_files_match_directory = { 'path' => '(\.swp|\.bak|~)$', 'provider' => 'filesmatch', 'require' => 'all denied', }
          } else {
            $_files_match_directory = { 'path' => '(\.swp|\.bak|~)$', 'provider' => 'filesmatch', 'deny' => 'from all', }
          }

          $_directories = [
            { 'path' => '/var/www/files', },
            $_files_match_directory,
          ]

          apache::vhost { 'files.example.net':
            docroot     => '/var/www/files',
            directories => $_directories,
          }
          file { '/var/www/files/index.html':
            ensure  => file,
            content => "Hello World\\n",
          }
          file { '/var/www/files/index.html.bak':
            ensure  => file,
            content => "Hello World\\n",
          }
          host { 'files.example.net': ip => '127.0.0.1', }
        EOS
        apply_manifest(pp, :catch_failures => true)
      end

      describe service($service_name) do
        it { is_expected.to be_enabled }
        it { is_expected.to be_running }
      end

      it 'should answer to files.example.net' do
        expect(shell("/usr/bin/curl -sSf files.example.net:80/index.html").stdout).to eq("Hello World\n")
        expect(shell("/usr/bin/curl -sSf files.example.net:80/index.html.bak", {:acceptable_exit_codes => 22}).stderr).to match(/curl: \(22\) The requested URL returned error: 403/)
      end
    end

    describe 'other Directory options' do
      it 'should configure a vhost with multiple Directory sections' do
        pp = <<-EOS
          class { 'apache': }

          if versioncmp($apache::apache_version, '2.4') >= 0 {
            $_files_match_directory = { 'path' => 'private.html$', 'provider' => 'filesmatch', 'require' => 'all denied' }
          } else {
            $_files_match_directory = [
              { 'path' => 'private.html$', 'provider' => 'filesmatch', 'deny' => 'from all' },
              { 'path' => '/bar/bar.html', 'provider' => 'location', allow => [ 'from 127.0.0.1', ] },
            ]
          }

          $_directories = [
            { 'path' => '/var/www/files', },
            { 'path' => '/foo/', 'provider' => 'location', 'directoryindex' => 'notindex.html', },
            $_files_match_directory,
          ]

          apache::vhost { 'files.example.net':
            docroot     => '/var/www/files',
            directories => $_directories,
          }
          file { '/var/www/files/foo':
            ensure => directory,
          }
          file { '/var/www/files/foo/notindex.html':
            ensure  => file,
            content => "Hello Foo\\n",
          }
          file { '/var/www/files/private.html':
            ensure  => file,
            content => "Hello World\\n",
          }
          file { '/var/www/files/bar':
            ensure => directory,
          }
          file { '/var/www/files/bar/bar.html':
            ensure  => file,
            content => "Hello Bar\\n",
          }
          host { 'files.example.net': ip => '127.0.0.1', }
        EOS
        apply_manifest(pp, :catch_failures => true)
      end

      describe service($service_name) do
        it { is_expected.to be_enabled }
        it { is_expected.to be_running }
      end

      it 'should answer to files.example.net' do
        expect(shell("/usr/bin/curl -sSf files.example.net:80/").stdout).to eq("Hello World\n")
        expect(shell("/usr/bin/curl -sSf files.example.net:80/foo/").stdout).to eq("Hello Foo\n")
        expect(shell("/usr/bin/curl -sSf files.example.net:80/private.html", {:acceptable_exit_codes => 22}).stderr).to match(/curl: \(22\) The requested URL returned error: 403/)
        expect(shell("/usr/bin/curl -sSf files.example.net:80/bar/bar.html").stdout).to eq("Hello Bar\n")
      end
    end

    describe 'SetHandler directive' do
      it 'should configure a vhost with a SetHandler directive' do
        pp = <<-EOS
          class { 'apache': }
          apache::mod { 'status': }
          host { 'files.example.net': ip => '127.0.0.1', }
          apache::vhost { 'files.example.net':
            docroot     => '/var/www/files',
            directories => [
              { path => '/var/www/files', },
              { path => '/server-status', provider => 'location', sethandler => 'server-status', },
            ],
          }
          file { '/var/www/files/index.html':
            ensure  => file,
            content => "Hello World\\n",
          }
        EOS
        apply_manifest(pp, :catch_failures => true)
      end

      describe service($service_name) do
        it { is_expected.to be_enabled }
        it { is_expected.to be_running }
      end

      it 'should answer to files.example.net' do
        expect(shell("/usr/bin/curl -sSf files.example.net:80/index.html").stdout).to eq("Hello World\n")
        expect(shell("/usr/bin/curl -sSf files.example.net:80/server-status?auto").stdout).to match(/Scoreboard: /)
      end
    end

    describe 'Satisfy and Auth directive' do
      it 'should configure a vhost with Satisfy and Auth directive' do
        pp = <<-EOS
          class { 'apache': }
          host { 'files.example.net': ip => '127.0.0.1', }
          apache::vhost { 'files.example.net':
            docroot     => '/var/www/files',
            directories => [
              {
                path => '/var/www/files/foo',
                auth_type => 'Basic',
                auth_name => 'Basic Auth',
                auth_user_file => '/var/www/htpasswd',
                auth_require => "valid-user",
              },
              {
                path => '/var/www/files/bar',
                auth_type => 'Basic',
                auth_name => 'Basic Auth',
                auth_user_file => '/var/www/htpasswd',
                auth_require => 'valid-user',
                satisfy => 'Any',
              },
              {
                path => '/var/www/files/baz',
                allow => 'from 10.10.10.10',
                auth_type => 'Basic',
                auth_name => 'Basic Auth',
                auth_user_file => '/var/www/htpasswd',
                auth_require => 'valid-user',
                satisfy => 'Any',
              },
            ],
          }
          file { '/var/www/files/foo':
            ensure => directory,
          }
          file { '/var/www/files/bar':
            ensure => directory,
          }
          file { '/var/www/files/baz':
            ensure => directory,
          }
          file { '/var/www/files/foo/index.html':
            ensure  => file,
            content => "Hello World\\n",
          }
          file { '/var/www/files/bar/index.html':
            ensure  => file,
            content => "Hello World\\n",
          }
          file { '/var/www/files/baz/index.html':
            ensure  => file,
            content => "Hello World\\n",
          }
          file { '/var/www/htpasswd':
            ensure  => file,
            content => "login:IZ7jMcLSx0oQk", # "password" as password
          }
        EOS
        apply_manifest(pp, :catch_failures => true)
      end

      describe service($service_name) do
        it { should be_enabled }
        it { should be_running }
      end

      it 'should answer to files.example.net' do
        shell("/usr/bin/curl -sSf files.example.net:80/foo/index.html", {:acceptable_exit_codes => 22}).stderr.should match(/curl: \(22\) The requested URL returned error: 401/)
        shell("/usr/bin/curl -sSf -u login:password files.example.net:80/foo/index.html").stdout.should eq("Hello World\n")
        shell("/usr/bin/curl -sSf files.example.net:80/bar/index.html").stdout.should eq("Hello World\n")
        shell("/usr/bin/curl -sSf -u login:password files.example.net:80/bar/index.html").stdout.should eq("Hello World\n")
        shell("/usr/bin/curl -sSf files.example.net:80/baz/index.html", {:acceptable_exit_codes => 22}).stderr.should match(/curl: \(22\) The requested URL returned error: 401/)
        shell("/usr/bin/curl -sSf -u login:password files.example.net:80/baz/index.html").stdout.should eq("Hello World\n")
      end
    end
  end

  case fact('lsbdistcodename')
  when 'precise', 'wheezy'
    context 'vhost fallbackresouce example' do
      it 'should configure a vhost with Fallbackresource' do
        pp = <<-EOS
        class { 'apache': }
        apache::vhost { 'fallback.example.net':
          docroot         => '/var/www/fallback',
          fallbackresource => '/index.html'
        }
        file { '/var/www/fallback/index.html':
          ensure  => file,
          content => "Hello World\\n",
        }
        host { 'fallback.example.net': ip => '127.0.0.1', }
        EOS
        apply_manifest(pp, :catch_failures => true)
      end

      describe service($service_name) do
        it { is_expected.to be_enabled }
        it { is_expected.to be_running }
      end

      it 'should answer to fallback.example.net' do
        shell("/usr/bin/curl fallback.example.net:80/Does/Not/Exist") do |r|
          expect(r.stdout).to eq("Hello World\n")
        end
      end

    end
  else
    # The current stable RHEL release (6.4) comes with Apache httpd 2.2.15
    # That was released March 6, 2010.
    # FallbackResource was backported to 2.2.16, and released July 25, 2010.
    # Ubuntu Lucid (10.04) comes with apache2 2.2.14, released October 3, 2009.
    # https://svn.apache.org/repos/asf/httpd/httpd/branches/2.2.x/STATUS
  end

  context 'virtual_docroot hosting separate sites' do
    it 'should configure a vhost with VirtualDocumentRoot' do
      pp = <<-EOS
        class { 'apache': }
        apache::vhost { 'virt.example.com':
          vhost_name      => '*',
          serveraliases   => '*virt.example.com',
          port            => '80',
          docroot         => '/var/www/virt',
          virtual_docroot => '/var/www/virt/%1',
        }
        host { 'virt.example.com': ip => '127.0.0.1', }
        host { 'a.virt.example.com': ip => '127.0.0.1', }
        host { 'b.virt.example.com': ip => '127.0.0.1', }
        file { [ '/var/www/virt/a', '/var/www/virt/b', ]: ensure => directory, }
        file { '/var/www/virt/a/index.html': ensure  => file, content => "Hello from a.virt\\n", }
        file { '/var/www/virt/b/index.html': ensure  => file, content => "Hello from b.virt\\n", }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe service($service_name) do
      it { is_expected.to be_enabled }
      it { is_expected.to be_running }
    end

    it 'should answer to a.virt.example.com' do
      shell("/usr/bin/curl a.virt.example.com:80", {:acceptable_exit_codes => 0}) do |r|
        expect(r.stdout).to eq("Hello from a.virt\n")
      end
    end

    it 'should answer to b.virt.example.com' do
      shell("/usr/bin/curl b.virt.example.com:80", {:acceptable_exit_codes => 0}) do |r|
        expect(r.stdout).to eq("Hello from b.virt\n")
      end
    end
  end

  context 'proxy_pass for alternative vhost' do
    it 'should configure a local vhost and a proxy vhost' do
      apply_manifest(%{
        class { 'apache': default_vhost => false, }
        apache::vhost { 'localhost':
          docroot => '/var/www/local',
          ip      => '127.0.0.1',
          port    => '8888',
        }
        apache::listen { '*:80': }
        apache::vhost { 'proxy.example.com':
          docroot    => '/var/www',
          port       => '80',
          add_listen => false,
          proxy_pass => {
            'path' => '/',
            'url'  => 'http://localhost:8888/subdir/',
          },
        }
        host { 'proxy.example.com': ip => '127.0.0.1', }
        file { ['/var/www/local', '/var/www/local/subdir']: ensure => directory, }
        file { '/var/www/local/subdir/index.html':
          ensure  => file,
          content => "Hello from localhost\\n",
        }
                     }, :catch_failures => true)
    end

    describe service($service_name) do
      it { is_expected.to be_enabled }
      it { is_expected.to be_running }
    end

    it 'should get a response from the back end' do
      shell("/usr/bin/curl --max-redirs 0 proxy.example.com:80") do |r|
        expect(r.stdout).to eq("Hello from localhost\n")
        expect(r.exit_code).to eq(0)
      end
    end
  end

  describe 'ip_based' do
    it 'applies cleanly' do
      pp = <<-EOS
        class { 'apache': }
        host { 'test.server': ip => '127.0.0.1' }
        apache::vhost { 'test.server':
          docroot    => '/tmp',
          ip_based   => true,
          servername => 'test.server',
        }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe file($ports_file) do
      it { is_expected.to be_file }
      it { is_expected.not_to contain 'NameVirtualHost test.server' }
    end
  end

  describe 'add_listen' do
    it 'applies cleanly' do
      pp = <<-EOS
        class { 'apache': default_vhost => false }
        host { 'testlisten.server': ip => '127.0.0.1' }
        apache::listen { '81': }
        apache::vhost { 'testlisten.server':
          docroot    => '/tmp',
          port       => '80',
          add_listen => false,
          servername => 'testlisten.server',
        }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe file($ports_file) do
      it { is_expected.to be_file }
      it { is_expected.not_to contain 'Listen 80' }
      it { is_expected.to contain 'Listen 81' }
    end
  end

  describe 'docroot' do
    it 'applies cleanly' do
      pp = <<-EOS
        user { 'test_owner': ensure => present, }
        group { 'test_group': ensure => present, }
        class { 'apache': }
        host { 'test.server': ip => '127.0.0.1' }
        apache::vhost { 'test.server':
          docroot       => '/tmp/test',
          docroot_owner => 'test_owner',
          docroot_group => 'test_group',
          docroot_mode  => '0750',
        }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe file('/tmp/test') do
      it { is_expected.to be_directory }
      it { is_expected.to be_owned_by 'test_owner' }
      it { is_expected.to be_grouped_into 'test_group' }
      it { is_expected.to be_mode 750 }
    end
  end

  describe 'default_vhost' do
    it 'applies cleanly' do
      pp = <<-EOS
        class { 'apache': }
        host { 'test.server': ip => '127.0.0.1' }
        apache::vhost { 'test.server':
          docroot    => '/tmp',
          default_vhost => true,
        }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe file($ports_file) do
      it { is_expected.to be_file }
      if fact('osfamily') == 'RedHat' and fact('operatingsystemmajrelease') == '7'
        it { is_expected.not_to contain 'NameVirtualHost test.server' }
      elsif fact('operatingsystem') == 'Ubuntu' and fact('operatingsystemrelease') =~ /(14\.04|13\.10)/
        it { is_expected.not_to contain 'NameVirtualHost test.server' }
      else
        it { is_expected.to contain 'NameVirtualHost test.server' }
      end
    end

    describe file("#{$vhost_dir}/10-test.server.conf") do
      it { is_expected.to be_file }
    end
  end

  describe 'options' do
    it 'applies cleanly' do
      pp = <<-EOS
        class { 'apache': }
        host { 'test.server': ip => '127.0.0.1' }
        apache::vhost { 'test.server':
          docroot    => '/tmp',
          options    => ['Indexes','FollowSymLinks', 'ExecCGI'],
        }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe file("#{$vhost_dir}/25-test.server.conf") do
      it { is_expected.to be_file }
      it { is_expected.to contain 'Options Indexes FollowSymLinks ExecCGI' }
    end
  end

  describe 'override' do
    it 'applies cleanly' do
      pp = <<-EOS
        class { 'apache': }
        host { 'test.server': ip => '127.0.0.1' }
        apache::vhost { 'test.server':
          docroot    => '/tmp',
          override   => ['All'],
        }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe file("#{$vhost_dir}/25-test.server.conf") do
      it { is_expected.to be_file }
      it { is_expected.to contain 'AllowOverride All' }
    end
  end

  describe 'logroot' do
    it 'applies cleanly' do
      pp = <<-EOS
        class { 'apache': }
        host { 'test.server': ip => '127.0.0.1' }
        apache::vhost { 'test.server':
          docroot    => '/tmp',
          logroot    => '/tmp',
        }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe file("#{$vhost_dir}/25-test.server.conf") do
      it { is_expected.to be_file }
      it { is_expected.to contain '  CustomLog "/tmp' }
    end
  end

  ['access', 'error'].each do |logtype|
    case logtype
    when 'access'
      logname = 'CustomLog'
    when 'error'
      logname = 'ErrorLog'
    end

    describe "#{logtype}_log" do
      it 'applies cleanly' do
        pp = <<-EOS
          class { 'apache': }
          host { 'test.server': ip => '127.0.0.1' }
          apache::vhost { 'test.server':
            docroot    => '/tmp',
            logroot    => '/tmp',
        #{logtype}_log => false,
          }
        EOS
        apply_manifest(pp, :catch_failures => true)
      end

      describe file("#{$vhost_dir}/25-test.server.conf") do
        it { is_expected.to be_file }
        it { is_expected.not_to contain "  #{logname} \"/tmp" }
      end
    end

    describe "#{logtype}_log_pipe" do
      it 'applies cleanly' do
        pp = <<-EOS
          class { 'apache': }
          host { 'test.server': ip => '127.0.0.1' }
          apache::vhost { 'test.server':
            docroot    => '/tmp',
            logroot    => '/tmp',
        #{logtype}_log_pipe => '|/bin/sh',
          }
        EOS
        apply_manifest(pp, :catch_failures => true)
      end

      describe file("#{$vhost_dir}/25-test.server.conf") do
        it { is_expected.to be_file }
        it { is_expected.to contain "  #{logname} \"|/bin/sh" }
      end
    end

    describe "#{logtype}_log_syslog" do
      it 'applies cleanly' do
        pp = <<-EOS
          class { 'apache': }
          host { 'test.server': ip => '127.0.0.1' }
          apache::vhost { 'test.server':
            docroot    => '/tmp',
            logroot    => '/tmp',
        #{logtype}_log_syslog => 'syslog',
          }
        EOS
        apply_manifest(pp, :catch_failures => true)
      end

      describe file("#{$vhost_dir}/25-test.server.conf") do
        it { is_expected.to be_file }
        it { is_expected.to contain "  #{logname} \"syslog\"" }
      end
    end
  end

  describe 'access_log_format' do
    it 'applies cleanly' do
      pp = <<-EOS
        class { 'apache': }
        host { 'test.server': ip => '127.0.0.1' }
        apache::vhost { 'test.server':
          docroot    => '/tmp',
          logroot    => '/tmp',
          access_log_syslog => 'syslog',
          access_log_format => '%h %l',
        }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe file("#{$vhost_dir}/25-test.server.conf") do
      it { is_expected.to be_file }
      it { is_expected.to contain 'CustomLog "syslog" "%h %l"' }
    end
  end

  describe 'access_log_env_var' do
    it 'applies cleanly' do
      pp = <<-EOS
        class { 'apache': }
        host { 'test.server': ip => '127.0.0.1' }
        apache::vhost { 'test.server':
          docroot            => '/tmp',
          logroot            => '/tmp',
          access_log_syslog  => 'syslog',
          access_log_env_var => 'admin',
        }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe file("#{$vhost_dir}/25-test.server.conf") do
      it { is_expected.to be_file }
      it { is_expected.to contain 'CustomLog "syslog" combined env=admin' }
    end
  end

  describe 'aliases' do
    it 'applies cleanly' do
      pp = <<-EOS
        class { 'apache': }
        host { 'test.server': ip => '127.0.0.1' }
        apache::vhost { 'test.server':
          docroot    => '/tmp',
          aliases => [{ alias => '/image', path => '/ftp/pub/image' }],
        }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe file("#{$vhost_dir}/25-test.server.conf") do
      it { is_expected.to be_file }
      it { is_expected.to contain 'Alias /image "/ftp/pub/image"' }
    end
  end

  describe 'scriptaliases' do
    it 'applies cleanly' do
      pp = <<-EOS
        class { 'apache': }
        host { 'test.server': ip => '127.0.0.1' }
        apache::vhost { 'test.server':
          docroot    => '/tmp',
          scriptaliases => [{ alias => '/myscript', path  => '/usr/share/myscript', }],
        }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe file("#{$vhost_dir}/25-test.server.conf") do
      it { is_expected.to be_file }
      it { is_expected.to contain 'ScriptAlias /myscript "/usr/share/myscript"' }
    end
  end

  describe 'proxy' do
    it 'applies cleanly' do
      pp = <<-EOS
        class { 'apache': service_ensure => stopped, }
        host { 'test.server': ip => '127.0.0.1' }
        apache::vhost { 'test.server':
          docroot    => '/tmp',
          proxy_dest => 'test2',
        }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe file("#{$vhost_dir}/25-test.server.conf") do
      it { is_expected.to be_file }
      it { is_expected.to contain 'ProxyPass          / test2/' }
    end
  end

  describe 'actions' do
    it 'applies cleanly' do
      pp = <<-EOS
        class { 'apache': }
        host { 'test.server': ip => '127.0.0.1' }
        apache::vhost { 'test.server':
          docroot => '/tmp',
          action  => 'php-fastcgi',
        }
      EOS
      pp = pp + "\nclass { 'apache::mod::actions': }" if fact('osfamily') == 'Debian'
      apply_manifest(pp, :catch_failures => true)
    end

    describe file("#{$vhost_dir}/25-test.server.conf") do
      it { is_expected.to be_file }
      it { is_expected.to contain 'Action php-fastcgi /cgi-bin virtual' }
    end
  end

  describe 'suphp' do
    it 'applies cleanly' do
      pp = <<-EOS
        class { 'apache': service_ensure => stopped, }
        host { 'test.server': ip => '127.0.0.1' }
        apache::vhost { 'test.server':
          docroot          => '/tmp',
          suphp_addhandler => '#{$suphp_handler}',
          suphp_engine     => 'on',
          suphp_configpath => '#{$suphp_configpath}',
        }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe file("#{$vhost_dir}/25-test.server.conf") do
      it { is_expected.to be_file }
      it { is_expected.to contain "suPHP_AddHandler #{$suphp_handler}" }
      it { is_expected.to contain 'suPHP_Engine on' }
      it { is_expected.to contain "suPHP_ConfigPath \"#{$suphp_configpath}\"" }
    end
  end

  describe 'no_proxy_uris' do
    it 'applies cleanly' do
      pp = <<-EOS
        class { 'apache': service_ensure => stopped, }
        host { 'test.server': ip => '127.0.0.1' }
        apache::vhost { 'test.server':
          docroot          => '/tmp',
          proxy_dest       => 'http://test2',
          no_proxy_uris    => [ 'http://test2/test' ],
        }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe file("#{$vhost_dir}/25-test.server.conf") do
      it { is_expected.to be_file }
      it { is_expected.to contain 'ProxyPass          / http://test2/' }
      it { is_expected.to contain 'ProxyPass        http://test2/test !' }
    end
  end

  describe 'redirect' do
    it 'applies cleanly' do
      pp = <<-EOS
        class { 'apache': }
        host { 'test.server': ip => '127.0.0.1' }
        apache::vhost { 'test.server':
          docroot          => '/tmp',
          redirect_source  => ['/images'],
          redirect_dest    => ['http://test.server/'],
          redirect_status  => ['permanent'],
        }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe file("#{$vhost_dir}/25-test.server.conf") do
      it { is_expected.to be_file }
      it { is_expected.to contain 'Redirect permanent /images http://test.server/' }
    end
  end

  # Passenger isn't even in EPEL on el-5
  if default['platform'] !~ /^el-5/
    if fact('osfamily') == 'RedHat' and fact('operatingsystemmajrelease') == '7'
      pending('Since we don\'t have passenger on RHEL7 rack_base_uris tests will fail')
    else
      describe 'rack_base_uris' do
        if fact('osfamily') == 'RedHat'
          it 'adds epel' do
            pp = "class { 'epel': }"
            apply_manifest(pp, :catch_failures => true)
          end
        end

        it 'applies cleanly' do
          pp = <<-EOS
            class { 'apache': }
            host { 'test.server': ip => '127.0.0.1' }
            apache::vhost { 'test.server':
              docroot          => '/tmp',
              rack_base_uris  => ['/test'],
            }
          EOS
          apply_manifest(pp, :catch_failures => true)
        end

        describe file("#{$vhost_dir}/25-test.server.conf") do
          it { is_expected.to be_file }
          it { is_expected.to contain 'RackBaseURI /test' }
        end
      end
    end
  end


  describe 'request_headers' do
    it 'applies cleanly' do
      pp = <<-EOS
        class { 'apache': }
        host { 'test.server': ip => '127.0.0.1' }
        apache::vhost { 'test.server':
          docroot          => '/tmp',
          request_headers  => ['append MirrorID "mirror 12"'],
        }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe file("#{$vhost_dir}/25-test.server.conf") do
      it { is_expected.to be_file }
      it { is_expected.to contain 'append MirrorID "mirror 12"' }
    end
  end

  describe 'rewrite rules' do
    it 'applies cleanly' do
      pp = <<-EOS
        class { 'apache': }
        host { 'test.server': ip => '127.0.0.1' }
        apache::vhost { 'test.server':
          docroot          => '/tmp',
          rewrites => [
            { comment => 'test',
              rewrite_cond => '%{HTTP_USER_AGENT} ^Lynx/ [OR]',
              rewrite_rule => ['^index\.html$ welcome.html'],
            }
          ],
        }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe file("#{$vhost_dir}/25-test.server.conf") do
      it { is_expected.to be_file }
      it { is_expected.to contain '#test' }
      it { is_expected.to contain 'RewriteCond %{HTTP_USER_AGENT} ^Lynx/ [OR]' }
      it { is_expected.to contain 'RewriteRule ^index.html$ welcome.html' }
    end
  end

  describe 'setenv/setenvif' do
    it 'applies cleanly' do
      pp = <<-EOS
        class { 'apache': }
        host { 'test.server': ip => '127.0.0.1' }
        apache::vhost { 'test.server':
          docroot  => '/tmp',
          setenv   => ['TEST /test'],
          setenvif => ['Request_URI "\.gif$" object_is_image=gif']
        }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe file("#{$vhost_dir}/25-test.server.conf") do
      it { is_expected.to be_file }
      it { is_expected.to contain 'SetEnv TEST /test' }
      it { is_expected.to contain 'SetEnvIf Request_URI "\.gif$" object_is_image=gif' }
    end
  end

  describe 'block' do
    it 'applies cleanly' do
      pp = <<-EOS
        class { 'apache': }
        host { 'test.server': ip => '127.0.0.1' }
        apache::vhost { 'test.server':
          docroot  => '/tmp',
          block    => 'scm',
        }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe file("#{$vhost_dir}/25-test.server.conf") do
      it { is_expected.to be_file }
      it { is_expected.to contain '<DirectoryMatch .*\.(svn|git|bzr)/.*>' }
    end
  end

  describe 'wsgi' do
    it 'import_script applies cleanly' do
      pp = <<-EOS
        class { 'apache': }
        class { 'apache::mod::wsgi': }
        host { 'test.server': ip => '127.0.0.1' }
        apache::vhost { 'test.server':
          docroot                     => '/tmp',
          wsgi_application_group      => '%{GLOBAL}',
          wsgi_daemon_process         => 'wsgi',
          wsgi_daemon_process_options => {processes => '2'},
          wsgi_process_group          => 'nobody',
          wsgi_script_aliases         => { '/test' => '/test1' },
    wsgi_pass_authorization     => 'On',
        }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    it 'import_script applies cleanly', :unless => (fact('lsbdistcodename') == 'lucid' or UNSUPPORTED_PLATFORMS.include?(fact('osfamily'))) do
      pp = <<-EOS
        class { 'apache': }
        class { 'apache::mod::wsgi': }
        host { 'test.server': ip => '127.0.0.1' }
        apache::vhost { 'test.server':
          docroot                     => '/tmp',
          wsgi_application_group      => '%{GLOBAL}',
          wsgi_daemon_process         => 'wsgi',
          wsgi_daemon_process_options => {processes => '2'},
          wsgi_import_script          => '/test1',
          wsgi_import_script_options  => { application-group => '%{GLOBAL}', process-group => 'wsgi' },
          wsgi_process_group          => 'nobody',
          wsgi_script_aliases         => { '/test' => '/test1' },
    wsgi_pass_authorization     => 'On',
        }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe file("#{$vhost_dir}/25-test.server.conf"), :unless => (fact('lsbdistcodename') == 'lucid' or UNSUPPORTED_PLATFORMS.include?(fact('osfamily'))) do
      it { is_expected.to be_file }
      it { is_expected.to contain 'WSGIApplicationGroup %{GLOBAL}' }
      it { is_expected.to contain 'WSGIDaemonProcess wsgi processes=2' }
      it { is_expected.to contain 'WSGIImportScript /test1 application-group=%{GLOBAL} process-group=wsgi' }
      it { is_expected.to contain 'WSGIProcessGroup nobody' }
      it { is_expected.to contain 'WSGIScriptAlias /test "/test1"' }
      it { is_expected.to contain 'WSGIPassAuthorization On' }
    end
  end

  describe 'custom_fragment' do
    it 'applies cleanly' do
      pp = <<-EOS
        class { 'apache': }
        host { 'test.server': ip => '127.0.0.1' }
        apache::vhost { 'test.server':
          docroot  => '/tmp',
          custom_fragment => inline_template('#weird test string'),
        }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe file("#{$vhost_dir}/25-test.server.conf") do
      it { is_expected.to be_file }
      it { is_expected.to contain '#weird test string' }
    end
  end

  describe 'itk' do
    it 'applies cleanly' do
      pp = <<-EOS
        class { 'apache': }
        host { 'test.server': ip => '127.0.0.1' }
        apache::vhost { 'test.server':
          docroot  => '/tmp',
          itk      => { user => 'nobody', group => 'nobody' }
        }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe file("#{$vhost_dir}/25-test.server.conf") do
      it { is_expected.to be_file }
      it { is_expected.to contain 'AssignUserId nobody nobody' }
    end
  end

  # So what does this work on?
  if default['platform'] !~ /^(debian-(6|7)|el-(5|6|7))/
    describe 'fastcgi' do
      it 'applies cleanly' do
        pp = <<-EOS
          class { 'apache': }
          class { 'apache::mod::fastcgi': }
          host { 'test.server': ip => '127.0.0.1' }
          apache::vhost { 'test.server':
            docroot        => '/tmp',
            fastcgi_server => 'localhost',
            fastcgi_socket => '/tmp/fast/1234',
            fastcgi_dir    => '/tmp/fast',
          }
        EOS
        apply_manifest(pp, :catch_failures => true)
      end

      describe file("#{$vhost_dir}/25-test.server.conf") do
        it { is_expected.to be_file }
        it { is_expected.to contain 'FastCgiExternalServer localhost -socket /tmp/fast/1234' }
        it { is_expected.to contain '<Directory "/tmp/fast">' }
      end
    end
  end

  describe 'additional_includes' do
    it 'applies cleanly' do
      pp = <<-EOS
        if $::osfamily == 'RedHat' and $::selinux == 'true' {
          $semanage_package = $::operatingsystemmajrelease ? {
            '5'     => 'policycoreutils',
            default => 'policycoreutils-python',
          }
          exec { 'set_apache_defaults':
            command => 'semanage fcontext -a -t httpd_sys_content_t "/apache_spec(/.*)?"',
            path    => '/bin:/usr/bin/:/sbin:/usr/sbin',
            require => Package[$semanage_package],
          }
          package { $semanage_package: ensure => installed }
          exec { 'restorecon_apache':
            command => 'restorecon -Rv /apache_spec',
            path    => '/bin:/usr/bin/:/sbin:/usr/sbin',
            before  => Service['httpd'],
            require => Class['apache'],
          }
        }
        class { 'apache': }
        host { 'test.server': ip => '127.0.0.1' }
        file { '/apache_spec': ensure => directory, }
        file { '/apache_spec/include': ensure => present, content => '#additional_includes' }
        apache::vhost { 'test.server':
          docroot             => '/apache_spec',
          additional_includes => '/apache_spec/include',
        }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe file("#{$vhost_dir}/25-test.server.conf") do
      it { is_expected.to be_file }
      it { is_expected.to contain 'Include "/apache_spec/include"' }
    end
  end

end
require 'spec_helper'

describe 'apache', :type => :class do
  context "on a Debian OS" do
    let :facts do
      {
        :id                     => 'root',
        :kernel                 => 'Linux',
        :lsbdistcodename        => 'squeeze',
        :osfamily               => 'Debian',
        :operatingsystem        => 'Debian',
        :operatingsystemrelease => '6',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
        :concat_basedir         => '/dne',
      }
    end
    it { is_expected.to contain_class("apache::params") }
    it { is_expected.to contain_package("httpd").with(
      'notify' => 'Class[Apache::Service]',
      'ensure' => 'installed'
      )
    }
    it { is_expected.to contain_user("www-data") }
    it { is_expected.to contain_group("www-data") }
    it { is_expected.to contain_class("apache::service") }
    it { is_expected.to contain_file("/etc/apache2/sites-enabled").with(
      'ensure'  => 'directory',
      'recurse' => 'true',
      'purge'   => 'true',
      'notify'  => 'Class[Apache::Service]',
      'require' => 'Package[httpd]'
      )
    }
    it { is_expected.to contain_file("/etc/apache2/mods-enabled").with(
      'ensure'  => 'directory',
      'recurse' => 'true',
      'purge'   => 'true',
      'notify'  => 'Class[Apache::Service]',
      'require' => 'Package[httpd]'
      )
    }
    it { is_expected.to contain_file("/etc/apache2/mods-available").with(
      'ensure'  => 'directory',
      'recurse' => 'true',
      'purge'   => 'false',
      'notify'  => 'Class[Apache::Service]',
      'require' => 'Package[httpd]'
      )
    }
    it { is_expected.to contain_concat("/etc/apache2/ports.conf").with(
      'owner'   => 'root',
      'group'   => 'root',
      'mode'    => '0644',
      'notify'  => 'Class[Apache::Service]'
      )
    }
    # Assert that load files are placed and symlinked for these mods, but no conf file.
    [
      'auth_basic',
      'authn_file',
      'authz_default',
      'authz_groupfile',
      'authz_host',
      'authz_user',
      'dav',
      'env'
    ].each do |modname|
      it { is_expected.to contain_file("#{modname}.load").with(
        'path'   => "/etc/apache2/mods-available/#{modname}.load",
        'ensure' => 'file'
      ) }
      it { is_expected.to contain_file("#{modname}.load symlink").with(
        'path'   => "/etc/apache2/mods-enabled/#{modname}.load",
        'ensure' => 'link',
        'target' => "/etc/apache2/mods-available/#{modname}.load"
      ) }
      it { is_expected.not_to contain_file("#{modname}.conf") }
      it { is_expected.not_to contain_file("#{modname}.conf symlink") }
    end

    context "with Apache version < 2.4" do
      let :params do
        { :apache_version => '2.2' }
      end

      it { is_expected.to contain_file("/etc/apache2/apache2.conf").with_content %r{^Include "/etc/apache2/conf\.d/\*\.conf"$} }
    end

    context "with Apache version >= 2.4" do
      let :params do
        { :apache_version => '2.4' }
      end

      it { is_expected.to contain_file("/etc/apache2/apache2.conf").with_content %r{^IncludeOptional "/etc/apache2/conf\.d/\*\.conf"$} }
    end

    # Assert that both load files and conf files are placed and symlinked for these mods
    [
      'alias',
      'autoindex',
      'dav_fs',
      'deflate',
      'dir',
      'mime',
      'negotiation',
      'setenvif',
    ].each do |modname|
      it { is_expected.to contain_file("#{modname}.load").with(
        'path'   => "/etc/apache2/mods-available/#{modname}.load",
        'ensure' => 'file'
      ) }
      it { is_expected.to contain_file("#{modname}.load symlink").with(
        'path'   => "/etc/apache2/mods-enabled/#{modname}.load",
        'ensure' => 'link',
        'target' => "/etc/apache2/mods-available/#{modname}.load"
      ) }
      it { is_expected.to contain_file("#{modname}.conf").with(
        'path'   => "/etc/apache2/mods-available/#{modname}.conf",
        'ensure' => 'file'
      ) }
      it { is_expected.to contain_file("#{modname}.conf symlink").with(
        'path'   => "/etc/apache2/mods-enabled/#{modname}.conf",
        'ensure' => 'link',
        'target' => "/etc/apache2/mods-available/#{modname}.conf"
      ) }
    end

    describe "Don't create user resource" do
      context "when parameter manage_user is false" do
        let :params do
          { :manage_user => false }
        end

        it { is_expected.not_to contain_user('www-data') }
        it { is_expected.to contain_file("/etc/apache2/apache2.conf").with_content %r{^User www-data\n} }
      end
    end
    describe "Don't create group resource" do
      context "when parameter manage_group is false" do
        let :params do
          { :manage_group => false }
        end

        it { is_expected.not_to contain_group('www-data') }
        it { is_expected.to contain_file("/etc/apache2/apache2.conf").with_content %r{^Group www-data\n} }
      end
    end

    describe "Add extra LogFormats" do
      context "When parameter log_formats is a hash" do
        let :params do
          { :log_formats => {
            'vhost_common'   => "%v %h %l %u %t \"%r\" %>s %b",
            'vhost_combined' => "%v %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\""
          } }
        end

        it { is_expected.to contain_file("/etc/apache2/apache2.conf").with_content %r{^LogFormat "%v %h %l %u %t \"%r\" %>s %b" vhost_common\n} }
        it { is_expected.to contain_file("/etc/apache2/apache2.conf").with_content %r{^LogFormat "%v %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\"" vhost_combined\n} }
      end
    end

    context "on Ubuntu" do
      let :facts do
        super().merge({
          :operatingsystem => 'Ubuntu'
        })
      end

      context "13.10" do
        let :facts do
          super().merge({
            :lsbdistrelease         => '13.10',
            :operatingsystemrelease => '13.10'
          })
        end
        it { is_expected.to contain_class('apache').with_apache_version('2.4') }
      end
      context "12.04" do
        let :facts do
          super().merge({
            :lsbdistrelease         => '12.04',
            :operatingsystemrelease => '12.04'
          })
        end
        it { is_expected.to contain_class('apache').with_apache_version('2.2') }
      end
      context "13.04" do
        let :facts do
          super().merge({
            :lsbdistrelease         => '13.04',
            :operatingsystemrelease => '13.04'
          })
        end
        it { is_expected.to contain_class('apache').with_apache_version('2.2') }
      end
    end
  end
  context "on a RedHat 5 OS" do
    let :facts do
      {
        :id                     => 'root',
        :kernel                 => 'Linux',
        :osfamily               => 'RedHat',
        :operatingsystem        => 'RedHat',
        :operatingsystemrelease => '5',
        :concat_basedir         => '/dne',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    it { is_expected.to contain_class("apache::params") }
    it { is_expected.to contain_package("httpd").with(
      'notify' => 'Class[Apache::Service]',
      'ensure' => 'installed'
      )
    }
    it { is_expected.to contain_user("apache") }
    it { is_expected.to contain_group("apache") }
    it { is_expected.to contain_class("apache::service") }
    it { is_expected.to contain_file("/etc/httpd/conf.d").with(
      'ensure'  => 'directory',
      'recurse' => 'true',
      'purge'   => 'true',
      'notify'  => 'Class[Apache::Service]',
      'require' => 'Package[httpd]'
      )
    }
    it { is_expected.to contain_concat("/etc/httpd/conf/ports.conf").with(
      'owner'   => 'root',
      'group'   => 'root',
      'mode'    => '0644',
      'notify'  => 'Class[Apache::Service]'
      )
    }
    describe "Alternate confd/mod/vhosts directory" do
      let :params do
        {
          :vhost_dir => '/etc/httpd/site.d',
          :confd_dir => '/etc/httpd/conf.d',
          :mod_dir   => '/etc/httpd/mod.d',
        }
      end

      ['mod.d','site.d','conf.d'].each do |dir|
        it { is_expected.to contain_file("/etc/httpd/#{dir}").with(
          'ensure'  => 'directory',
          'recurse' => 'true',
          'purge'   => 'true',
          'notify'  => 'Class[Apache::Service]',
          'require' => 'Package[httpd]'
        ) }
      end

      # Assert that load files are placed for these mods, but no conf file.
      [
        'auth_basic',
        'authn_file',
        'authz_default',
        'authz_groupfile',
        'authz_host',
        'authz_user',
        'dav',
        'env',
      ].each do |modname|
        it { is_expected.to contain_file("#{modname}.load").with_path(
          "/etc/httpd/mod.d/#{modname}.load"
        ) }
        it { is_expected.not_to contain_file("#{modname}.conf").with_path(
          "/etc/httpd/mod.d/#{modname}.conf"
        ) }
      end

      # Assert that both load files and conf files are placed for these mods
      [
        'alias',
        'autoindex',
        'dav_fs',
        'deflate',
        'dir',
        'mime',
        'negotiation',
        'setenvif',
      ].each do |modname|
        it { is_expected.to contain_file("#{modname}.load").with_path(
          "/etc/httpd/mod.d/#{modname}.load"
        ) }
        it { is_expected.to contain_file("#{modname}.conf").with_path(
          "/etc/httpd/mod.d/#{modname}.conf"
        ) }
      end

      context "with Apache version < 2.4" do
        let :params do
          { :apache_version => '2.2' }
        end

        it { is_expected.to contain_file("/etc/httpd/conf/httpd.conf").with_content %r{^Include "/etc/httpd/conf\.d/\*\.conf"$} }
      end

      context "with Apache version >= 2.4" do
        let :params do
          { :apache_version => '2.4' }
        end

        it { is_expected.to contain_file("/etc/httpd/conf/httpd.conf").with_content %r{^IncludeOptional "/etc/httpd/conf\.d/\*\.conf"$} }
      end

      it { is_expected.to contain_file("/etc/httpd/conf/httpd.conf").with_content %r{^Include "/etc/httpd/site\.d/\*"$} }
      it { is_expected.to contain_file("/etc/httpd/conf/httpd.conf").with_content %r{^Include "/etc/httpd/mod\.d/\*\.conf"$} }
      it { is_expected.to contain_file("/etc/httpd/conf/httpd.conf").with_content %r{^Include "/etc/httpd/mod\.d/\*\.load"$} }
    end

    describe "Alternate conf.d directory" do
      let :params do
        { :confd_dir => '/etc/httpd/special_conf.d' }
      end

      it { is_expected.to contain_file("/etc/httpd/special_conf.d").with(
        'ensure'  => 'directory',
        'recurse' => 'true',
        'purge'   => 'true',
        'notify'  => 'Class[Apache::Service]',
        'require' => 'Package[httpd]'
      ) }
    end

    describe "Alternate mpm_modules" do
      context "when declaring mpm_module is false" do
        let :params do
          { :mpm_module => false }
        end
        it 'should not declare mpm modules' do
          is_expected.not_to contain_class('apache::mod::event')
          is_expected.not_to contain_class('apache::mod::itk')
          is_expected.not_to contain_class('apache::mod::peruser')
          is_expected.not_to contain_class('apache::mod::prefork')
          is_expected.not_to contain_class('apache::mod::worker')
        end
      end
      context "when declaring mpm_module => prefork" do
        let :params do
          { :mpm_module => 'prefork' }
        end
        it { is_expected.to contain_class('apache::mod::prefork') }
        it { is_expected.not_to contain_class('apache::mod::event') }
        it { is_expected.not_to contain_class('apache::mod::itk') }
        it { is_expected.not_to contain_class('apache::mod::peruser') }
        it { is_expected.not_to contain_class('apache::mod::worker') }
      end
      context "when declaring mpm_module => worker" do
        let :params do
          { :mpm_module => 'worker' }
        end
        it { is_expected.to contain_class('apache::mod::worker') }
        it { is_expected.not_to contain_class('apache::mod::event') }
        it { is_expected.not_to contain_class('apache::mod::itk') }
        it { is_expected.not_to contain_class('apache::mod::peruser') }
        it { is_expected.not_to contain_class('apache::mod::prefork') }
      end
      context "when declaring mpm_module => breakme" do
        let :params do
          { :mpm_module => 'breakme' }
        end
        it { expect { subject }.to raise_error Puppet::Error, /does not match/ }
      end
    end

    describe "different templates for httpd.conf" do
      context "with default" do
        let :params do
          { :conf_template => 'apache/httpd.conf.erb' }
        end
        it { is_expected.to contain_file("/etc/httpd/conf/httpd.conf").with_content %r{^# Security\n} }
      end
      context "with non-default" do
        let :params do
          { :conf_template => 'site_apache/fake.conf.erb' }
        end
        it { is_expected.to contain_file("/etc/httpd/conf/httpd.conf").with_content %r{^Fake template for rspec.$} }
      end
    end

    describe "default mods" do
      context "without" do
        let :params do
          { :default_mods => false }
        end

        it { is_expected.to contain_apache__mod('authz_host') }
        it { is_expected.not_to contain_apache__mod('env') }
      end
      context "custom" do
        let :params do
          { :default_mods => [
            'info',
            'alias',
            'mime',
            'env',
            'setenv',
            'expires',
          ]}
        end

        it { is_expected.to contain_apache__mod('authz_host') }
        it { is_expected.to contain_apache__mod('env') }
        it { is_expected.to contain_class('apache::mod::info') }
        it { is_expected.to contain_class('apache::mod::mime') }
      end
    end
    describe "Don't create user resource" do
      context "when parameter manage_user is false" do
        let :params do
          { :manage_user => false }
        end

        it { is_expected.not_to contain_user('apache') }
        it { is_expected.to contain_file("/etc/httpd/conf/httpd.conf").with_content %r{^User apache\n} }
      end
    end
    describe "Don't create group resource" do
      context "when parameter manage_group is false" do
        let :params do
          { :manage_group => false }
        end

        it { is_expected.not_to contain_group('apache') }
        it { is_expected.to contain_file("/etc/httpd/conf/httpd.conf").with_content %r{^Group apache\n} }

      end
    end
    describe "sendfile" do
      context "with invalid value" do
        let :params do
          { :sendfile => 'foo' }
        end
        it "should fail" do
          expect do
            subject
          end.to raise_error(Puppet::Error, /"foo" does not match/)
        end
      end
      context "On" do
        let :params do
          { :sendfile => 'On' }
        end
        it { is_expected.to contain_file("/etc/httpd/conf/httpd.conf").with_content %r{^EnableSendfile On\n} }
      end
      context "Off" do
        let :params do
          { :sendfile => 'Off' }
        end
        it { is_expected.to contain_file("/etc/httpd/conf/httpd.conf").with_content %r{^EnableSendfile Off\n} }
      end
    end
  end
  context "on a FreeBSD OS" do
    let :facts do
      {
        :id                     => 'root',
        :kernel                 => 'FreeBSD',
        :osfamily               => 'FreeBSD',
        :operatingsystem        => 'FreeBSD',
        :operatingsystemrelease => '9',
        :concat_basedir         => '/dne',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    it { is_expected.to contain_class("apache::params") }
    it { is_expected.to contain_class("apache::package").with({'ensure' => 'present'}) }
    it { is_expected.to contain_user("www") }
    it { is_expected.to contain_group("www") }
    it { is_expected.to contain_class("apache::service") }
    it { is_expected.to contain_file("/usr/local/etc/apache22/Vhosts").with(
      'ensure'  => 'directory',
      'recurse' => 'true',
      'purge'   => 'true',
      'notify'  => 'Class[Apache::Service]',
      'require' => 'Package[httpd]'
    ) }
    it { is_expected.to contain_file("/usr/local/etc/apache22/Modules").with(
      'ensure'  => 'directory',
      'recurse' => 'true',
      'purge'   => 'true',
      'notify'  => 'Class[Apache::Service]',
      'require' => 'Package[httpd]'
    ) }
    it { is_expected.to contain_concat("/usr/local/etc/apache22/ports.conf").with(
      'owner'   => 'root',
      'group'   => 'wheel',
      'mode'    => '0644',
      'notify'  => 'Class[Apache::Service]'
    ) }
    # Assert that load files are placed for these mods, but no conf file.
    [
      'auth_basic',
      'authn_file',
      'authz_default',
      'authz_groupfile',
      'authz_host',
      'authz_user',
      'dav',
      'env'
    ].each do |modname|
      it { is_expected.to contain_file("#{modname}.load").with(
        'path'   => "/usr/local/etc/apache22/Modules/#{modname}.load",
        'ensure' => 'file'
      ) }
      it { is_expected.not_to contain_file("#{modname}.conf") }
    end

    # Assert that both load files and conf files are placed for these mods
    [
      'alias',
      'autoindex',
      'dav_fs',
      'deflate',
      'dir',
      'mime',
      'negotiation',
      'setenvif',
    ].each do |modname|
      it { is_expected.to contain_file("#{modname}.load").with(
        'path'   => "/usr/local/etc/apache22/Modules/#{modname}.load",
        'ensure' => 'file'
      ) }
      it { is_expected.to contain_file("#{modname}.conf").with(
        'path'   => "/usr/local/etc/apache22/Modules/#{modname}.conf",
        'ensure' => 'file'
      ) }
    end
  end
  context 'on all OSes' do
    let :facts do
      {
        :id                     => 'root',
        :kernel                 => 'Linux',
        :osfamily               => 'RedHat',
        :operatingsystem        => 'RedHat',
        :operatingsystemrelease => '6',
        :concat_basedir         => '/dne',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    context 'default vhost defaults' do
      it { is_expected.to contain_apache__vhost('default').with_ensure('present') }
      it { is_expected.to contain_apache__vhost('default-ssl').with_ensure('absent') }
    end
    context 'without default non-ssl vhost' do
      let :params do {
        :default_vhost  => false
      }
      end
      it { is_expected.to contain_apache__vhost('default').with_ensure('absent') }
    end
    context 'with default ssl vhost' do
      let :params do {
          :default_ssl_vhost  => true
        }
      end
      it { is_expected.to contain_apache__vhost('default-ssl').with_ensure('present') }
    end
  end
  context 'with unsupported osfamily' do
    let :facts do
      { :osfamily        => 'Darwin',
        :operatingsystemrelease => '13.1.0',
        :concat_basedir         => '/dne',
      }
    end

    it do
      expect {
       should compile
      }.to raise_error(Puppet::Error, /Unsupported osfamily/)
    end
  end
end
require 'spec_helper'

describe 'apache::dev', :type => :class do
  context "on a Debian OS" do
    let :facts do
      {
        :lsbdistcodename        => 'squeeze',
        :osfamily               => 'Debian',
        :operatingsystem        => 'Debian',
        :operatingsystemrelease => '6',
      }
    end
    it { is_expected.to contain_class("apache::params") }
    it { is_expected.to contain_package("libaprutil1-dev") }
    it { is_expected.to contain_package("libapr1-dev") }
    it { is_expected.to contain_package("apache2-prefork-dev") }
  end
  context "on a RedHat OS" do
    let :facts do
      {
        :osfamily               => 'RedHat',
        :operatingsystem        => 'RedHat',
        :operatingsystemrelease => '6',
      }
    end
    it { is_expected.to contain_class("apache::params") }
    it { is_expected.to contain_package("httpd-devel") }
  end
  context "on a FreeBSD OS" do
    let :pre_condition do
      'include apache::package'
    end
    let :facts do
      {
        :osfamily               => 'FreeBSD',
        :operatingsystem        => 'FreeBSD',
        :operatingsystemrelease => '9',
      }
    end
    it { is_expected.to contain_class("apache::params") }
  end
end
require 'spec_helper'

describe 'apache::mod::auth_kerb', :type => :class do
  let :pre_condition do
    'include apache'
  end
  context "on a Debian OS", :compile do
    let :facts do
      {
        :id                     => 'root',
        :kernel                 => 'Linux',
        :lsbdistcodename        => 'squeeze',
        :osfamily               => 'Debian',
        :operatingsystem        => 'Debian',
        :operatingsystemrelease => '6',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
        :concat_basedir         => '/dne',
      }
    end
    it { is_expected.to contain_class("apache::params") }
    it { is_expected.to contain_apache__mod("auth_kerb") }
    it { is_expected.to contain_package("libapache2-mod-auth-kerb") }
  end
  context "on a RedHat OS", :compile do
    let :facts do
      {
        :id                     => 'root',
        :kernel                 => 'Linux',
        :osfamily               => 'RedHat',
        :operatingsystem        => 'RedHat',
        :operatingsystemrelease => '6',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
        :concat_basedir         => '/dne',
      }
    end
    it { is_expected.to contain_class("apache::params") }
    it { is_expected.to contain_apache__mod("auth_kerb") }
    it { is_expected.to contain_package("mod_auth_kerb") }
  end
  context "on a FreeBSD OS", :compile do
    let :facts do
      {
        :id                     => 'root',
        :kernel                 => 'FreeBSD',
        :osfamily               => 'FreeBSD',
        :operatingsystem        => 'FreeBSD',
        :operatingsystemrelease => '9',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
        :concat_basedir         => '/dne',
      }
    end
    it { is_expected.to contain_class("apache::params") }
    it { is_expected.to contain_apache__mod("auth_kerb") }
    it { is_expected.to contain_package("www/mod_auth_kerb2") }
  end
end
require 'spec_helper'

describe 'apache::mod::authnz_ldap', :type => :class do
  let :pre_condition do
    'include apache'
  end

  context "on a Debian OS" do
    let :facts do
      {
        :lsbdistcodename        => 'squeeze',
        :osfamily               => 'Debian',
        :operatingsystemrelease => '6',
        :concat_basedir         => '/dne',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :operatingsystem        => 'Debian',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    it { is_expected.to contain_class("apache::params") }
    it { is_expected.to contain_class("apache::mod::ldap") }
    it { is_expected.to contain_apache__mod('authnz_ldap') }

    context 'default verifyServerCert' do
      it { is_expected.to contain_file('authnz_ldap.conf').with_content(/^LDAPVerifyServerCert On$/) }
    end

    context 'verifyServerCert = false' do
      let(:params) { { :verifyServerCert => false } }
      it { is_expected.to contain_file('authnz_ldap.conf').with_content(/^LDAPVerifyServerCert Off$/) }
    end

    context 'verifyServerCert = wrong' do
      let(:params) { { :verifyServerCert => 'wrong' } }
      it 'should raise an error' do
        expect { is_expected.to raise_error Puppet::Error }
      end
    end
  end #Debian

  context "on a RedHat OS" do
    let :facts do
      {
        :osfamily               => 'RedHat',
        :operatingsystemrelease => '6',
        :concat_basedir         => '/dne',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :operatingsystem        => 'RedHat',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    it { is_expected.to contain_class("apache::params") }
    it { is_expected.to contain_class("apache::mod::ldap") }
    it { is_expected.to contain_apache__mod('authnz_ldap') }

    context 'default verifyServerCert' do
      it { is_expected.to contain_file('authnz_ldap.conf').with_content(/^LDAPVerifyServerCert On$/) }
    end

    context 'verifyServerCert = false' do
      let(:params) { { :verifyServerCert => false } }
      it { is_expected.to contain_file('authnz_ldap.conf').with_content(/^LDAPVerifyServerCert Off$/) }
    end

    context 'verifyServerCert = wrong' do
      let(:params) { { :verifyServerCert => 'wrong' } }
      it 'should raise an error' do
        expect { is_expected.to raise_error Puppet::Error }
      end
    end
  end # Redhat

end

require 'spec_helper'

describe 'apache::mod::dav_svn', :type => :class do
  let :pre_condition do
    'include apache'
  end
  context "on a Debian OS" do
    let :facts do
      {
        :lsbdistcodename        => 'squeeze',
        :osfamily               => 'Debian',
        :operatingsystemrelease => '6',
        :concat_basedir         => '/dne',
        :operatingsystem        => 'Debian',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    it { is_expected.to contain_class("apache::params") }
    it { is_expected.to contain_apache__mod('dav_svn') }
    it { is_expected.to contain_package("libapache2-svn") }
  end
  context "on a RedHat OS" do
    let :facts do
      {
        :osfamily               => 'RedHat',
        :operatingsystemrelease => '6',
        :concat_basedir         => '/dne',
        :operatingsystem        => 'RedHat',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    it { is_expected.to contain_class("apache::params") }
    it { is_expected.to contain_apache__mod('dav_svn') }
    it { is_expected.to contain_package("mod_dav_svn") }
  end
  context "on a FreeBSD OS" do
    let :facts do
      {
        :osfamily               => 'FreeBSD',
        :operatingsystemrelease => '9',
        :concat_basedir         => '/dne',
        :operatingsystem        => 'FreeBSD',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    it { is_expected.to contain_class("apache::params") }
    it { is_expected.to contain_apache__mod('dav_svn') }
    it { is_expected.to contain_package("devel/subversion") }
  end
end
require 'spec_helper'

# This function is called inside the OS specific contexts
def general_deflate_specs
  it { is_expected.to contain_apache__mod("deflate") }

  it do
    is_expected.to contain_file("deflate.conf").with_content(
      "AddOutputFilterByType DEFLATE text/css\n"\
      "AddOutputFilterByType DEFLATE text/html\n"\
      "\n"\
      "DeflateFilterNote Input instream\n"\
      "DeflateFilterNote Ratio ratio\n"
    )
  end
end

describe 'apache::mod::deflate', :type => :class do
  let :pre_condition do
    'class { "apache":
      default_mods => false,
    }
    class { "apache::mod::deflate":
      types => [ "text/html", "text/css" ],
      notes => {
        "Input" => "instream",
        "Ratio" => "ratio",
      }
    }
    '
  end

  context "On a Debian OS with default params" do
    let :facts do
      {
        :id                     => 'root',
        :lsbdistcodename        => 'squeeze',
        :osfamily               => 'Debian',
        :operatingsystem        => 'Debian',
        :operatingsystemrelease => '6',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
        :concat_basedir         => '/dne',
      }
    end

    # Load the more generic tests for this context
    general_deflate_specs()

    it { is_expected.to contain_file("deflate.conf").with({
      :ensure => 'file',
      :path   => '/etc/apache2/mods-available/deflate.conf',
    } ) }
    it { is_expected.to contain_file("deflate.conf symlink").with({
      :ensure => 'link',
      :path   => '/etc/apache2/mods-enabled/deflate.conf',
    } ) }
  end

  context "on a RedHat OS with default params" do
    let :facts do
      {
        :id                     => 'root',
        :osfamily               => 'RedHat',
        :operatingsystem        => 'RedHat',
        :operatingsystemrelease => '6',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
        :concat_basedir         => '/dne',
      }
    end

    # Load the more generic tests for this context
    general_deflate_specs()

    it { is_expected.to contain_file("deflate.conf").with_path("/etc/httpd/conf.d/deflate.conf") }
  end

  context "On a FreeBSD OS with default params" do
    let :facts do
      {
        :id                     => 'root',
        :osfamily               => 'FreeBSD',
        :operatingsystem        => 'FreeBSD',
        :operatingsystemrelease => '9',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
        :concat_basedir         => '/dne',
      }
    end

    # Load the more generic tests for this context
    general_deflate_specs()

    it { is_expected.to contain_file("deflate.conf").with({
      :ensure => 'file',
      :path   => '/usr/local/etc/apache22/Modules/deflate.conf',
    } ) }
  end
end
require 'spec_helper'

describe 'apache::mod::dev', :type => :class do
  [
    ['RedHat',  '6', 'Santiago'],
    ['Debian',  '6', 'squeeze'],
    ['FreeBSD', '9', 'FreeBSD'],
  ].each do |osfamily, operatingsystemrelease, lsbdistcodename|
    if osfamily == 'FreeBSD'
      let :pre_condition do
        'include apache::package'
      end
    end
    context "on a #{osfamily} OS" do
      let :facts do
        {
          :lsbdistcodename        => lsbdistcodename,
          :osfamily               => osfamily,
          :operatingsystem        => osfamily,
          :operatingsystemrelease => operatingsystemrelease,
        }
      end
      it { is_expected.to contain_class('apache::dev') }
    end
  end
end
require 'spec_helper'

describe 'apache::mod::dir', :type => :class do
  let :pre_condition do
    'class { "apache":
      default_mods => false,
    }'
  end
  context "on a Debian OS" do
    let :facts do
      {
        :osfamily               => 'Debian',
        :operatingsystemrelease => '6',
        :concat_basedir         => '/dne',
        :operatingsystem        => 'Debian',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
        :lsbdistcodename        => 'squeeze',
      }
    end
    context "passing no parameters" do
      it { is_expected.to contain_class("apache::params") }
      it { is_expected.to contain_apache__mod('dir') }
      it { is_expected.to contain_file('dir.conf').with_content(/^DirectoryIndex /) }
      it { is_expected.to contain_file('dir.conf').with_content(/ index\.html /) }
      it { is_expected.to contain_file('dir.conf').with_content(/ index\.html\.var /) }
      it { is_expected.to contain_file('dir.conf').with_content(/ index\.cgi /) }
      it { is_expected.to contain_file('dir.conf').with_content(/ index\.pl /) }
      it { is_expected.to contain_file('dir.conf').with_content(/ index\.php /) }
      it { is_expected.to contain_file('dir.conf').with_content(/ index\.xhtml$/) }
    end
    context "passing indexes => ['example.txt','fearsome.aspx']" do
      let :params do
        {:indexes => ['example.txt','fearsome.aspx']}
      end
      it { is_expected.to contain_file('dir.conf').with_content(/ example\.txt /) }
      it { is_expected.to contain_file('dir.conf').with_content(/ fearsome\.aspx$/) }
    end
  end
  context "on a RedHat OS" do
    let :facts do
      {
        :osfamily               => 'RedHat',
        :operatingsystemrelease => '6',
        :concat_basedir         => '/dne',
        :operatingsystem        => 'Redhat',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    context "passing no parameters" do
      it { is_expected.to contain_class("apache::params") }
      it { is_expected.to contain_apache__mod('dir') }
      it { is_expected.to contain_file('dir.conf').with_content(/^DirectoryIndex /) }
      it { is_expected.to contain_file('dir.conf').with_content(/ index\.html /) }
      it { is_expected.to contain_file('dir.conf').with_content(/ index\.html\.var /) }
      it { is_expected.to contain_file('dir.conf').with_content(/ index\.cgi /) }
      it { is_expected.to contain_file('dir.conf').with_content(/ index\.pl /) }
      it { is_expected.to contain_file('dir.conf').with_content(/ index\.php /) }
      it { is_expected.to contain_file('dir.conf').with_content(/ index\.xhtml$/) }
    end
    context "passing indexes => ['example.txt','fearsome.aspx']" do
      let :params do
        {:indexes => ['example.txt','fearsome.aspx']}
      end
      it { is_expected.to contain_file('dir.conf').with_content(/ example\.txt /) }
      it { is_expected.to contain_file('dir.conf').with_content(/ fearsome\.aspx$/) }
    end
  end
  context "on a FreeBSD OS" do
    let :facts do
      {
        :osfamily               => 'FreeBSD',
        :operatingsystemrelease => '9',
        :concat_basedir         => '/dne',
        :operatingsystem        => 'FreeBSD',
        :id                     => 'root',
        :kernel                 => 'FreeBSD',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    context "passing no parameters" do
      it { is_expected.to contain_class("apache::params") }
      it { is_expected.to contain_apache__mod('dir') }
      it { is_expected.to contain_file('dir.conf').with_content(/^DirectoryIndex /) }
      it { is_expected.to contain_file('dir.conf').with_content(/ index\.html /) }
      it { is_expected.to contain_file('dir.conf').with_content(/ index\.html\.var /) }
      it { is_expected.to contain_file('dir.conf').with_content(/ index\.cgi /) }
      it { is_expected.to contain_file('dir.conf').with_content(/ index\.pl /) }
      it { is_expected.to contain_file('dir.conf').with_content(/ index\.php /) }
      it { is_expected.to contain_file('dir.conf').with_content(/ index\.xhtml$/) }
    end
    context "passing indexes => ['example.txt','fearsome.aspx']" do
      let :params do
        {:indexes => ['example.txt','fearsome.aspx']}
      end
      it { is_expected.to contain_file('dir.conf').with_content(/ example\.txt /) }
      it { is_expected.to contain_file('dir.conf').with_content(/ fearsome\.aspx$/) }
    end
  end
end
require 'spec_helper'

describe 'apache::mod::event', :type => :class do
  let :pre_condition do
    'class { "apache": mpm_module => false, }'
  end
  context "on a FreeBSD OS" do
    let :facts do
      {
        :osfamily               => 'FreeBSD',
        :operatingsystemrelease => '9',
        :concat_basedir         => '/dne',
        :operatingsystem        => 'FreeBSD',
        :id                     => 'root',
        :kernel                 => 'FreeBSD',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    it { is_expected.to contain_class("apache::params") }
    it { is_expected.not_to contain_apache__mod('event') }
    it { is_expected.to contain_file("/usr/local/etc/apache22/Modules/event.conf").with_ensure('file') }
  end
  context "on a Debian OS" do
    let :facts do
      {
        :lsbdistcodename        => 'squeeze',
        :osfamily               => 'Debian',
        :operatingsystemrelease => '6',
        :concat_basedir         => '/dne',
        :operatingsystem        => 'Debian',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end

    it { is_expected.to contain_class("apache::params") }
    it { is_expected.not_to contain_apache__mod('event') }
    it { is_expected.to contain_file("/etc/apache2/mods-available/event.conf").with_ensure('file') }
    it { is_expected.to contain_file("/etc/apache2/mods-enabled/event.conf").with_ensure('link') }

    context "with Apache version < 2.4" do
      let :params do
        {
          :apache_version => '2.2',
        }
      end

      it { is_expected.not_to contain_file("/etc/apache2/mods-available/event.load") }
      it { is_expected.not_to contain_file("/etc/apache2/mods-enabled/event.load") }

      it { is_expected.to contain_package("apache2-mpm-event") }
    end

    context "with Apache version >= 2.4" do
      let :params do
        {
          :apache_version => '2.4',
        }
      end

      it { is_expected.to contain_file("/etc/apache2/mods-available/event.load").with({
        'ensure'  => 'file',
        'content' => "LoadModule mpm_event_module /usr/lib/apache2/modules/mod_mpm_event.so\n"
        })
      }
      it { is_expected.to contain_file("/etc/apache2/mods-enabled/event.load").with_ensure('link') }
    end
  end
  context "on a RedHat OS" do
    let :facts do
      {
        :osfamily               => 'RedHat',
        :operatingsystemrelease => '6',
        :concat_basedir         => '/dne',
        :operatingsystem        => 'RedHat',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end

    context "with Apache version >= 2.4" do
      let :params do
        {
          :apache_version => '2.4',
        }
      end

      it { is_expected.to contain_class("apache::params") }
      it { is_expected.not_to contain_apache__mod('worker') }
      it { is_expected.not_to contain_apache__mod('prefork') }

      it { is_expected.to contain_file("/etc/httpd/conf.d/event.conf").with_ensure('file') }

      it { is_expected.to contain_file("/etc/httpd/conf.d/event.load").with({
        'ensure'  => 'file',
        'content' => "LoadModule mpm_event_module modules/mod_mpm_event.so\n",
        })
      }
    end
  end
end
require 'spec_helper'

describe 'apache::mod::fastcgi', :type => :class do
  let :pre_condition do
    'include apache'
  end
  context "on a Debian OS" do
    let :facts do
      {
        :osfamily               => 'Debian',
        :operatingsystemrelease => '6',
        :concat_basedir         => '/dne',
        :lsbdistcodename        => 'squeze',
        :operatingsystem        => 'Debian',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    it { is_expected.to contain_class("apache::params") }
    it { is_expected.to contain_apache__mod('fastcgi') }
    it { is_expected.to contain_package("libapache2-mod-fastcgi") }
    it { is_expected.to contain_file('fastcgi.conf') }
  end

  context "on a RedHat OS" do
    let :facts do
      {
        :osfamily               => 'RedHat',
        :operatingsystemrelease => '6',
        :concat_basedir         => '/dne',
        :operatingsystem        => 'RedHat',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    it { is_expected.to contain_class("apache::params") }
    it { is_expected.to contain_apache__mod('fastcgi') }
    it { is_expected.to contain_package("mod_fastcgi") }
    it { is_expected.not_to contain_file('fastcgi.conf') }
  end
end
require 'spec_helper'

describe 'apache::mod::fcgid', :type => :class do
  let :pre_condition do
    'include apache'
  end

  context "on a Debian OS" do
    let :facts do
      {
        :osfamily               => 'Debian',
        :operatingsystemrelease => '6',
        :concat_basedir         => '/dne',
        :lsbdistcodename        => 'squeeze',
        :operatingsystem        => 'Debian',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    it { is_expected.to contain_class("apache::params") }
    it { is_expected.to contain_apache__mod('fcgid') }
    it { is_expected.to contain_package("libapache2-mod-fcgid") }
  end

  context "on a RedHat OS" do
    let :facts do
      {
        :osfamily               => 'RedHat',
        :operatingsystemrelease => '6',
        :concat_basedir         => '/dne',
        :operatingsystem        => 'RedHat',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end

    describe 'without parameters' do
      it { is_expected.to contain_class("apache::params") }
      it { is_expected.to contain_apache__mod('fcgid') }
      it { is_expected.to contain_package("mod_fcgid") }
    end

    describe 'with parameters' do
      let :params do {
        :options                     => {
          'FcgidIPCDir'               => '/var/run/fcgidsock',
          'SharememPath'              => '/var/run/fcgid_shm',
          'FcgidMinProcessesPerClass' => '0',
          'AddHandler'                => 'fcgid-script .fcgi',
        }
      } end

      it 'should contain the correct config' do
        content = subject.resource('file', 'fcgid.conf').send(:parameters)[:content]
        expect(content.split("\n").reject { |c| c =~ /(^#|^$)/ }).to eq([
          '<IfModule mod_fcgid.c>',
          '  AddHandler fcgid-script .fcgi',
          '  FcgidIPCDir /var/run/fcgidsock',
          '  FcgidMinProcessesPerClass 0',
          '  SharememPath /var/run/fcgid_shm',
          '</IfModule>',
        ])
      end
    end
  end

  context "on a FreeBSD OS" do
    let :facts do
      {
        :osfamily               => 'FreeBSD',
        :operatingsystemrelease => '9',
        :concat_basedir         => '/dne',
        :operatingsystem        => 'FreeBSD',
        :id                     => 'root',
        :kernel                 => 'FreeBSD',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end

    it { is_expected.to contain_class("apache::params") }
    it { is_expected.to contain_apache__mod('fcgid') }
    it { is_expected.to contain_package("www/mod_fcgid") }
  end
end
# This function is called inside the OS specific contexts
def general_info_specs
  it { is_expected.to contain_apache__mod('info') }

  context 'passing no parameters' do
    it {
      is_expected.to contain_file('info.conf').with_content(
        "<Location /server-info>\n"\
        "    SetHandler server-info\n"\
        "    Order deny,allow\n"\
        "    Deny from all\n"\
        "    Allow from 127.0.0.1\n"\
        "    Allow from ::1\n"\
        "</Location>\n"
      )
    }
  end
  context 'passing restrict_access => false' do
    let :params do {
      :restrict_access => false
    }
    end
    it {
      is_expected.to contain_file('info.conf').with_content(
        "<Location /server-info>\n"\
        "    SetHandler server-info\n"\
        "</Location>\n"
      )
    }
  end
  context "passing allow_from => ['10.10.1.2', '192.168.1.2', '127.0.0.1']" do
    let :params do
      {:allow_from => ['10.10.1.2', '192.168.1.2', '127.0.0.1']}
    end
    it {
      is_expected.to contain_file('info.conf').with_content(
        "<Location /server-info>\n"\
        "    SetHandler server-info\n"\
        "    Order deny,allow\n"\
        "    Deny from all\n"\
        "    Allow from 10.10.1.2\n"\
        "    Allow from 192.168.1.2\n"\
        "    Allow from 127.0.0.1\n"\
        "</Location>\n"
      )
    }
  end
  context 'passing both restrict_access and allow_from' do
    let :params do
      {
        :restrict_access => false,
        :allow_from      => ['10.10.1.2', '192.168.1.2', '127.0.0.1']
      }
    end
    it {
      is_expected.to contain_file('info.conf').with_content(
        "<Location /server-info>\n"\
        "    SetHandler server-info\n"\
        "</Location>\n"
      )
    }
  end
end

describe 'apache::mod::info', :type => :class do
  let :pre_condition do
    "class { 'apache': default_mods => false, }"
  end

  context 'On a Debian OS' do
    let :facts do
      {
        :osfamily               => 'Debian',
        :operatingsystemrelease => '6',
        :concat_basedir         => '/dne',
        :lsbdistcodename        => 'squeeze',
        :operatingsystem        => 'Debian',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end

    # Load the more generic tests for this context
    general_info_specs()

    it { is_expected.to contain_file('info.conf').with({
      :ensure => 'file',
      :path   => '/etc/apache2/mods-available/info.conf',
    } ) }
    it { is_expected.to contain_file('info.conf symlink').with({
      :ensure => 'link',
      :path   => '/etc/apache2/mods-enabled/info.conf',
    } ) }
  end

  context 'on a RedHat OS' do
    let :facts do
      {
        :osfamily               => 'RedHat',
        :operatingsystemrelease => '6',
        :concat_basedir         => '/dne',
        :operatingsystem        => 'RedHat',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end

    # Load the more generic tests for this context
    general_info_specs()

    it { is_expected.to contain_file('info.conf').with({
      :ensure => 'file',
      :path   => '/etc/httpd/conf.d/info.conf',
      } ) }
  end

  context 'on a FreeBSD OS' do
    let :facts do
      {
        :osfamily               => 'FreeBSD',
        :operatingsystemrelease => '9',
        :concat_basedir         => '/dne',
        :operatingsystem        => 'FreeBSD',
        :id                     => 'root',
        :kernel                 => 'FreeBSD',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end

    # Load the more generic tests for this context
    general_info_specs()

    it { is_expected.to contain_file('info.conf').with({
      :ensure => 'file',
      :path   => '/usr/local/etc/apache22/Modules/info.conf',
    } ) }
  end

end
require 'spec_helper'

describe 'apache::mod::itk', :type => :class do
  let :pre_condition do
    'class { "apache": mpm_module => false, }'
  end
  context "on a Debian OS" do
    let :facts do
      {
        :osfamily               => 'Debian',
        :operatingsystemrelease => '6',
        :concat_basedir         => '/dne',
        :lsbdistcodename        => 'squeeze',
        :operatingsystem        => 'Debian',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    it { is_expected.to contain_class("apache::params") }
    it { is_expected.not_to contain_apache__mod('itk') }
    it { is_expected.to contain_file("/etc/apache2/mods-available/itk.conf").with_ensure('file') }
    it { is_expected.to contain_file("/etc/apache2/mods-enabled/itk.conf").with_ensure('link') }

    context "with Apache version < 2.4" do
      let :params do
        {
          :apache_version => '2.2',
        }
      end

      it { is_expected.not_to contain_file("/etc/apache2/mods-available/itk.load") }
      it { is_expected.not_to contain_file("/etc/apache2/mods-enabled/itk.load") }

      it { is_expected.to contain_package("apache2-mpm-itk") }
    end

    context "with Apache version >= 2.4" do
      let :params do
        {
          :apache_version => '2.4',
        }
      end

      it { is_expected.to contain_file("/etc/apache2/mods-available/itk.load").with({
        'ensure'  => 'file',
        'content' => "LoadModule mpm_itk_module /usr/lib/apache2/modules/mod_mpm_itk.so\n"
        })
      }
      it { is_expected.to contain_file("/etc/apache2/mods-enabled/itk.load").with_ensure('link') }
    end
  end
  context "on a FreeBSD OS" do
    let :facts do
      {
        :osfamily               => 'FreeBSD',
        :operatingsystemrelease => '9',
        :concat_basedir         => '/dne',
        :operatingsystem        => 'FreeBSD',
        :id                     => 'root',
        :kernel                 => 'FreeBSD',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    it { is_expected.to contain_class("apache::params") }
    it { is_expected.not_to contain_apache__mod('itk') }
    it { is_expected.to contain_file("/usr/local/etc/apache22/Modules/itk.conf").with_ensure('file') }
  end
end
require 'spec_helper'

# This function is called inside the OS specific contexts
def general_mime_magic_specs
  it { is_expected.to contain_apache__mod("mime_magic") }
end

describe 'apache::mod::mime_magic', :type => :class do
  let :pre_condition do
    'include apache'
  end

  context "On a Debian OS with default params" do
    let :facts do
      {
        :osfamily               => 'Debian',
        :operatingsystemrelease => '6',
        :concat_basedir         => '/dne',
        :lsbdistcodename        => 'squeeze',
        :operatingsystem        => 'Debian',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end

    general_mime_magic_specs()

    it do
      is_expected.to contain_file("mime_magic.conf").with_content(
        "MIMEMagicFile \"/etc/apache2/magic\"\n"
      )
    end

    it { is_expected.to contain_file("mime_magic.conf").with({
      :ensure => 'file',
      :path   => '/etc/apache2/mods-available/mime_magic.conf',
    } ) }
    it { is_expected.to contain_file("mime_magic.conf symlink").with({
      :ensure => 'link',
      :path   => '/etc/apache2/mods-enabled/mime_magic.conf',
    } ) }

    context "with magic_file => /tmp/Debian_magic" do
      let :params do
        { :magic_file => "/tmp/Debian_magic" }
      end

      it do
        is_expected.to contain_file("mime_magic.conf").with_content(
          "MIMEMagicFile \"/tmp/Debian_magic\"\n"
        )
      end
    end

  end

  context "on a RedHat OS with default params" do
    let :facts do
      {
        :osfamily               => 'RedHat',
        :operatingsystemrelease => '6',
        :concat_basedir         => '/dne',
        :operatingsystem        => 'RedHat',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end

    general_mime_magic_specs()

    it do
      is_expected.to contain_file("mime_magic.conf").with_content(
        "MIMEMagicFile \"/etc/httpd/conf/magic\"\n"
      )
    end

    it { is_expected.to contain_file("mime_magic.conf").with_path("/etc/httpd/conf.d/mime_magic.conf") }

  end

  context "with magic_file => /tmp/magic" do
    let :facts do
      {
        :osfamily               => 'Debian',
        :operatingsystemrelease => '6',
        :concat_basedir         => '/dne',
        :lsbdistcodename        => 'squeeze',
        :operatingsystem        => 'Debian',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end

    let :params do
      { :magic_file => "/tmp/magic" }
    end

    it do
      is_expected.to contain_file("mime_magic.conf").with_content(
        "MIMEMagicFile \"/tmp/magic\"\n"
      )
    end
  end


end
require 'spec_helper'

# This function is called inside the OS specific conte, :compilexts
def general_mime_specs
  it { is_expected.to contain_apache__mod("mime") }
end

describe 'apache::mod::mime', :type => :class do
  let :pre_condition do
    'include apache'
  end

  context "On a Debian OS with default params", :compile do
    let :facts do
      {
        :osfamily               => 'Debian',
        :operatingsystemrelease => '6',
        :concat_basedir         => '/dne',
        :lsbdistcodename        => 'squeeze',
        :operatingsystem        => 'Debian',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end

    general_mime_specs()

    it { is_expected.to contain_file("mime.conf").with_path('/etc/apache2/mods-available/mime.conf') }

  end

  context "on a RedHat OS with default params", :compile do
    let :facts do
      {
        :osfamily               => 'RedHat',
        :operatingsystemrelease => '6',
        :concat_basedir         => '/dne',
        :operatingsystem        => 'RedHat',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end

    general_mime_specs()

    it { is_expected.to contain_file("mime.conf").with_path("/etc/httpd/conf.d/mime.conf") }

  end

end
require 'spec_helper'

describe 'apache::mod::negotiation', :type => :class do
  describe "OS independent tests" do

    let :facts do
      {
        :osfamily               => 'Debian',
        :operatingsystem        => 'Debian',
        :lsbdistcodename        => 'squeeze',
        :operatingsystemrelease => '6',
        :concat_basedir         => '/dne',
        :id                     => 'root',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end

    context "default params" do
      let :pre_condition do
        'class {"::apache": }'
      end
      it { should contain_class("apache") }
      it do
        should contain_file('negotiation.conf').with( {
          :ensure  => 'file',
          :content => 'LanguagePriority en ca cs da de el eo es et fr he hr it ja ko ltz nl nn no pl pt pt-BR ru sv zh-CN zh-TW
ForceLanguagePriority Prefer Fallback
',
        } )
      end
    end

    context 'with force_language_priority parameter' do
      let :pre_condition do
        'class {"::apache": default_mods => ["negotiation"]}'
      end
      let :params do
        { :force_language_priority => 'Prefer' }
      end
      it do
        should contain_file('negotiation.conf').with( {
          :ensure  => 'file',
          :content => /^ForceLanguagePriority Prefer$/,
        } )
      end
    end

    context 'with language_priority parameter' do
      let :pre_condition do
        'class {"::apache": default_mods => ["negotiation"]}'
      end
      let :params do
        { :language_priority => [ 'en', 'es' ] }
      end
      it do
        should contain_file('negotiation.conf').with( {
          :ensure  => 'file',
          :content => /^LanguagePriority en es$/,
        } )
      end
    end
  end
end
require 'spec_helper'

describe 'apache::mod::pagespeed', :type => :class do
  let :pre_condition do
    'include apache'
  end
  context "on a Debian OS" do
    let :facts do
      {
        :osfamily               => 'Debian',
        :operatingsystemrelease => '6',
        :concat_basedir         => '/dne',
        :lsbdistcodename        => 'squeeze',
        :operatingsystem        => 'Debian',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    it { is_expected.to contain_class("apache::params") }
    it { is_expected.to contain_apache__mod('pagespeed') }
    it { is_expected.to contain_package("mod-pagespeed-stable") }
    it { is_expected.to contain_file('pagespeed.conf') }
  end

  context "on a RedHat OS" do
    let :facts do
      {
        :osfamily               => 'RedHat',
        :operatingsystemrelease => '6',
        :concat_basedir         => '/dne',
        :operatingsystem        => 'RedHat',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    it { is_expected.to contain_class("apache::params") }
    it { is_expected.to contain_apache__mod('pagespeed') }
    it { is_expected.to contain_package("mod-pagespeed-stable") }
    it { is_expected.to contain_file('pagespeed.conf') }
  end
end
require 'spec_helper'

describe 'apache::mod::passenger', :type => :class do
  let :pre_condition do
    'include apache'
  end
  context "on a Debian OS" do
    let :facts do
      {
        :osfamily               => 'Debian',
        :operatingsystemrelease => '6',
        :concat_basedir         => '/dne',
        :lsbdistcodename        => 'squeeze',
        :operatingsystem        => 'Debian',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    it { is_expected.to contain_class("apache::params") }
    it { is_expected.to contain_apache__mod('passenger') }
    it { is_expected.to contain_package("libapache2-mod-passenger") }
    it { is_expected.to contain_file('passenger.load').with({
      'path' => '/etc/apache2/mods-available/passenger.load',
    }) }
    it { is_expected.to contain_file('passenger.conf').with({
      'path' => '/etc/apache2/mods-available/passenger.conf',
    }) }
    it { is_expected.to contain_file('passenger_package.conf').with_ensure('absent') }
    describe "with passenger_root => '/usr/lib/example'" do
      let :params do
        { :passenger_root => '/usr/lib/example' }
      end
      it { is_expected.to contain_file('passenger.conf').with_content(%r{PassengerRoot "/usr/lib/example"}) }
    end
    describe "with passenger_ruby => /usr/lib/example/ruby" do
      let :params do
        { :passenger_ruby => '/usr/lib/example/ruby' }
      end
      it { is_expected.to contain_file('passenger.conf').with_content(%r{PassengerRuby "/usr/lib/example/ruby"}) }
    end
    describe "with passenger_default_ruby => /usr/lib/example/ruby1.9.3" do
      let :params do
        { :passenger_ruby => '/usr/lib/example/ruby1.9.3' }
      end
      it { is_expected.to contain_file('passenger.conf').with_content(%r{PassengerRuby "/usr/lib/example/ruby1.9.3"}) }
    end
    describe "with passenger_high_performance => on" do
      let :params do
        { :passenger_high_performance => 'on' }
      end
      it { is_expected.to contain_file('passenger.conf').with_content(/^  PassengerHighPerformance on$/) }
    end
    describe "with passenger_pool_idle_time => 1200" do
      let :params do
        { :passenger_pool_idle_time => 1200 }
      end
      it { is_expected.to contain_file('passenger.conf').with_content(/^  PassengerPoolIdleTime 1200$/) }
    end
    describe "with passenger_max_requests => 20" do
      let :params do
        { :passenger_max_requests => 20 }
      end
      it { is_expected.to contain_file('passenger.conf').with_content(/^  PassengerMaxRequests 20$/) }
    end
    describe "with passenger_stat_throttle_rate => 10" do
      let :params do
        { :passenger_stat_throttle_rate => 10 }
      end
      it { is_expected.to contain_file('passenger.conf').with_content(/^  PassengerStatThrottleRate 10$/) }
    end
    describe "with passenger_max_pool_size => 16" do
      let :params do
        { :passenger_max_pool_size => 16 }
      end
      it { is_expected.to contain_file('passenger.conf').with_content(/^  PassengerMaxPoolSize 16$/) }
    end
    describe "with rack_autodetect => on" do
      let :params do
        { :rack_autodetect => 'on' }
      end
      it { is_expected.to contain_file('passenger.conf').with_content(/^  RackAutoDetect on$/) }
    end
    describe "with rails_autodetect => on" do
      let :params do
        { :rails_autodetect => 'on' }
      end
      it { is_expected.to contain_file('passenger.conf').with_content(/^  RailsAutoDetect on$/) }
    end
    describe "with passenger_use_global_queue => on" do
      let :params do
        { :passenger_use_global_queue => 'on' }
      end
      it { is_expected.to contain_file('passenger.conf').with_content(/^  PassengerUseGlobalQueue on$/) }
    end
    describe "with mod_path => '/usr/lib/foo/mod_foo.so'" do
      let :params do
        { :mod_path => '/usr/lib/foo/mod_foo.so' }
      end
      it { is_expected.to contain_file('passenger.load').with_content(/^LoadModule passenger_module \/usr\/lib\/foo\/mod_foo\.so$/) }
    end
    describe "with mod_lib_path => '/usr/lib/foo'" do
      let :params do
        { :mod_lib_path => '/usr/lib/foo' }
      end
      it { is_expected.to contain_file('passenger.load').with_content(/^LoadModule passenger_module \/usr\/lib\/foo\/mod_passenger\.so$/) }
    end
    describe "with mod_lib => 'mod_foo.so'" do
      let :params do
        { :mod_lib => 'mod_foo.so' }
      end
      it { is_expected.to contain_file('passenger.load').with_content(/^LoadModule passenger_module \/usr\/lib\/apache2\/modules\/mod_foo\.so$/) }
    end
    describe "with mod_id => 'mod_foo'" do
      let :params do
        { :mod_id => 'mod_foo' }
      end
      it { is_expected.to contain_file('passenger.load').with_content(/^LoadModule mod_foo \/usr\/lib\/apache2\/modules\/mod_passenger\.so$/) }
    end

    context "with Ubuntu 12.04 defaults" do
      let :facts do
        {
          :osfamily               => 'Debian',
          :operatingsystemrelease => '12.04',
          :operatingsystem        => 'Ubuntu',
          :lsbdistrelease         => '12.04',
          :concat_basedir         => '/dne',
          :id                     => 'root',
          :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
        }
      end

      it { is_expected.to contain_file('passenger.conf').with_content(%r{PassengerRoot "/usr"}) }
      it { is_expected.to contain_file('passenger.conf').with_content(%r{PassengerRuby "/usr/bin/ruby"}) }
      it { is_expected.to contain_file('passenger.conf').without_content(/PassengerDefaultRuby/) }
    end

    context "with Ubuntu 14.04 defaults" do
      let :facts do
        {
          :osfamily               => 'Debian',
          :operatingsystemrelease => '14.04',
          :operatingsystem        => 'Ubuntu',
          :lsbdistrelease         => '14.04',
          :concat_basedir         => '/dne',
          :id                     => 'root',
          :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
        }
      end

      it { is_expected.to contain_file('passenger.conf').with_content(%r{PassengerRoot "/usr/lib/ruby/vendor_ruby/phusion_passenger/locations.ini"}) }
      it { is_expected.to contain_file('passenger.conf').without_content(/PassengerRuby/) }
      it { is_expected.to contain_file('passenger.conf').with_content(%r{PassengerDefaultRuby "/usr/bin/ruby"}) }
    end

    context "with Debian 7 defaults" do
      let :facts do
        {
          :osfamily               => 'Debian',
          :operatingsystemrelease => '7.3',
          :operatingsystem        => 'Debian',
          :lsbdistcodename        => 'wheezy',
          :concat_basedir         => '/dne',
          :id                     => 'root',
          :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
        }
      end

      it { is_expected.to contain_file('passenger.conf').with_content(%r{PassengerRoot "/usr"}) }
      it { is_expected.to contain_file('passenger.conf').with_content(%r{PassengerRuby "/usr/bin/ruby"}) }
      it { is_expected.to contain_file('passenger.conf').without_content(/PassengerDefaultRuby/) }
    end
  end

  context "on a RedHat OS" do
    let :facts do
      {
        :osfamily               => 'RedHat',
        :operatingsystemrelease => '6',
        :concat_basedir         => '/dne',
        :operatingsystem        => 'RedHat',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    it { is_expected.to contain_class("apache::params") }
    it { is_expected.to contain_apache__mod('passenger') }
    it { is_expected.to contain_package("mod_passenger") }
    it { is_expected.to contain_file('passenger_package.conf').with({
      'path' => '/etc/httpd/conf.d/passenger.conf',
    }) }
    it { is_expected.to contain_file('passenger_package.conf').without_content }
    it { is_expected.to contain_file('passenger_package.conf').without_source }
    it { is_expected.to contain_file('passenger.load').with({
      'path' => '/etc/httpd/conf.d/passenger.load',
    }) }
    it { is_expected.to contain_file('passenger.conf').without_content(/PassengerRoot/) }
    it { is_expected.to contain_file('passenger.conf').without_content(/PassengerRuby/) }
    describe "with passenger_root => '/usr/lib/example'" do
      let :params do
        { :passenger_root => '/usr/lib/example' }
      end
      it { is_expected.to contain_file('passenger.conf').with_content(/^  PassengerRoot "\/usr\/lib\/example"$/) }
    end
    describe "with passenger_ruby => /usr/lib/example/ruby" do
      let :params do
        { :passenger_ruby => '/usr/lib/example/ruby' }
      end
      it { is_expected.to contain_file('passenger.conf').with_content(/^  PassengerRuby "\/usr\/lib\/example\/ruby"$/) }
    end
  end
  context "on a FreeBSD OS" do
    let :facts do
      {
        :osfamily               => 'FreeBSD',
        :operatingsystemrelease => '9',
        :concat_basedir         => '/dne',
        :operatingsystem        => 'FreeBSD',
        :id                     => 'root',
        :kernel                 => 'FreeBSD',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    it { is_expected.to contain_class("apache::params") }
    it { is_expected.to contain_apache__mod('passenger') }
    it { is_expected.to contain_package("www/rubygem-passenger") }
  end
end
require 'spec_helper'

describe 'apache::mod::perl', :type => :class do
  let :pre_condition do
    'include apache'
  end
  context "on a Debian OS" do
    let :facts do
      {
        :osfamily               => 'Debian',
        :operatingsystemrelease => '6',
        :concat_basedir         => '/dne',
        :lsbdistcodename        => 'squeeze',
        :operatingsystem        => 'Debian',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    it { is_expected.to contain_class("apache::params") }
    it { is_expected.to contain_apache__mod('perl') }
    it { is_expected.to contain_package("libapache2-mod-perl2") }
  end
  context "on a RedHat OS" do
    let :facts do
      {
        :osfamily               => 'RedHat',
        :operatingsystemrelease => '6',
        :concat_basedir         => '/dne',
        :operatingsystem        => 'RedHat',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    it { is_expected.to contain_class("apache::params") }
    it { is_expected.to contain_apache__mod('perl') }
    it { is_expected.to contain_package("mod_perl") }
  end
  context "on a FreeBSD OS" do
    let :facts do
      {
        :osfamily               => 'FreeBSD',
        :operatingsystemrelease => '9',
        :concat_basedir         => '/dne',
        :operatingsystem        => 'FreeBSD',
        :id                     => 'root',
        :kernel                 => 'FreeBSD',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    it { is_expected.to contain_class("apache::params") }
    it { is_expected.to contain_apache__mod('perl') }
    it { is_expected.to contain_package("www/mod_perl2") }
  end
end
require 'spec_helper'

describe 'apache::mod::peruser', :type => :class do
  let :pre_condition do
    'class { "apache": mpm_module => false, }'
  end
  context "on a FreeBSD OS" do
    let :facts do
      {
        :osfamily               => 'FreeBSD',
        :operatingsystemrelease => '9',
        :concat_basedir         => '/dne',
        :operatingsystem        => 'FreeBSD',
        :id                     => 'root',
        :kernel                 => 'FreeBSD',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    it { is_expected.to contain_class("apache::params") }
    it { is_expected.not_to contain_apache__mod('peruser') }
    it { is_expected.to contain_file("/usr/local/etc/apache22/Modules/peruser.conf").with_ensure('file') }
  end
end
require 'spec_helper'

describe 'apache::mod::php', :type => :class do
  describe "on a Debian OS" do
    let :facts do
      {
        :osfamily               => 'Debian',
        :operatingsystemrelease => '6',
        :concat_basedir         => '/dne',
        :lsbdistcodename        => 'squeeze',
        :operatingsystem        => 'Debian',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    context "with mpm_module => prefork" do
      let :pre_condition do
        'class { "apache": mpm_module => prefork, }'
      end
      it { is_expected.to contain_class("apache::params") }
      it { is_expected.to contain_apache__mod('php5') }
      it { is_expected.to contain_package("libapache2-mod-php5") }
      it { is_expected.to contain_file("php5.load").with(
        :content => "LoadModule php5_module /usr/lib/apache2/modules/libphp5.so\n"
      ) }
    end
    context 'with mpm_module => worker' do
      let :pre_condition do
        'class { "apache": mpm_module => worker, }'
      end
      it 'should raise an error' do
        expect { subject }.to raise_error Puppet::Error, /mpm_module => 'prefork'/
      end
    end
  end
  describe "on a RedHat OS" do
    let :facts do
      {
        :osfamily               => 'RedHat',
        :operatingsystemrelease => '6',
        :concat_basedir         => '/dne',
        :operatingsystem        => 'RedHat',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    context "with default params" do
      let :pre_condition do
        'class { "apache": }'
      end
      it { is_expected.to contain_class("apache::params") }
      it { is_expected.to contain_apache__mod('php5') }
      it { is_expected.to contain_package("php") }
      it { is_expected.to contain_file("php5.load").with(
        :content => "LoadModule php5_module modules/libphp5.so\n"
      ) }
    end
    context "with alternative package name" do let :pre_condition do
        'class { "apache": }'
      end
      let :params do
        { :package_name => 'php54'}
      end
      it { is_expected.to contain_package("php54") }
    end
    context "with alternative path" do let :pre_condition do
        'class { "apache": }'
      end
      let :params do
        { :path => 'alternative-path'}
      end
      it { is_expected.to contain_file("php5.load").with(
        :content => "LoadModule php5_module alternative-path\n"
      ) }
    end
    context "with alternative extensions" do let :pre_condition do
        'class { "apache": }'
      end
      let :params do
        { :extensions => ['.php','.php5']}
      end
      it { is_expected.to contain_file("php5.conf").with_content(/AddHandler php5-script .php .php5\n/) }
    end
    context "with specific version" do
      let :pre_condition do
        'class { "apache": }'
      end
      let :params do
        { :package_ensure => '5.3.13'}
      end
      it { is_expected.to contain_package("php").with(
        :ensure => '5.3.13'
      ) }
    end
    context "with mpm_module => prefork" do
      let :pre_condition do
        'class { "apache": mpm_module => prefork, }'
      end
      it { is_expected.to contain_class("apache::params") }
      it { is_expected.to contain_apache__mod('php5') }
      it { is_expected.to contain_package("php") }
      it { is_expected.to contain_file("php5.load").with(
        :content => "LoadModule php5_module modules/libphp5.so\n"
      ) }
    end
  end
  describe "on a FreeBSD OS" do
    let :facts do
      {
        :osfamily               => 'FreeBSD',
        :operatingsystemrelease => '9',
        :concat_basedir         => '/dne',
        :operatingsystem        => 'FreeBSD',
        :id                     => 'root',
        :kernel                 => 'FreeBSD',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    context "with mpm_module => prefork" do
      let :pre_condition do
        'class { "apache": mpm_module => prefork, }'
      end
      it { is_expected.to contain_class('apache::params') }
      it { is_expected.to contain_apache__mod('php5') }
      it { is_expected.to contain_package("lang/php5") }
      it { is_expected.to contain_file('php5.load') }
    end
    # FIXME: not sure about the following context
    context 'with mpm_module => worker' do
      let :pre_condition do
        'class { "apache": mpm_module => worker, }'
      end
      it 'should raise an error' do
        expect { expect(subject).to contain_apache__mod('php5') }.to raise_error Puppet::Error, /mpm_module => 'prefork'/
      end
    end
  end
  describe "OS independent tests" do
    let :facts do
      {
        :osfamily               => 'Debian',
        :operatingsystem        => 'Debian',
        :operatingsystemrelease => '6',
        :lsbdistcodename        => 'squeeze',
        :concat_basedir         => '/dne',
        :id                     => 'root',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    context 'with content param' do
      let :pre_condition do
        'class { "apache": mpm_module => prefork, }'
      end
      let :params do
        { :content => 'somecontent' }
      end
      it { should contain_file('php5.conf').with(
        :content => 'somecontent'
      ) }
    end
    context 'with template param' do
      let :pre_condition do
        'class { "apache": mpm_module => prefork, }'
      end
      let :params do
        { :template => 'apache/mod/php5.conf.erb' }
      end
      it { should contain_file('php5.conf').with(
        :content => /^# PHP is an HTML-embedded scripting language which attempts to make it/
      ) }
    end
    context 'with source param' do
      let :pre_condition do
        'class { "apache": mpm_module => prefork, }'
      end
      let :params do
        { :source => 'some-path' }
      end
      it { should contain_file('php5.conf').with(
        :source => 'some-path'
      ) }
    end
    context 'content has priority over template' do
      let :pre_condition do
        'class { "apache": mpm_module => prefork, }'
      end
      let :params do
        {
          :template => 'apache/mod/php5.conf.erb',
          :content  => 'somecontent'
        }
      end
      it { should contain_file('php5.conf').with(
        :content => 'somecontent'
      ) }
    end
    context 'source has priority over template' do
      let :pre_condition do
        'class { "apache": mpm_module => prefork, }'
      end
      let :params do
        {
          :template => 'apache/mod/php5.conf.erb',
          :source   => 'some-path'
        }
      end
      it { should contain_file('php5.conf').with(
        :source => 'some-path'
      ) }
    end
    context 'source has priority over content' do
      let :pre_condition do
        'class { "apache": mpm_module => prefork, }'
      end
      let :params do
        {
          :content => 'somecontent',
          :source  => 'some-path'
        }
      end
      it { should contain_file('php5.conf').with(
        :source => 'some-path'
      ) }
    end
  end
end
require 'spec_helper'

describe 'apache::mod::prefork', :type => :class do
  let :pre_condition do
    'class { "apache": mpm_module => false, }'
  end
  context "on a Debian OS" do
    let :facts do
      {
        :osfamily               => 'Debian',
        :operatingsystemrelease => '6',
        :concat_basedir         => '/dne',
        :lsbdistcodename        => 'squeeze',
        :operatingsystem        => 'Debian',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    it { is_expected.to contain_class("apache::params") }
    it { is_expected.not_to contain_apache__mod('prefork') }
    it { is_expected.to contain_file("/etc/apache2/mods-available/prefork.conf").with_ensure('file') }
    it { is_expected.to contain_file("/etc/apache2/mods-enabled/prefork.conf").with_ensure('link') }

    context "with Apache version < 2.4" do
      let :params do
        {
          :apache_version => '2.2',
        }
      end

      it { is_expected.not_to contain_file("/etc/apache2/mods-available/prefork.load") }
      it { is_expected.not_to contain_file("/etc/apache2/mods-enabled/prefork.load") }

      it { is_expected.to contain_package("apache2-mpm-prefork") }
    end

    context "with Apache version >= 2.4" do
      let :params do
        {
          :apache_version => '2.4',
        }
      end

      it { is_expected.to contain_file("/etc/apache2/mods-available/prefork.load").with({
        'ensure'  => 'file',
        'content' => "LoadModule mpm_prefork_module /usr/lib/apache2/modules/mod_mpm_prefork.so\n"
        })
      }
      it { is_expected.to contain_file("/etc/apache2/mods-enabled/prefork.load").with_ensure('link') }
    end
  end
  context "on a RedHat OS" do
    let :facts do
      {
        :osfamily               => 'RedHat',
        :operatingsystemrelease => '6',
        :concat_basedir         => '/dne',
        :operatingsystem        => 'RedHat',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    it { is_expected.to contain_class("apache::params") }
    it { is_expected.not_to contain_apache__mod('prefork') }
    it { is_expected.to contain_file("/etc/httpd/conf.d/prefork.conf").with_ensure('file') }

    context "with Apache version < 2.4" do
      let :params do
        {
          :apache_version => '2.2',
        }
      end

      it { is_expected.to contain_file_line("/etc/sysconfig/httpd prefork enable").with({
        'require' => 'Package[httpd]',
        })
      }
    end

    context "with Apache version >= 2.4" do
      let :params do
        {
          :apache_version => '2.4',
        }
      end

      it { is_expected.not_to contain_apache__mod('event') }

      it { is_expected.to contain_file("/etc/httpd/conf.d/prefork.load").with({
        'ensure'  => 'file',
        'content' => "LoadModule mpm_prefork_module modules/mod_mpm_prefork.so\n",
        })
      }
    end
  end
  context "on a FreeBSD OS" do
    let :facts do
      {
        :osfamily               => 'FreeBSD',
        :operatingsystemrelease => '9',
        :concat_basedir         => '/dne',
        :operatingsystem        => 'FreeBSD',
        :id                     => 'root',
        :kernel                 => 'FreeBSD',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    it { is_expected.to contain_class("apache::params") }
    it { is_expected.not_to contain_apache__mod('prefork') }
    it { is_expected.to contain_file("/usr/local/etc/apache22/Modules/prefork.conf").with_ensure('file') }
  end
end
require 'spec_helper'

describe 'apache::mod::proxy_html', :type => :class do
  let :pre_condition do
    [
      'include apache',
      'include apache::mod::proxy',
      'include apache::mod::proxy_http',
    ]
  end
  context "on a Debian OS" do
    shared_examples "debian" do |loadfiles|
      it { is_expected.to contain_class("apache::params") }
      it { is_expected.to contain_apache__mod('proxy_html').with(:loadfiles => loadfiles) }
      it { is_expected.to contain_package("libapache2-mod-proxy-html") }
    end
    let :facts do
      {
        :osfamily        => 'Debian',
        :concat_basedir  => '/dne',
        :architecture    => 'i386',
        :lsbdistcodename => 'squeeze',
        :operatingsystem => 'Debian',
        :id              => 'root',
        :kernel          => 'Linux',
        :path            => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
        :hardwaremodel   => 'i386',
      }
    end

    context "on squeeze" do
      let(:facts) { super().merge({ :operatingsystemrelease => '6' }) }
      it_behaves_like "debian", ['/usr/lib/libxml2.so.2']
    end
    context "on wheezy" do
      let(:facts) { super().merge({ :operatingsystemrelease => '7' }) }
      context "i386" do
        let(:facts) { super().merge({
          :hardwaremodel => 'i686',
          :architecture  => 'i386'
        })}
        it_behaves_like "debian", ["/usr/lib/i386-linux-gnu/libxml2.so.2"]
      end
      context "x64" do
        let(:facts) { super().merge({
          :hardwaremodel => 'x86_64',
          :architecture  => 'amd64'
        })}
        it_behaves_like "debian", ["/usr/lib/x86_64-linux-gnu/libxml2.so.2"]
      end
    end
  end
  context "on a RedHat OS", :compile do
    let :facts do
      {
        :osfamily               => 'RedHat',
        :operatingsystemrelease => '6',
        :concat_basedir         => '/dne',
        :operatingsystem        => 'RedHat',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    it { is_expected.to contain_class("apache::params") }
    it { is_expected.to contain_apache__mod('proxy_html').with(:loadfiles => nil) }
    it { is_expected.to contain_package("mod_proxy_html") }
  end
  context "on a FreeBSD OS", :compile do
    let :facts do
      {
        :osfamily               => 'FreeBSD',
        :operatingsystemrelease => '9',
        :concat_basedir         => '/dne',
        :operatingsystem        => 'FreeBSD',
        :id                     => 'root',
        :kernel                 => 'FreeBSD',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    it { is_expected.to contain_class("apache::params") }
    it { is_expected.to contain_apache__mod('proxy_html').with(:loadfiles => nil) }
    it { is_expected.to contain_package("www/mod_proxy_html") }
  end
end
require 'spec_helper'

describe 'apache::mod::python', :type => :class do
  let :pre_condition do
    'include apache'
  end
  context "on a Debian OS" do
    let :facts do
      {
        :osfamily               => 'Debian',
        :operatingsystemrelease => '6',
        :concat_basedir         => '/dne',
        :lsbdistcodename        => 'squeeze',
        :operatingsystem        => 'Debian',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    it { is_expected.to contain_class("apache::params") }
    it { is_expected.to contain_apache__mod("python") }
    it { is_expected.to contain_package("libapache2-mod-python") }
  end
  context "on a RedHat OS" do
    let :facts do
      {
        :osfamily               => 'RedHat',
        :operatingsystemrelease => '6',
        :concat_basedir         => '/dne',
        :operatingsystem        => 'RedHat',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    it { is_expected.to contain_class("apache::params") }
    it { is_expected.to contain_apache__mod("python") }
    it { is_expected.to contain_package("mod_python") }
  end
  context "on a FreeBSD OS" do
    let :facts do
      {
        :osfamily               => 'FreeBSD',
        :operatingsystemrelease => '9',
        :concat_basedir         => '/dne',
        :operatingsystem        => 'FreeBSD',
        :id                     => 'root',
        :kernel                 => 'FreeBSD',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    it { is_expected.to contain_class("apache::params") }
    it { is_expected.to contain_apache__mod("python") }
    it { is_expected.to contain_package("www/mod_python3") }
  end
end
require 'spec_helper'

describe 'apache::mod::rpaf', :type => :class do
  let :pre_condition do
    [
      'include apache',
    ]
  end
  context "on a Debian OS" do
    let :facts do
      {
        :osfamily               => 'Debian',
        :operatingsystemrelease => '6',
        :concat_basedir         => '/dne',
        :lsbdistcodename        => 'squeeze',
        :operatingsystem        => 'Debian',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    it { is_expected.to contain_class("apache::params") }
    it { is_expected.to contain_apache__mod('rpaf') }
    it { is_expected.to contain_package("libapache2-mod-rpaf") }
    it { is_expected.to contain_file('rpaf.conf').with({
      'path' => '/etc/apache2/mods-available/rpaf.conf',
    }) }
    it { is_expected.to contain_file('rpaf.conf').with_content(/^RPAFenable On$/) }

    describe "with sethostname => true" do
      let :params do
        { :sethostname => 'true' }
      end
      it { is_expected.to contain_file('rpaf.conf').with_content(/^RPAFsethostname On$/) }
    end
    describe "with proxy_ips => [ 10.42.17.8, 10.42.18.99 ]" do
      let :params do
        { :proxy_ips => [ '10.42.17.8', '10.42.18.99' ] }
      end
      it { is_expected.to contain_file('rpaf.conf').with_content(/^RPAFproxy_ips 10.42.17.8 10.42.18.99$/) }
    end
    describe "with header => X-Real-IP" do
      let :params do
        { :header => 'X-Real-IP' }
      end
      it { is_expected.to contain_file('rpaf.conf').with_content(/^RPAFheader X-Real-IP$/) }
    end
  end
  context "on a FreeBSD OS" do
    let :facts do
      {
        :osfamily               => 'FreeBSD',
        :operatingsystemrelease => '9',
        :concat_basedir         => '/dne',
        :operatingsystem        => 'FreeBSD',
        :id                     => 'root',
        :kernel                 => 'FreeBSD',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    it { is_expected.to contain_class("apache::params") }
    it { is_expected.to contain_apache__mod('rpaf') }
    it { is_expected.to contain_package("www/mod_rpaf2") }
    it { is_expected.to contain_file('rpaf.conf').with({
      'path' => '/usr/local/etc/apache22/Modules/rpaf.conf',
    }) }
    it { is_expected.to contain_file('rpaf.conf').with_content(/^RPAFenable On$/) }

    describe "with sethostname => true" do
      let :params do
        { :sethostname => 'true' }
      end
      it { is_expected.to contain_file('rpaf.conf').with_content(/^RPAFsethostname On$/) }
    end
    describe "with proxy_ips => [ 10.42.17.8, 10.42.18.99 ]" do
      let :params do
        { :proxy_ips => [ '10.42.17.8', '10.42.18.99' ] }
      end
      it { is_expected.to contain_file('rpaf.conf').with_content(/^RPAFproxy_ips 10.42.17.8 10.42.18.99$/) }
    end
    describe "with header => X-Real-IP" do
      let :params do
        { :header => 'X-Real-IP' }
      end
      it { is_expected.to contain_file('rpaf.conf').with_content(/^RPAFheader X-Real-IP$/) }
    end
  end
end
require 'spec_helper'

describe 'apache::mod::speling', :type => :class do
  let :pre_condition do
    'include apache'
  end
  context "on a Debian OS" do
    let :facts do
      {
        :osfamily               => 'Debian',
        :operatingsystemrelease => '6',
        :concat_basedir         => '/dne',
        :lsbdistcodename        => 'squeeze',
        :operatingsystem        => 'Debian',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    it { is_expected.to contain_apache__mod('speling') }
  end

  context "on a RedHat OS" do
    let :facts do
      {
        :osfamily               => 'RedHat',
        :operatingsystemrelease => '6',
        :concat_basedir         => '/dne',
        :operatingsystem        => 'RedHat',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    it { is_expected.to contain_apache__mod('speling') }
  end
end
require 'spec_helper'

describe 'apache::mod::ssl', :type => :class do
  let :pre_condition do
    'include apache'
  end
  context 'on an unsupported OS' do
    let :facts do
      {
        :osfamily               => 'Magic',
        :operatingsystemrelease => '0',
        :concat_basedir         => '/dne',
        :operatingsystem        => 'Magic',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    it { expect { subject }.to raise_error(Puppet::Error, /Unsupported osfamily:/) }
  end

  context 'on a RedHat OS' do
    let :facts do
      {
        :osfamily               => 'RedHat',
        :operatingsystemrelease => '6',
        :concat_basedir         => '/dne',
        :operatingsystem        => 'RedHat',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    it { is_expected.to contain_class('apache::params') }
    it { is_expected.to contain_apache__mod('ssl') }
    it { is_expected.to contain_package('mod_ssl') }
  end

  context 'on a Debian OS' do
    let :facts do
      {
        :osfamily               => 'Debian',
        :operatingsystemrelease => '6',
        :concat_basedir         => '/dne',
        :lsbdistcodename        => 'squeeze',
        :operatingsystem        => 'Debian',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    it { is_expected.to contain_class('apache::params') }
    it { is_expected.to contain_apache__mod('ssl') }
    it { is_expected.not_to contain_package('libapache2-mod-ssl') }
  end

  context 'on a FreeBSD OS' do
    let :facts do
      {
        :osfamily               => 'FreeBSD',
        :operatingsystemrelease => '9',
        :concat_basedir         => '/dne',
        :operatingsystem        => 'FreeBSD',
        :id                     => 'root',
        :kernel                 => 'FreeBSD',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    it { is_expected.to contain_class('apache::params') }
    it { is_expected.to contain_apache__mod('ssl') }
  end
end
require 'spec_helper'

# Helper function for testing the contents of `status.conf`
def status_conf_spec(allow_from, extended_status)
  it do
    is_expected.to contain_file("status.conf").with_content(
      "<Location /server-status>\n"\
      "    SetHandler server-status\n"\
      "    Order deny,allow\n"\
      "    Deny from all\n"\
      "    Allow from #{Array(allow_from).join(' ')}\n"\
      "</Location>\n"\
      "ExtendedStatus #{extended_status}\n"\
      "\n"\
      "<IfModule mod_proxy.c>\n"\
      "    # Show Proxy LoadBalancer status in mod_status\n"\
      "    ProxyStatus On\n"\
      "</IfModule>\n"
    )
  end
end

describe 'apache::mod::status', :type => :class do
  let :pre_condition do
    'include apache'
  end

  context "on a Debian OS with default params" do
    let :facts do
      {
        :osfamily               => 'Debian',
        :operatingsystemrelease => '6',
        :concat_basedir         => '/dne',
        :lsbdistcodename        => 'squeeze',
        :operatingsystem        => 'Debian',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end

    it { is_expected.to contain_apache__mod("status") }

    status_conf_spec(["127.0.0.1", "::1"], "On")

    it { is_expected.to contain_file("status.conf").with({
      :ensure => 'file',
      :path   => '/etc/apache2/mods-available/status.conf',
    } ) }

    it { is_expected.to contain_file("status.conf symlink").with({
      :ensure => 'link',
      :path   => '/etc/apache2/mods-enabled/status.conf',
    } ) }

  end

  context "on a RedHat OS with default params" do
    let :facts do
      {
        :osfamily               => 'RedHat',
        :operatingsystemrelease => '6',
        :concat_basedir         => '/dne',
        :operatingsystem        => 'RedHat',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end

    it { is_expected.to contain_apache__mod("status") }

    status_conf_spec(["127.0.0.1", "::1"], "On")

    it { is_expected.to contain_file("status.conf").with_path("/etc/httpd/conf.d/status.conf") }

  end

  context "with custom parameters $allow_from => ['10.10.10.10','11.11.11.11'], $extended_status => 'Off'" do
    let :facts do
      {
        :osfamily               => 'Debian',
        :operatingsystemrelease => '6',
        :concat_basedir         => '/dne',
        :lsbdistcodename        => 'squeeze',
        :operatingsystem        => 'Debian',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    let :params do
      {
        :allow_from => ['10.10.10.10','11.11.11.11'],
        :extended_status => 'Off',
      }
    end

    status_conf_spec(["10.10.10.10", "11.11.11.11"], "Off")

  end

  context "with valid parameter type $allow_from => ['10.10.10.10']" do
    let :facts do
      {
        :osfamily               => 'Debian',
        :operatingsystemrelease => '6',
        :concat_basedir         => '/dne',
        :lsbdistcodename        => 'squeeze',
        :operatingsystem        => 'Debian',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    let :params do
      { :allow_from => ['10.10.10.10'] }
    end
    it 'should expect to succeed array validation' do
      expect {
        is_expected.to contain_file("status.conf")
      }.not_to raise_error()
    end
  end

  context "with invalid parameter type $allow_from => '10.10.10.10'" do
    let :facts do
      {
        :osfamily               => 'Debian',
        :operatingsystemrelease => '6',
        :concat_basedir         => '/dne',
        :operatingsystem        => 'Debian',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    let :params do
      { :allow_from => '10.10.10.10' }
    end
    it 'should expect to fail array validation' do
      expect {
        is_expected.to contain_file("status.conf")
      }.to raise_error(Puppet::Error)
    end
  end

  # Only On or Off are valid options
  ['On', 'Off'].each do |valid_param|
    context "with valid value $extended_status => '#{valid_param}'" do
      let :facts do
        {
          :osfamily               => 'Debian',
          :operatingsystemrelease => '6',
          :concat_basedir         => '/dne',
          :lsbdistcodename        => 'squeeze',
          :operatingsystem        => 'Debian',
          :id                     => 'root',
          :kernel                 => 'Linux',
          :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
        }
      end
      let :params do
        { :extended_status => valid_param }
      end
      it 'should expect to succeed regular expression validation' do
        expect {
          is_expected.to contain_file("status.conf")
        }.not_to raise_error()
      end
    end
  end

  ['Yes', 'No'].each do |invalid_param|
    context "with invalid value $extended_status => '#{invalid_param}'" do
      let :facts do
        {
          :osfamily               => 'Debian',
          :operatingsystemrelease => '6',
          :concat_basedir         => '/dne',
          :operatingsystem        => 'Debian',
          :id                     => 'root',
          :kernel                 => 'Linux',
          :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
        }
      end
      let :params do
        { :extended_status => invalid_param }
      end
      it 'should expect to fail regular expression validation' do
        expect {
          is_expected.to contain_file("status.conf")
        }.to raise_error(Puppet::Error)
      end
    end
  end

end
require 'spec_helper'

describe 'apache::mod::suphp', :type => :class do
  let :pre_condition do
    'include apache'
  end
  context "on a Debian OS" do
    let :facts do
      {
        :osfamily               => 'Debian',
        :operatingsystemrelease => '6',
        :concat_basedir         => '/dne',
        :lsbdistcodename        => 'squeeze',
        :operatingsystem        => 'Debian',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    it { is_expected.to contain_class("apache::params") }
    it { is_expected.to contain_package("libapache2-mod-suphp") }
  end
  context "on a RedHat OS" do
    let :facts do
      {
        :osfamily               => 'RedHat',
        :operatingsystemrelease => '6',
        :concat_basedir         => '/dne',
        :operatingsystem        => 'RedHat',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    it { is_expected.to contain_class("apache::params") }
    it { is_expected.to contain_package("mod_suphp") }
  end
end
require 'spec_helper'

describe 'apache::mod::worker', :type => :class do
  let :pre_condition do
    'class { "apache": mpm_module => false, }'
  end
  context "on a Debian OS" do
    let :facts do
      {
        :osfamily               => 'Debian',
        :operatingsystemrelease => '6',
        :concat_basedir         => '/dne',
        :lsbdistcodename        => 'squeeze',
        :operatingsystem        => 'Debian',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    it { is_expected.to contain_class("apache::params") }
    it { is_expected.not_to contain_apache__mod('worker') }
    it { is_expected.to contain_file("/etc/apache2/mods-available/worker.conf").with_ensure('file') }
    it { is_expected.to contain_file("/etc/apache2/mods-enabled/worker.conf").with_ensure('link') }

    context "with Apache version < 2.4" do
      let :params do
        {
          :apache_version => '2.2',
        }
      end

      it { is_expected.not_to contain_file("/etc/apache2/mods-available/worker.load") }
      it { is_expected.not_to contain_file("/etc/apache2/mods-enabled/worker.load") }

      it { is_expected.to contain_package("apache2-mpm-worker") }
    end

    context "with Apache version >= 2.4" do
      let :params do
        {
          :apache_version => '2.4',
        }
      end

      it { is_expected.to contain_file("/etc/apache2/mods-available/worker.load").with({
        'ensure'  => 'file',
        'content' => "LoadModule mpm_worker_module /usr/lib/apache2/modules/mod_mpm_worker.so\n"
        })
      }
      it { is_expected.to contain_file("/etc/apache2/mods-enabled/worker.load").with_ensure('link') }
    end
  end
  context "on a RedHat OS" do
    let :facts do
      {
        :osfamily               => 'RedHat',
        :operatingsystemrelease => '6',
        :concat_basedir         => '/dne',
        :operatingsystem        => 'RedHat',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    it { is_expected.to contain_class("apache::params") }
    it { is_expected.not_to contain_apache__mod('worker') }
    it { is_expected.to contain_file("/etc/httpd/conf.d/worker.conf").with_ensure('file') }

    context "with Apache version < 2.4" do
      let :params do
        {
          :apache_version => '2.2',
        }
      end

      it { is_expected.to contain_file_line("/etc/sysconfig/httpd worker enable").with({
        'require' => 'Package[httpd]',
        })
      }
    end

    context "with Apache version >= 2.4" do
      let :params do
        {
          :apache_version => '2.4',
        }
      end

      it { is_expected.not_to contain_apache__mod('event') }

      it { is_expected.to contain_file("/etc/httpd/conf.d/worker.load").with({
        'ensure'  => 'file',
        'content' => "LoadModule mpm_worker_module modules/mod_mpm_worker.so\n",
        })
      }
    end
  end
  context "on a FreeBSD OS" do
    let :facts do
      {
        :osfamily               => 'FreeBSD',
        :operatingsystemrelease => '9',
        :concat_basedir         => '/dne',
        :operatingsystem        => 'FreeBSD',
        :id                     => 'root',
        :kernel                 => 'FreeBSD',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    it { is_expected.to contain_class("apache::params") }
    it { is_expected.not_to contain_apache__mod('worker') }
    it { is_expected.to contain_file("/usr/local/etc/apache22/Modules/worker.conf").with_ensure('file') }
  end

  # Template config doesn't vary by distro
  context "on all distros" do
    let :facts do
      {
        :osfamily               => 'RedHat',
        :operatingsystem        => 'CentOS',
        :operatingsystemrelease => '6',
        :id                     => 'root',
        :concat_basedir         => '/dne',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end

    context 'defaults' do
      it { should contain_file('/etc/httpd/conf.d/worker.conf').with(:content => /^<IfModule mpm_worker_module>$/) }
      it { should contain_file('/etc/httpd/conf.d/worker.conf').with(:content => /^\s+ServerLimit\s+25$/) }
      it { should contain_file('/etc/httpd/conf.d/worker.conf').with(:content => /^\s+StartServers\s+2$/) }
      it { should contain_file('/etc/httpd/conf.d/worker.conf').with(:content => /^\s+MaxClients\s+150$/) }
      it { should contain_file('/etc/httpd/conf.d/worker.conf').with(:content => /^\s+MinSpareThreads\s+25$/) }
      it { should contain_file('/etc/httpd/conf.d/worker.conf').with(:content => /^\s+MaxSpareThreads\s+75$/) }
      it { should contain_file('/etc/httpd/conf.d/worker.conf').with(:content => /^\s+ThreadsPerChild\s+25$/) }
      it { should contain_file('/etc/httpd/conf.d/worker.conf').with(:content => /^\s+MaxRequestsPerChild\s+0$/) }
      it { should contain_file('/etc/httpd/conf.d/worker.conf').with(:content => /^\s+ThreadLimit\s+64$/) }
    end

    context 'setting params' do
      let :params do
        {
          :serverlimit          => 10,
          :startservers         => 11,
          :maxclients           => 12,
          :minsparethreads      => 13,
          :maxsparethreads      => 14,
          :threadsperchild      => 15,
          :maxrequestsperchild  => 16,
          :threadlimit          => 17
        }
      end
      it { should contain_file('/etc/httpd/conf.d/worker.conf').with(:content => /^<IfModule mpm_worker_module>$/) }
      it { should contain_file('/etc/httpd/conf.d/worker.conf').with(:content => /^\s+ServerLimit\s+10$/) }
      it { should contain_file('/etc/httpd/conf.d/worker.conf').with(:content => /^\s+StartServers\s+11$/) }
      it { should contain_file('/etc/httpd/conf.d/worker.conf').with(:content => /^\s+MaxClients\s+12$/) }
      it { should contain_file('/etc/httpd/conf.d/worker.conf').with(:content => /^\s+MinSpareThreads\s+13$/) }
      it { should contain_file('/etc/httpd/conf.d/worker.conf').with(:content => /^\s+MaxSpareThreads\s+14$/) }
      it { should contain_file('/etc/httpd/conf.d/worker.conf').with(:content => /^\s+ThreadsPerChild\s+15$/) }
      it { should contain_file('/etc/httpd/conf.d/worker.conf').with(:content => /^\s+MaxRequestsPerChild\s+16$/) }
      it { should contain_file('/etc/httpd/conf.d/worker.conf').with(:content => /^\s+ThreadLimit\s+17$/) }
    end
  end
end
require 'spec_helper'

describe 'apache::mod::wsgi', :type => :class do
  let :pre_condition do
    'include apache'
  end
  context "on a Debian OS" do
    let :facts do
      {
        :osfamily               => 'Debian',
        :operatingsystemrelease => '6',
        :concat_basedir         => '/dne',
        :lsbdistcodename        => 'squeeze',
        :operatingsystem        => 'Debian',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    it { is_expected.to contain_class("apache::params") }
    it { is_expected.to contain_apache__mod('wsgi') }
    it { is_expected.to contain_package("libapache2-mod-wsgi") }
  end
  context "on a RedHat OS" do
    let :facts do
      {
        :osfamily               => 'RedHat',
        :operatingsystemrelease => '6',
        :concat_basedir         => '/dne',
        :operatingsystem        => 'RedHat',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    it { is_expected.to contain_class("apache::params") }
    it { is_expected.to contain_apache__mod('wsgi') }
    it { is_expected.to contain_package("mod_wsgi") }

    describe "with custom WSGISocketPrefix" do
      let :params do
        { :wsgi_socket_prefix => 'run/wsgi' }
      end
      it {is_expected.to contain_file('wsgi.conf').with_content(/^  WSGISocketPrefix run\/wsgi$/)}
    end
    describe "with custom WSGIPythonHome" do
      let :params do
        { :wsgi_python_home => '/path/to/virtenv' }
      end
      it {is_expected.to contain_file('wsgi.conf').with_content(/^  WSGIPythonHome "\/path\/to\/virtenv"$/)}
    end
  end
  context "on a FreeBSD OS" do
    let :facts do
      {
        :osfamily               => 'FreeBSD',
        :operatingsystemrelease => '9',
        :concat_basedir         => '/dne',
        :operatingsystem        => 'FreeBSD',
        :id                     => 'root',
        :kernel                 => 'FreeBSD',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    it { is_expected.to contain_class("apache::params") }
    it { is_expected.to contain_apache__mod('wsgi') }
    it { is_expected.to contain_package("www/mod_wsgi") }
  end
end
require 'spec_helper'

describe 'apache::params', :type => :class do
  context "On a Debian OS" do
    let :facts do
      {
        :osfamily               => 'Debian',
        :operatingsystemrelease => '6',
        :concat_basedir         => '/dne',
        :lsbdistcodename        => 'squeeze',
        :operatingsystem        => 'Debian',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    it { is_expected.to contain_apache__params }

    # There are 4 resources in this class currently
    # there should not be any more resources because it is a params class
    # The resources are class[apache::version], class[apache::params], class[main], class[settings], stage[main]
    it "Should not contain any resources" do
      expect(subject.resources.size).to eq(5)
    end
  end
end
require 'spec_helper'

describe 'apache::service', :type => :class do
  let :pre_condition do
    'include apache::params'
  end
  context "on a Debian OS" do
    let :facts do
      {
        :osfamily               => 'Debian',
        :operatingsystemrelease => '6',
        :concat_basedir         => '/dne',
        :lsbdistcodename        => 'squeeze',
        :operatingsystem        => 'Debian',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    it { is_expected.to contain_service("httpd").with(
      'name'      => 'apache2',
      'ensure'    => 'running',
      'enable'    => 'true'
      )
    }

    context "with $service_name => 'foo'" do
      let (:params) {{ :service_name => 'foo' }}
      it { is_expected.to contain_service("httpd").with(
        'name'      => 'foo'
        )
      }
    end

    context "with $service_enable => true" do
      let (:params) {{ :service_enable => true }}
      it { is_expected.to contain_service("httpd").with(
        'name'      => 'apache2',
        'ensure'    => 'running',
        'enable'    => 'true'
        )
      }
    end

    context "with $service_enable => false" do
      let (:params) {{ :service_enable => false }}
      it { is_expected.to contain_service("httpd").with(
        'name'      => 'apache2',
        'ensure'    => 'running',
        'enable'    => 'false'
        )
      }
    end

    context "$service_enable must be a bool" do
      let (:params) {{ :service_enable => 'not-a-boolean' }}

      it 'should fail' do
        expect { subject }.to raise_error(Puppet::Error, /is not a boolean/)
      end
    end

    context "with $service_ensure => 'running'" do
      let (:params) {{ :service_ensure => 'running', }}
      it { is_expected.to contain_service("httpd").with(
        'ensure'    => 'running',
        'enable'    => 'true'
        )
      }
    end

    context "with $service_ensure => 'stopped'" do
      let (:params) {{ :service_ensure => 'stopped', }}
      it { is_expected.to contain_service("httpd").with(
        'ensure'    => 'stopped',
        'enable'    => 'true'
        )
      }
    end

    context "with $service_ensure => 'UNDEF'" do
      let (:params) {{ :service_ensure => 'UNDEF' }}
      it { is_expected.to contain_service("httpd").without_ensure }
    end
  end


  context "on a RedHat 5 OS" do
    let :facts do
      {
        :osfamily               => 'RedHat',
        :operatingsystemrelease => '5',
        :concat_basedir         => '/dne',
        :operatingsystem        => 'RedHat',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    it { is_expected.to contain_service("httpd").with(
      'name'      => 'httpd',
      'ensure'    => 'running',
      'enable'    => 'true'
      )
    }
  end

  context "on a FreeBSD 5 OS" do
    let :facts do
      {
        :osfamily               => 'FreeBSD',
        :operatingsystemrelease => '9',
        :concat_basedir         => '/dne',
        :operatingsystem        => 'FreeBSD',
        :id                     => 'root',
        :kernel                 => 'FreeBSD',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    it { is_expected.to contain_service("httpd").with(
      'name'      => 'apache22',
      'ensure'    => 'running',
      'enable'    => 'true'
      )
    }
  end
end
require 'spec_helper'

describe 'apache::fastcgi::server', :type => :define do
  let :pre_condition do
    'include apache'
  end
  let :title do
    'www'
  end
  describe 'os-dependent items' do
    context "on RedHat based systems" do
      let :default_facts do
        {
          :osfamily               => 'RedHat',
          :operatingsystem        => 'CentOS',
          :operatingsystemrelease => '6',
          :id                     => 'root',
          :concat_basedir         => '/dne',
          :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
        }
      end
      let :facts do default_facts end
      it { should contain_class("apache") }
      it { should contain_class("apache::mod::fastcgi") }
      it { should contain_file("fastcgi-pool-#{title}.conf").with(
        :ensure => 'present',
        :path => "/etc/httpd/conf.d/fastcgi-pool-#{title}.conf"
      ) }
    end
    context "on Debian based systems" do
      let :default_facts do
        {
          :osfamily               => 'Debian',
          :operatingsystem        => 'Debian',
          :operatingsystemrelease => '6',
          :lsbdistcodename        => 'squeeze',
          :id                     => 'root',
          :concat_basedir         => '/dne',
          :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
        }
      end
      let :facts do default_facts end
      it { should contain_class("apache") }
      it { should contain_class("apache::mod::fastcgi") }
      it { should contain_file("fastcgi-pool-#{title}.conf").with(
        :ensure => 'present',
        :path   => "/etc/apache2/conf.d/fastcgi-pool-#{title}.conf"
      ) }
    end
    context "on FreeBSD systems" do
      let :default_facts do
        {
          :osfamily               => 'FreeBSD',
          :operatingsystem        => 'FreeBSD',
          :operatingsystemrelease => '9',
          :id                     => 'root',
          :concat_basedir         => '/dne',
          :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
        }
      end
      let :facts do default_facts end
      it { should contain_class("apache") }
      it { should contain_class("apache::mod::fastcgi") }
      it { should contain_file("fastcgi-pool-#{title}.conf").with(
        :ensure => 'present',
        :path   => "/usr/local/etc/apache22/Includes/fastcgi-pool-#{title}.conf"
      ) }
    end
  end
  describe 'os-independent items' do
    let :facts do
      {
        :osfamily               => 'Debian',
        :operatingsystem        => 'Debian',
        :operatingsystemrelease => '6',
        :lsbdistcodename        => 'squeeze',
        :id                     => 'root',
        :concat_basedir         => '/dne',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    describe ".conf content" do
      let :params do
        {
          :host       => '127.0.0.1:9001',
          :timeout    => 30,
          :flush      => true,
          :faux_path  => '/var/www/php-www.fcgi',
          :fcgi_alias => '/php-www.fcgi',
          :file_type  => 'application/x-httpd-php'
        }
      end
      let :expected do
'FastCGIExternalServer /var/www/php-www.fcgi -idle-timeout 30 -flush -host 127.0.0.1:9001
Alias /php-www.fcgi /var/www/php-www.fcgi
Action application/x-httpd-php /php-www.fcgi
'
      end
      it do
        should contain_file("fastcgi-pool-www.conf").with_content(expected)
      end
    end
  end
end
require 'spec_helper'

describe 'apache::mod', :type => :define do
  let :pre_condition do
    'include apache'
  end
  context "on a RedHat osfamily" do
    let :facts do
      {
        :osfamily               => 'RedHat',
        :operatingsystemrelease => '6',
        :concat_basedir         => '/dne',
        :operatingsystem        => 'RedHat',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end

    describe "for non-special modules" do
      let :title do
        'spec_m'
      end
      it { is_expected.to contain_class("apache::params") }
      it "should manage the module load file" do
        is_expected.to contain_file('spec_m.load').with({
          :path    => '/etc/httpd/conf.d/spec_m.load',
          :content => "LoadModule spec_m_module modules/mod_spec_m.so\n",
          :owner   => 'root',
          :group   => 'root',
          :mode    => '0644',
        } )
      end
    end

    describe "with shibboleth module and package param passed" do
      # name/title for the apache::mod define
      let :title do
        'xsendfile'
      end
      # parameters
      let(:params) { {:package => 'mod_xsendfile'} }

      it { is_expected.to contain_class("apache::params") }
      it { is_expected.to contain_package('mod_xsendfile') }
    end
  end

  context "on a Debian osfamily" do
    let :facts do
      {
        :osfamily               => 'Debian',
        :operatingsystemrelease => '6',
        :concat_basedir         => '/dne',
        :lsbdistcodename        => 'squeeze',
        :operatingsystem        => 'Debian',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end

    describe "for non-special modules" do
      let :title do
        'spec_m'
      end
      it { is_expected.to contain_class("apache::params") }
      it "should manage the module load file" do
        is_expected.to contain_file('spec_m.load').with({
          :path    => '/etc/apache2/mods-available/spec_m.load',
          :content => "LoadModule spec_m_module /usr/lib/apache2/modules/mod_spec_m.so\n",
          :owner   => 'root',
          :group   => 'root',
          :mode    => '0644',
        } )
      end
      it "should link the module load file" do
        is_expected.to contain_file('spec_m.load symlink').with({
          :path   => '/etc/apache2/mods-enabled/spec_m.load',
          :target => '/etc/apache2/mods-available/spec_m.load',
          :owner   => 'root',
          :group   => 'root',
          :mode    => '0644',
        } )
      end
    end
  end

  context "on a FreeBSD osfamily" do
    let :facts do
      {
        :osfamily               => 'FreeBSD',
        :operatingsystemrelease => '9',
        :concat_basedir         => '/dne',
        :operatingsystem        => 'FreeBSD',
        :id                     => 'root',
        :kernel                 => 'FreeBSD',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end

    describe "for non-special modules" do
      let :title do
        'spec_m'
      end
      it { is_expected.to contain_class("apache::params") }
      it "should manage the module load file" do
        is_expected.to contain_file('spec_m.load').with({
          :path    => '/usr/local/etc/apache22/Modules/spec_m.load',
          :content => "LoadModule spec_m_module /usr/local/libexec/apache22/mod_spec_m.so\n",
          :owner   => 'root',
          :group   => 'wheel',
          :mode    => '0644',
        } )
      end
    end
  end
end
require 'spec_helper'

describe 'apache::vhost', :type => :define do
  let :pre_condition do
    'class { "apache": default_vhost => false, }'
  end
  let :title do
    'rspec.example.com'
  end
  let :default_params do
    {
      :docroot => '/rspec/docroot',
      :port    => '84',
    }
  end
  describe 'os-dependent items' do
    context "on RedHat based systems" do
      let :default_facts do
        {
          :osfamily               => 'RedHat',
          :operatingsystemrelease => '6',
          :concat_basedir         => '/dne',
          :operatingsystem        => 'RedHat',
          :id                     => 'root',
          :kernel                 => 'Linux',
          :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
        }
      end
      let :params do default_params end
      let :facts do default_facts end
      it { is_expected.to contain_class("apache") }
      it { is_expected.to contain_class("apache::params") }
    end
    context "on Debian based systems" do
      let :default_facts do
        {
          :osfamily               => 'Debian',
          :operatingsystemrelease => '6',
          :concat_basedir         => '/dne',
          :lsbdistcodename        => 'squeeze',
          :operatingsystem        => 'Debian',
          :id                     => 'root',
          :kernel                 => 'Linux',
          :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
        }
      end
      let :params do default_params end
      let :facts do default_facts end
      it { is_expected.to contain_class("apache") }
      it { is_expected.to contain_class("apache::params") }
      it { is_expected.to contain_file("25-rspec.example.com.conf").with(
        :ensure => 'present',
        :path   => '/etc/apache2/sites-available/25-rspec.example.com.conf'
      ) }
      it { is_expected.to contain_file("25-rspec.example.com.conf symlink").with(
        :ensure => 'link',
        :path   => '/etc/apache2/sites-enabled/25-rspec.example.com.conf',
        :target => '/etc/apache2/sites-available/25-rspec.example.com.conf'
      ) }
    end
    context "on FreeBSD systems" do
      let :default_facts do
        {
          :osfamily               => 'FreeBSD',
          :operatingsystemrelease => '9',
          :concat_basedir         => '/dne',
          :operatingsystem        => 'FreeBSD',
          :id                     => 'root',
          :kernel                 => 'FreeBSD',
          :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
        }
      end
      let :params do default_params end
      let :facts do default_facts end
      it { is_expected.to contain_class("apache") }
      it { is_expected.to contain_class("apache::params") }
      it { is_expected.to contain_file("25-rspec.example.com.conf").with(
        :ensure => 'present',
        :path   => '/usr/local/etc/apache22/Vhosts/25-rspec.example.com.conf'
      ) }
    end
  end
  describe 'os-independent items' do
    let :facts do
      {
        :osfamily               => 'Debian',
        :operatingsystemrelease => '6',
        :concat_basedir         => '/dne',
        :lsbdistcodename        => 'squeeze',
        :operatingsystem        => 'Debian',
        :id                     => 'root',
        :kernel                 => 'Linux',
        :path                   => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
      }
    end
    describe 'basic assumptions' do
      let :params do default_params end
      it { is_expected.to contain_class("apache") }
      it { is_expected.to contain_class("apache::params") }
      it { is_expected.to contain_apache__listen(params[:port]) }
      it { is_expected.to contain_apache__namevirtualhost("*:#{params[:port]}") }
    end

    # All match and notmatch should be a list of regexs and exact match strings
    context ".conf content" do
      [
        {
          :title => 'should contain docroot',
          :attr  => 'docroot',
          :value => '/not/default',
          :match => [/^  DocumentRoot "\/not\/default"$/,/  <Directory "\/not\/default">/],
        },
        {
          :title => 'should set a port',
          :attr  => 'port',
          :value => '8080',
          :match => [/^<VirtualHost \*:8080>$/],
        },
        {
          :title => 'should set an ip',
          :attr  => 'ip',
          :value => '10.0.0.1',
          :match => [/^<VirtualHost 10\.0\.0\.1:84>$/],
        },
        {
          :title => 'should set a serveradmin',
          :attr  => 'serveradmin',
          :value => 'test@test.com',
          :match => [/^  ServerAdmin test@test.com$/],
        },
        {
          :title => 'should enable ssl',
          :attr  => 'ssl',
          :value => true,
          :match => [/^  SSLEngine on$/],
        },
        {
          :title => 'should set a servername',
          :attr  => 'servername',
          :value => 'param.test',
          :match => [/^  ServerName param.test$/],
        },
        {
          :title => 'should accept server aliases',
          :attr  => 'serveraliases',
          :value => ['one.com','two.com'],
          :match => [
            /^  ServerAlias one\.com$/,
            /^  ServerAlias two\.com$/
          ],
        },
        {
          :title => 'should accept setenv',
          :attr  => 'setenv',
          :value => ['TEST1 one','TEST2 two'],
          :match => [
            /^  SetEnv TEST1 one$/,
            /^  SetEnv TEST2 two$/
          ],
        },
        {
          :title => 'should accept setenvif',
          :attr  => 'setenvif',
          ## These are bugged in rspec-puppet; the $1 is droped
          #:value => ['Host "^([^\.]*)\.website\.com$" CLIENT_NAME=$1'],
          #:match => ['  SetEnvIf Host "^([^\.]*)\.website\.com$" CLIENT_NAME=$1'],
          :value => ['Host "^test\.com$" VHOST_ACCESS=test'],
          :match => [/^  SetEnvIf Host "\^test\\.com\$" VHOST_ACCESS=test$/],
        },
        {
          :title => 'should accept options',
          :attr  => 'options',
          :value => ['Fake','Options'],
          :match => [/^    Options Fake Options$/],
        },
        {
          :title => 'should accept overrides',
          :attr  => 'override',
          :value => ['Fake', 'Override'],
          :match => [/^    AllowOverride Fake Override$/],
        },
        {
          :title => 'should accept logroot',
          :attr  => 'logroot',
          :value => '/fake/log',
          :match => [/CustomLog "\/fake\/log\//,/ErrorLog "\/fake\/log\//],
        },
        {
          :title => 'should accept log_level',
          :attr  => 'log_level',
          :value => 'info',
          :match => [/LogLevel info/],
        },
        {
          :title => 'should accept pipe destination for access log',
          :attr  => 'access_log_pipe',
          :value => '| /bin/fake/logging',
          :match => [/CustomLog "| \/bin\/fake\/logging" combined$/],
        },
        {
          :title => 'should accept pipe destination for error log',
          :attr  => 'error_log_pipe',
          :value => '| /bin/fake/logging',
          :match => [/ErrorLog "| \/bin\/fake\/logging" combined$/],
        },
        {
          :title => 'should accept syslog destination for access log',
          :attr  => 'access_log_syslog',
          :value => 'syslog:local1',
          :match => [/CustomLog "syslog:local1" combined$/],
        },
        {
          :title => 'should accept syslog destination for error log',
          :attr  => 'error_log_syslog',
          :value => 'syslog',
          :match => [/ErrorLog "syslog"$/],
        },
        {
          :title => 'should accept custom format for access logs',
          :attr  => 'access_log_format',
          :value => '%h %{X-Forwarded-For}i %l %u %t \"%r\" %s %b  \"%{Referer}i\" \"%{User-agent}i\" \"Host: %{Host}i\" %T %D',
          :match => [/CustomLog "\/var\/log\/.+_access\.log" "%h %\{X-Forwarded-For\}i %l %u %t \\"%r\\" %s %b  \\"%\{Referer\}i\\" \\"%\{User-agent\}i\\" \\"Host: %\{Host\}i\\" %T %D"$/],
        },
        {
          :title => 'should contain access logs',
          :attr  => 'access_log',
          :value => true,
          :match => [/CustomLog "\/var\/log\/.+_access\.log" combined$/],
        },
        {
          :title    => 'should not contain access logs',
          :attr     => 'access_log',
          :value    => false,
          :notmatch => [/CustomLog "\/var\/log\/.+_access\.log" combined$/],
        },
        {
          :title => 'should contain error logs',
          :attr  => 'error_log',
          :value => true,
          :match => [/ErrorLog.+$/],
        },
        {
          :title    => 'should not contain error logs',
          :attr     => 'error_log',
          :value    => false,
          :notmatch => [/ErrorLog.+$/],
        },
        {
          :title    => 'should set ErrorDocument 503',
          :attr     => 'error_documents',
          :value    => [ { 'error_code' => '503', 'document' => '"Go away, the backend is broken."'}],
          :match => [/^  ErrorDocument 503 "Go away, the backend is broken."$/],
        },
        {
          :title    => 'should set ErrorDocuments 503 407',
          :attr     => 'error_documents',
          :value    => [
            { 'error_code' => '503', 'document' => '/service-unavail'},
            { 'error_code' => '407', 'document' => 'https://example.com/proxy/login'},
          ],
          :match => [
            /^  ErrorDocument 503 \/service-unavail$/,
            /^  ErrorDocument 407 https:\/\/example\.com\/proxy\/login$/,
          ],
        },
        {
          :title    => 'should set ErrorDocument 503 in directory',
          :attr     => 'directories',
          :value    => { 'path' => '/srv/www', 'error_documents' => [{ 'error_code' => '503', 'document' => '"Go away, the backend is broken."'}] },
          :match => [/^    ErrorDocument 503 "Go away, the backend is broken."$/],
        },
        {
          :title    => 'should set ErrorDocuments 503 407 in directory',
          :attr     => 'directories',
          :value    => { 'path' => '/srv/www', 'error_documents' =>
          [
            { 'error_code' => '503', 'document' => '/service-unavail'},
            { 'error_code' => '407', 'document' => 'https://example.com/proxy/login'},
          ]},
          :match => [
            /^    ErrorDocument 503 \/service-unavail$/,
            /^    ErrorDocument 407 https:\/\/example\.com\/proxy\/login$/,
          ],
        },
        {
          :title => 'should accept a scriptalias',
          :attr  => 'scriptalias',
          :value => '/usr/scripts',
          :match => [
            /^  ScriptAlias \/cgi-bin "\/usr\/scripts"$/,
          ],
        },
        {
          :title    => 'should accept a single scriptaliases',
          :attr     => 'scriptaliases',
          :value    => { 'alias' => '/blah/', 'path' => '/usr/scripts' },
          :match    => [
            /^  ScriptAlias \/blah\/ "\/usr\/scripts"$/,
          ],
          :nomatch  => [/ScriptAlias \/cgi\-bin\//],
        },
        {
          :title    => 'should accept multiple scriptaliases',
          :attr     => 'scriptaliases',
          :value    => [ { 'alias' => '/blah', 'path' => '/usr/scripts' }, { 'alias' => '/blah2', 'path' => '/usr/scripts' } ],
          :match    => [
            /^  ScriptAlias \/blah "\/usr\/scripts"$/,
            /^  ScriptAlias \/blah2 "\/usr\/scripts"$/,
          ],
          :nomatch  => [/ScriptAlias \/cgi\-bin\//],
        },
        {
          :title    => 'should accept multiple scriptaliases with and without trailing slashes',
          :attr     => 'scriptaliases',
          :value    => [ { 'alias' => '/blah', 'path' => '/usr/scripts' }, { 'alias' => '/blah2/', 'path' => '/usr/scripts2/' } ],
          :match    => [
            /^  ScriptAlias \/blah "\/usr\/scripts"$/,
            /^  ScriptAlias \/blah2\/ "\/usr\/scripts2\/"$/,
          ],
          :nomatch  => [/ScriptAlias \/cgi\-bin\//],
        },
        {
          :title    => 'should accept a ScriptAliasMatch directive',
          :attr     => 'scriptaliases',
          ## XXX As mentioned above, rspec-puppet drops constructs like $1.
          ## Thus, these tests don't work as they should. As a workaround we
          ## use FOO instead of $1 here.
          :value    => [ { 'aliasmatch' => '^/cgi-bin(.*)', 'path' => '/usr/local/apache/cgi-binFOO' } ],
          :match    => [
            /^  ScriptAliasMatch \^\/cgi-bin\(\.\*\) "\/usr\/local\/apache\/cgi-binFOO"$/
          ],
        },
        {
          :title    => 'should accept multiple ScriptAliasMatch directives',
          :attr     => 'scriptaliases',
          ## XXX As mentioned above, rspec-puppet drops constructs like $1.
          ## Thus, these tests don't work as they should. As a workaround we
          ## use FOO instead of $1 here.
          :value    => [
            { 'aliasmatch' => '^/cgi-bin(.*)', 'path' => '/usr/local/apache/cgi-binFOO' },
            { 'aliasmatch' => '"(?x)^/git/(.*/(HEAD|info/refs|objects/(info/[^/]+|[0-9a-f]{2}/[0-9a-f]{38}|pack/pack-[0-9a-f]{40}\.(pack|idx))|git-(upload|receive)-pack))"', 'path' => '/var/www/bin/gitolite-suexec-wrapper/FOO' },
          ],
          :match    => [
            /^  ScriptAliasMatch \^\/cgi-bin\(\.\*\) "\/usr\/local\/apache\/cgi-binFOO"$/,
            /^  ScriptAliasMatch "\(\?x\)\^\/git\/\(\.\*\/\(HEAD\|info\/refs\|objects\/\(info\/\[\^\/\]\+\|\[0-9a-f\]\{2\}\/\[0-9a-f\]\{38\}\|pack\/pack-\[0-9a-f\]\{40\}\\\.\(pack\|idx\)\)\|git-\(upload\|receive\)-pack\)\)" "\/var\/www\/bin\/gitolite-suexec-wrapper\/FOO"$/,
          ],
        },
        {
          :title    => 'should accept mixed ScriptAlias and ScriptAliasMatch directives',
          :attr     => 'scriptaliases',
          ## XXX As mentioned above, rspec-puppet drops constructs like $1.
          ## Thus, these tests don't work as they should. As a workaround we
          ## use FOO instead of $1 here.
          :value    => [
            { 'aliasmatch' => '"(?x)^/git/(.*/(HEAD|info/refs|objects/(info/[^/]+|[0-9a-f]{2}/[0-9a-f]{38}|pack/pack-[0-9a-f]{40}\.(pack|idx))|git-(upload|receive)-pack))"', 'path' => '/var/www/bin/gitolite-suexec-wrapper/FOO' },
            { 'alias' => '/git', 'path' => '/var/www/gitweb/index.cgi' },
            { 'aliasmatch' => '^/cgi-bin(.*)', 'path' => '/usr/local/apache/cgi-binFOO' },
            { 'alias' => '/trac', 'path' => '/etc/apache2/trac.fcgi' },
          ],
          :match    => [
            /^  ScriptAliasMatch "\(\?x\)\^\/git\/\(\.\*\/\(HEAD\|info\/refs\|objects\/\(info\/\[\^\/\]\+\|\[0-9a-f\]\{2\}\/\[0-9a-f\]\{38\}\|pack\/pack-\[0-9a-f\]\{40\}\\\.\(pack\|idx\)\)\|git-\(upload\|receive\)-pack\)\)" "\/var\/www\/bin\/gitolite-suexec-wrapper\/FOO"$/,
            /^  ScriptAlias \/git "\/var\/www\/gitweb\/index\.cgi"$/,
            /^  ScriptAliasMatch \^\/cgi-bin\(\.\*\) "\/usr\/local\/apache\/cgi-binFOO"$/,
            /^  ScriptAlias \/trac "\/etc\/apache2\/trac.fcgi"$/,
          ],
        },
        {
          :title    => 'should accept proxy destinations',
          :attr     => 'proxy_dest',
          :value    => 'http://fake.com',
          :match    => [
            /^  ProxyPass          \/ http:\/\/fake.com\/$/,
            /^  <Location          \/>$/,
            /^    ProxyPassReverse http:\/\/fake.com\/$/,
            /^  <\/Location>$/,
          ],
          :notmatch => [/ProxyPass .+!$/],
        },
        {
          :title    => 'should accept proxy_pass hash',
          :attr     => 'proxy_pass',
          :value    => { 'path' => '/path-a', 'url' => 'http://fake.com/a' },
          :match    => [
            /^  ProxyPass \/path-a http:\/\/fake.com\/a$/,
            /^  <Location \/path-a>$/,
            /^    ProxyPassReverse http:\/\/fake.com\/a$/,
            /^  <\/Location>$/,

          ],
          :notmatch => [/ProxyPass .+!$/],
        },
        {
          :title    => 'should accept proxy_pass array of hash',
          :attr     => 'proxy_pass',
          :value    => [
            { 'path' => '/path-a/', 'url' => 'http://fake.com/a/' },
            { 'path' => '/path-b', 'url' => 'http://fake.com/b' },
          ],
          :match    => [
            /^  ProxyPass \/path-a\/ http:\/\/fake.com\/a\/$/,
            /^  <Location \/path-a\/>$/,
            /^    ProxyPassReverse http:\/\/fake.com\/a\/$/,
            /^  <\/Location>$/,
            /^  ProxyPass \/path-b http:\/\/fake.com\/b$/,
            /^  <Location \/path-b>$/,
            /^    ProxyPassReverse http:\/\/fake.com\/b$/,
            /^  <\/Location>$/,
          ],
          :notmatch => [/ProxyPass .+!$/],
        },
        {
          :title => 'should enable rack',
          :attr  => 'rack_base_uris',
          :value => ['/rack1','/rack2'],
          :match => [
            /^  RackBaseURI \/rack1$/,
            /^  RackBaseURI \/rack2$/,
          ],
        },
        {
          :title => 'should accept headers',
          :attr  => 'headers',
          :value => ['add something', 'merge something_else'],
          :match => [
            /^  Header add something$/,
            /^  Header merge something_else$/,
          ],
        },
        {
          :title => 'should accept request headers',
          :attr  => 'request_headers',
          :value => ['append something', 'unset something_else'],
          :match => [
            /^  RequestHeader append something$/,
            /^  RequestHeader unset something_else$/,
          ],
        },
        {
          :title => 'should accept rewrite rules',
          :attr  => 'rewrite_rule',
          :value => 'not a real rule',
          :match => [/^  RewriteRule not a real rule$/],
        },
        {
          :title => 'should accept rewrite rules',
          :attr  => 'rewrites',
          :value => [{'rewrite_rule' => ['not a real rule']}],
          :match => [/^  RewriteRule not a real rule$/],
        },
        {
          :title => 'should accept rewrite comment',
          :attr  => 'rewrites',
          :value => [{'comment' => 'rewrite comment', 'rewrite_rule' => ['not a real rule']}],
          :match => [/^  #rewrite comment/],
        },
        {
          :title => 'should accept rewrite conditions',
          :attr  => 'rewrites',
          :value => [{'comment' => 'redirect IE', 'rewrite_cond' => ['%{HTTP_USER_AGENT} ^MSIE'], 'rewrite_rule' => ['^index\.html$ welcome.html'],}],
          :match => [
            /^  #redirect IE$/,
            /^  RewriteCond %{HTTP_USER_AGENT} \^MSIE$/,
            /^  RewriteRule \^index\\\.html\$ welcome.html$/,
          ],
        },
        {
          :title => 'should accept multiple rewrites',
          :attr  => 'rewrites',
          :value => [
            {'rewrite_rule' => ['not a real rule']},
            {'rewrite_rule' => ['not a real rule two']},
          ],
          :match => [
            /^  RewriteRule not a real rule$/,
            /^  RewriteRule not a real rule two$/,
          ],
        },
        {
          :title => 'should block scm',
          :attr  => 'block',
          :value => 'scm',
          :match => [/^  <DirectoryMatch \.\*\\\.\(svn\|git\|bzr\)\/\.\*>$/],
        },
        {
          :title => 'should accept a custom fragment',
          :attr  => 'custom_fragment',
          :value => "  Some custom fragment line\n  That spans multiple lines",
          :match => [
            /^  Some custom fragment line$/,
            /^  That spans multiple lines$/,
            /^<\/VirtualHost>$/,
          ],
        },
        {
          :title => 'should accept an array of alias hashes',
          :attr  => 'aliases',
          :value => [ { 'alias' => '/', 'path' => '/var/www'} ],
          :match => [/^  Alias \/ "\/var\/www"$/],
        },
        {
          :title => 'should accept an alias hash',
          :attr  => 'aliases',
          :value => { 'alias' => '/', 'path' => '/var/www'},
          :match => [/^  Alias \/ "\/var\/www"$/],
        },
        {
          :title => 'should accept multiple aliases',
          :attr  => 'aliases',
          :value => [
            { 'alias' => '/', 'path' => '/var/www'},
            { 'alias' => '/cgi-bin', 'path' => '/var/www/cgi-bin'},
            { 'alias' => '/css', 'path' => '/opt/someapp/css'},
          ],
          :match => [
            /^  Alias \/ "\/var\/www"$/,
            /^  Alias \/cgi-bin "\/var\/www\/cgi-bin"$/,
            /^  Alias \/css "\/opt\/someapp\/css"$/,
          ],
        },
        {
          :title => 'should accept an aliasmatch hash',
          :attr  => 'aliases',
          ## XXX As mentioned above, rspec-puppet drops the $1. Thus, these
          # tests don't work.
          #:value => { 'aliasmatch' => '^/image/(.*).gif', 'path' => '/files/gifs/$1.gif' },
          #:match => [/^  AliasMatch \^\/image\/\(\.\*\)\.gif \/files\/gifs\/\$1\.gif$/],
        },
        {
          :title => 'should accept a array of alias and aliasmatch hashes mixed',
          :attr  => 'aliases',
          ## XXX As mentioned above, rspec-puppet drops the $1. Thus, these
          # tests don't work.
          #:value => [
          #  { 'alias' => '/css', 'path' => '/files/css' },
          #  { 'aliasmatch' => '^/image/(.*).gif', 'path' => '/files/gifs/$1.gif' },
          #  { 'aliasmatch' => '^/image/(.*).jpg', 'path' => '/files/jpgs/$1.jpg' },
          #  { 'alias' => '/image', 'path' => '/files/images' },
          #],
          #:match => [
          #  /^  Alias \/css \/files\/css$/,
          #  /^  AliasMatch \^\/image\/\(.\*\)\.gif \/files\/gifs\/\$1\.gif$/,
          #  /^  AliasMatch \^\/image\/\(.\*\)\.jpg \/files\/jpgs\/\$1\.jpg$/,
          #  /^  Alias \/image \/files\/images$/
          #],
        },
        {
          :title => 'should accept multiple additional includes',
          :attr  => 'additional_includes',
          :value => [
            '/tmp/proxy_group_a',
            '/tmp/proxy_group_b',
            '/tmp/proxy_group_c',
          ],
          :match => [
            /^  Include "\/tmp\/proxy_group_a"$/,
            /^  Include "\/tmp\/proxy_group_b"$/,
            /^  Include "\/tmp\/proxy_group_c"$/,
          ],
        },
        {
          :title => 'should accept a suPHP_Engine',
          :attr  => 'suphp_engine',
          :value => 'on',
          :match => [/^  suPHP_Engine on$/],
        },
        {
          :title => 'should accept a php_admin_flags',
          :attr  => 'php_admin_flags',
          :value => { 'engine' => 'on' },
          :match => [/^  php_admin_flag engine on$/],
        },
        {
          :title => 'should accept php_admin_values',
          :attr  => 'php_admin_values',
          :value => { 'open_basedir' => '/srv/web/www.com/:/usr/share/pear/' },
          :match => [/^  php_admin_value open_basedir \/srv\/web\/www.com\/:\/usr\/share\/pear\/$/],
        },
        {
          :title => 'should accept php_admin_flags in directories',
          :attr  => 'directories',
          :value => {
						'path'            => '/srv/www',
						'php_admin_flags' => { 'php_engine' => 'on' }
					},
          :match => [/^    php_admin_flag php_engine on$/],
        },
        {
          :title => 'should accept php_admin_values',
          :attr  => 'php_admin_values',
          :value => { 'open_basedir' => '/srv/web/www.com/:/usr/share/pear/' },
          :match => [/^  php_admin_value open_basedir \/srv\/web\/www.com\/:\/usr\/share\/pear\/$/],
        },
        {
          :title => 'should accept php_admin_values in directories',
          :attr  => 'directories',
          :value => {
            'path'             => '/srv/www',
            'php_admin_values' => { 'open_basedir' => '/srv/web/www.com/:/usr/share/pear/' }
          },
          :match => [/^    php_admin_value open_basedir \/srv\/web\/www.com\/:\/usr\/share\/pear\/$/],
        },
        {
          :title => 'should accept a wsgi script alias',
          :attr  => 'wsgi_script_aliases',
          :value => { '/' => '/var/www/myapp.wsgi'},
          :match => [/^  WSGIScriptAlias \/ "\/var\/www\/myapp.wsgi"$/],
        },
        {
          :title => 'should accept multiple wsgi aliases',
          :attr  => 'wsgi_script_aliases',
          :value => {
            '/wiki' => '/usr/local/wsgi/scripts/mywiki.wsgi',
            '/blog' => '/usr/local/wsgi/scripts/myblog.wsgi',
            '/'     => '/usr/local/wsgi/scripts/myapp.wsgi',
          },
          :match => [
            /^  WSGIScriptAlias \/wiki "\/usr\/local\/wsgi\/scripts\/mywiki.wsgi"$/,
            /^  WSGIScriptAlias \/blog "\/usr\/local\/wsgi\/scripts\/myblog.wsgi"$/,
            /^  WSGIScriptAlias \/ "\/usr\/local\/wsgi\/scripts\/myapp.wsgi"$/,
          ],
        },
        {
          :title => 'should accept a wsgi application group',
          :attr  => 'wsgi_application_group',
          :value => '%{GLOBAL}',
          :match => [/^  WSGIApplicationGroup %{GLOBAL}$/],
        },
        {
          :title => 'should set wsgi pass authorization',
          :attr  => 'wsgi_pass_authorization',
          :value => 'On',
          :match => [/^  WSGIPassAuthorization On$/],
        },
        {
          :title => 'should set wsgi pass authorization false',
          :attr  => 'wsgi_pass_authorization',
          :value => 'Off',
          :match => [/^  WSGIPassAuthorization Off$/],
        },
        {
          :title => 'should contain environment variables',
          :attr  => 'access_log_env_var',
          :value => 'admin',
          :match => [/CustomLog "\/var\/log\/.+_access\.log" combined env=admin$/]
        },
        {
          :title => 'should contain virtual_docroot',
          :attr  => 'virtual_docroot',
          :value => '/not/default',
          :match => [
            /^  VirtualDocumentRoot "\/not\/default"$/,
          ],
        },
        {
          :title    => 'should accept multiple directories',
          :attr     => 'directories',
          :value    => [
            { 'path' => '/opt/app' },
            { 'path' => '/var/www' },
            { 'path' => '/rspec/docroot'}
          ],
          :match    => [
            /^  <Directory "\/opt\/app">$/,
            /^  <Directory "\/var\/www">$/,
            /^  <Directory "\/rspec\/docroot">$/,
          ],
        },
      ].each do |param|
        describe "when #{param[:attr]} is #{param[:value]}" do
          let :params do default_params.merge({ param[:attr].to_sym => param[:value] }) end

          it { is_expected.to contain_file("25-#{title}.conf").with_mode('0644') }
          if param[:match]
            it "#{param[:title]}: matches" do
              param[:match].each do |match|
                is_expected.to contain_file("25-#{title}.conf").with_content( match )
              end
            end
          end
          if param[:notmatch]
            it "#{param[:title]}: notmatches" do
              param[:notmatch].each do |notmatch|
                is_expected.not_to contain_file("25-#{title}.conf").with_content( notmatch )
              end
            end
          end
        end
      end
    end

    # Apache below 2.4 (Default Version). All match and notmatch should be a list of regexs and exact match strings
    context ".conf content with $apache_version < 2.4" do
      [
        {
          :title    => 'should accept a directory',
          :attr     => 'directories',
          :value    => { 'path' => '/opt/app' },
          :notmatch => ['  <Directory /rspec/docroot>'],
          :match    => [
            /^  <Directory "\/opt\/app">$/,
            /^    AllowOverride None$/,
            /^    Order allow,deny$/,
            /^    Allow from all$/,
            /^  <\/Directory>$/,
          ],
        },
        {
          :title    => 'should accept directory directives hash',
          :attr     => 'directories',
          :value    => {
            'path'              => '/opt/app',
            'headers'           => 'Set X-Robots-Tag "noindex, noarchive, nosnippet"',
            'allow'             => 'from rspec.org',
            'allow_override'    => 'Lol',
            'deny'              => 'from google.com',
            'options'           => '-MultiViews',
            'order'             => 'deny,yned',
            'passenger_enabled' => 'onf',
            'sethandler'        => 'None',
            'auth_type'         => 'Basic',
            'auth_name'         => 'Basic Auth',
            'auth_user_file'    => '/opt/app/htpasswd',
            'auth_require'      => 'valid-user',
            'satisfy'           => 'Any',
          },
          :match    => [
            /^  <Directory "\/opt\/app">$/,
            /^    Header Set X-Robots-Tag "noindex, noarchive, nosnippet"$/,
            /^    Allow from rspec.org$/,
            /^    AllowOverride Lol$/,
            /^    Deny from google.com$/,
            /^    Options -MultiViews$/,
            /^    Order deny,yned$/,
            /^    SetHandler None$/,
            /^    PassengerEnabled onf$/,
            /^    AuthType Basic$/,
            /^    AuthName "Basic Auth"$/,
            /^    AuthUserFile \/opt\/app\/htpasswd$/,
            /^    Require valid-user$/,
            /^    Satisfy Any$/,
            /^  <\/Directory>$/,
          ],
        },
        {
          :title    => 'should accept directory directives with arrays and hashes',
          :attr     => 'directories',
          :value    => [
            {
              'path'              => '/opt/app1',
              'allow'             => 'from rspec.org',
              'allow_override'    => ['AuthConfig','Indexes'],
              'deny'              => 'from google.com',
              'options'           => ['-MultiViews','+MultiViews'],
              'order'             => ['deny','yned'],
              'passenger_enabled' => 'onf',
            },
            {
              'path'        => '/opt/app2',
              'addhandlers' => {
                'handler'    => 'cgi-script',
                'extensions' => '.cgi',
              },
            },
          ],
          :match    => [
            /^  <Directory "\/opt\/app1">$/,
            /^    Allow from rspec.org$/,
            /^    AllowOverride AuthConfig Indexes$/,
            /^    Deny from google.com$/,
            /^    Options -MultiViews \+MultiViews$/,
            /^    Order deny,yned$/,
            /^    PassengerEnabled onf$/,
            /^  <\/Directory>$/,
            /^  <Directory "\/opt\/app2">$/,
            /^    AllowOverride None$/,
            /^    Order allow,deny$/,
            /^    Allow from all$/,
            /^    AddHandler cgi-script .cgi$/,
            /^  <\/Directory>$/,
          ],
        },
        {
          :title => 'should accept location for provider',
          :attr  => 'directories',
          :value => {
            'path'     => '/',
            'provider' => 'location',
          },
          :notmatch => ['    AllowOverride None'],
          :match => [
            /^  <Location "\/">$/,
            /^    Order allow,deny$/,
            /^    Allow from all$/,
            /^  <\/Location>$/,
          ],
        },
        {
          :title => 'should accept files for provider',
          :attr  => 'directories',
          :value => {
            'path'     => 'index.html',
            'provider' => 'files',
          },
          :notmatch => ['    AllowOverride None'],
          :match => [
            /^  <Files "index.html">$/,
            /^    Order allow,deny$/,
            /^    Allow from all$/,
            /^  <\/Files>$/,
          ],
        },
        {
          :title => 'should accept files match for provider',
          :attr  => 'directories',
          :value => {
            'path'     => 'index.html',
            'provider' => 'filesmatch',
          },
          :notmatch => ['    AllowOverride None'],
          :match => [
            /^  <FilesMatch "index.html">$/,
            /^    Order allow,deny$/,
            /^    Allow from all$/,
            /^  <\/FilesMatch>$/,
          ],
        },
      ].each do |param|
        describe "when #{param[:attr]} is #{param[:value]}" do
          let :params do default_params.merge({
            param[:attr].to_sym => param[:value],
            :apache_version => '2.2',
          }) end

          it { is_expected.to contain_file("25-#{title}.conf").with_mode('0644') }
          if param[:match]
            it "#{param[:title]}: matches" do
              param[:match].each do |match|
                is_expected.to contain_file("25-#{title}.conf").with_content( match )
              end
            end
          end
          if param[:notmatch]
            it "#{param[:title]}: notmatches" do
              param[:notmatch].each do |notmatch|
                is_expected.not_to contain_file("25-#{title}.conf").with_content( notmatch )
              end
            end
          end
        end
      end
    end

    # Apache equals or above 2.4. All match and notmatch should be a list of regexs and exact match strings
    context ".conf content with $apache_version >= 2.4" do
      [
        {
          :title    => 'should accept a directory',
          :attr     => 'directories',
          :value    => { 'path' => '/opt/app' },
          :notmatch => ['  <Directory /rspec/docroot>'],
          :match    => [
            /^  <Directory "\/opt\/app">$/,
            /^    AllowOverride None$/,
            /^    Require all granted$/,
            /^  <\/Directory>$/,
          ],
        },
        {
          :title    => 'should accept directory directives hash',
          :attr     => 'directories',
          :value    => {
            'path'              => '/opt/app',
            'headers'           => 'Set X-Robots-Tag "noindex, noarchive, nosnippet"',
            'allow_override'    => 'Lol',
            'options'           => '-MultiViews',
            'require'           => 'something denied',
            'passenger_enabled' => 'onf',
          },
          :match    => [
            /^  <Directory "\/opt\/app">$/,
            /^    Header Set X-Robots-Tag "noindex, noarchive, nosnippet"$/,
            /^    AllowOverride Lol$/,
            /^    Options -MultiViews$/,
            /^    Require something denied$/,
            /^    PassengerEnabled onf$/,
            /^  <\/Directory>$/,
          ],
        },
        {
          :title    => 'should accept directory directives with arrays and hashes',
          :attr     => 'directories',
          :value    => [
            {
              'path'              => '/opt/app1',
              'allow_override'    => ['AuthConfig','Indexes'],
              'options'           => ['-MultiViews','+MultiViews'],
              'require'           => ['host','example.org'],
              'passenger_enabled' => 'onf',
            },
            {
              'path'        => '/opt/app2',
              'addhandlers' => {
                'handler'    => 'cgi-script',
                'extensions' => '.cgi',
              },
            },
          ],
          :match    => [
            /^  <Directory "\/opt\/app1">$/,
            /^    AllowOverride AuthConfig Indexes$/,
            /^    Options -MultiViews \+MultiViews$/,
            /^    Require host example.org$/,
            /^    PassengerEnabled onf$/,
            /^  <\/Directory>$/,
            /^  <Directory "\/opt\/app2">$/,
            /^    AllowOverride None$/,
            /^    Require all granted$/,
            /^    AddHandler cgi-script .cgi$/,
            /^  <\/Directory>$/,
          ],
        },
        {
          :title => 'should accept location for provider',
          :attr  => 'directories',
          :value => {
            'path'     => '/',
            'provider' => 'location',
          },
          :notmatch => ['    AllowOverride None'],
          :match => [
            /^  <Location "\/">$/,
            /^    Require all granted$/,
            /^  <\/Location>$/,
          ],
        },
        {
          :title => 'should accept files for provider',
          :attr  => 'directories',
          :value => {
            'path'     => 'index.html',
            'provider' => 'files',
          },
          :notmatch => ['    AllowOverride None'],
          :match => [
            /^  <Files "index.html">$/,
            /^    Require all granted$/,
            /^  <\/Files>$/,
          ],
        },
        {
          :title => 'should accept files match for provider',
          :attr  => 'directories',
          :value => {
            'path'     => 'index.html',
            'provider' => 'filesmatch',
          },
          :notmatch => ['    AllowOverride None'],
          :match => [
            /^  <FilesMatch "index.html">$/,
            /^    Require all granted$/,
            /^  <\/FilesMatch>$/,
          ],
        },
      ].each do |param|
        describe "when #{param[:attr]} is #{param[:value]}" do
          let :params do default_params.merge({
            param[:attr].to_sym => param[:value],
            :apache_version => '2.4',
          }) end

          it { is_expected.to contain_file("25-#{title}.conf").with_mode('0644') }
          if param[:match]
            it "#{param[:title]}: matches" do
              param[:match].each do |match|
                is_expected.to contain_file("25-#{title}.conf").with_content( match )
              end
            end
          end
          if param[:notmatch]
            it "#{param[:title]}: notmatches" do
              param[:notmatch].each do |notmatch|
                is_expected.not_to contain_file("25-#{title}.conf").with_content( notmatch )
              end
            end
          end
        end
      end
    end

    # All match and notmatch should be a list of regexs and exact match strings
    context ".conf content with SSL" do
      [
        {
            :title => 'should accept setting SSLCertificateFile',
            :attr  => 'ssl_cert',
            :value => '/path/to/cert.pem',
            :match => [/^  SSLCertificateFile      "\/path\/to\/cert\.pem"$/],
        },
        {
            :title => 'should accept setting SSLCertificateKeyFile',
            :attr  => 'ssl_key',
            :value => '/path/to/cert.pem',
            :match => [/^  SSLCertificateKeyFile   "\/path\/to\/cert\.pem"$/],
        },
        {
            :title => 'should accept setting SSLCertificateChainFile',
            :attr  => 'ssl_chain',
            :value => '/path/to/cert.pem',
            :match => [/^  SSLCertificateChainFile "\/path\/to\/cert\.pem"$/],
        },
        {
            :title => 'should accept setting SSLCertificatePath',
            :attr  => 'ssl_certs_dir',
            :value => '/path/to/certs',
            :match => [/^  SSLCACertificatePath    "\/path\/to\/certs"$/],
        },
        {
            :title => 'should accept setting SSLCertificateFile',
            :attr  => 'ssl_ca',
            :value => '/path/to/ca.pem',
            :match => [/^  SSLCACertificateFile    "\/path\/to\/ca\.pem"$/],
        },
        {
            :title => 'should accept setting SSLRevocationPath',
            :attr  => 'ssl_crl_path',
            :value => '/path/to/crl',
            :match => [/^  SSLCARevocationPath     "\/path\/to\/crl"$/],
        },
        {
            :title => 'should accept setting SSLRevocationFile',
            :attr  => 'ssl_crl',
            :value => '/path/to/crl.pem',
            :match => [/^  SSLCARevocationFile     "\/path\/to\/crl\.pem"$/],
        },
        {
            :title => 'should accept setting SSLProxyEngine',
            :attr  => 'ssl_proxyengine',
            :value => true,
            :match => [/^  SSLProxyEngine On$/],
        },
        {
            :title => 'should accept setting SSLProtocol',
            :attr  => 'ssl_protocol',
            :value => 'all -SSLv2',
            :match => [/^  SSLProtocol             all -SSLv2$/],
        },
        {
            :title => 'should accept setting SSLCipherSuite',
            :attr  => 'ssl_cipher',
            :value => 'RC4-SHA:HIGH:!ADH:!SSLv2',
            :match => [/^  SSLCipherSuite          RC4-SHA:HIGH:!ADH:!SSLv2$/],
        },
        {
            :title => 'should accept setting SSLHonorCipherOrder',
            :attr  => 'ssl_honorcipherorder',
            :value => 'On',
            :match => [/^  SSLHonorCipherOrder     On$/],
        },
        {
            :title => 'should accept setting SSLVerifyClient',
            :attr  => 'ssl_verify_client',
            :value => 'optional',
            :match => [/^  SSLVerifyClient         optional$/],
        },
        {
            :title => 'should accept setting SSLVerifyDepth',
            :attr  => 'ssl_verify_depth',
            :value => '1',
            :match => [/^  SSLVerifyDepth          1$/],
        },
        {
            :title => 'should accept setting SSLOptions with a string',
            :attr  => 'ssl_options',
            :value => '+ExportCertData',
            :match => [/^  SSLOptions \+ExportCertData$/],
        },
        {
            :title => 'should accept setting SSLOptions with an array',
            :attr  => 'ssl_options',
            :value => ['+StrictRequire','+ExportCertData'],
            :match => [/^  SSLOptions \+StrictRequire \+ExportCertData/],
        },
        {
            :title => 'should accept setting SSLOptions with a string in directories',
            :attr  => 'directories',
            :value => { 'path' => '/srv/www', 'ssl_options' => '+ExportCertData'},
            :match => [/^    SSLOptions \+ExportCertData$/],
        },
        {
            :title => 'should accept setting SSLOptions with an array in directories',
            :attr  => 'directories',
            :value => { 'path' => '/srv/www', 'ssl_options' => ['-StdEnvVars','+ExportCertData']},
            :match => [/^    SSLOptions -StdEnvVars \+ExportCertData/],
        },
      ].each do |param|
        describe "when #{param[:attr]} is #{param[:value]} with SSL" do
          let :params do
            default_params.merge( {
              param[:attr].to_sym => param[:value],
              :ssl                => true,
            } )
          end
          it { is_expected.to contain_file("25-#{title}.conf").with_mode('0644') }
          if param[:match]
            it "#{param[:title]}: matches" do
              param[:match].each do |match|
                is_expected.to contain_file("25-#{title}.conf").with_content( match )
              end
            end
          end
          if param[:notmatch]
            it "#{param[:title]}: notmatches" do
              param[:notmatch].each do |notmatch|
                is_expected.not_to contain_file("25-#{title}.conf").with_content( notmatch )
              end
            end
          end
        end
      end
    end

    context 'attribute resources' do
      describe 'when access_log_file and access_log_pipe are specified' do
        let :params do default_params.merge({
          :access_log_file => 'fake.log',
          :access_log_pipe => '| /bin/fake',
        }) end
        it 'should cause a failure' do
          expect { subject }.to raise_error(Puppet::Error, /'access_log_file' and 'access_log_pipe' cannot be defined at the same time/)
        end
      end
      describe 'when error_log_file and error_log_pipe are specified' do
        let :params do default_params.merge({
          :error_log_file => 'fake.log',
          :error_log_pipe => '| /bin/fake',
        }) end
        it 'should cause a failure' do
          expect { subject }.to raise_error(Puppet::Error, /'error_log_file' and 'error_log_pipe' cannot be defined at the same time/)
        end
      end
      describe 'when logroot and logroot_mode are specified' do
        let :params do default_params.merge({
          :logroot       => '/rspec/logroot',
          :logroot_mode  => '0755',
        }) end
        it 'should set logroot mode' do
          should contain_file(params[:logroot]).with({
            :ensure => :directory,
            :mode   => '0755',
          })
        end
      end
      describe 'when docroot owner and mode is specified' do
        let :params do default_params.merge({
          :docroot_owner => 'testuser',
          :docroot_group => 'testgroup',
          :docroot_mode  => '0750',
        }) end
        it 'should set vhost ownership and permissions' do
          is_expected.to contain_file(params[:docroot]).with({
            :ensure => :directory,
            :owner  => 'testuser',
            :group  => 'testgroup',
            :mode   => '0750',
          })
        end
      end

      describe 'when docroot is *not* managed' do
        let :params do default_params.merge({
          :manage_docroot=> false,
        }) end
        it 'should not contain docroot ' do
          is_expected.not_to contain_file(params[:docroot])
        end
      end

      describe 'when wsgi_daemon_process and wsgi_daemon_process_options are specified' do
        let :params do default_params.merge({
          :wsgi_daemon_process         => 'example.org',
          :wsgi_daemon_process_options => { 'processes' => '2', 'threads' => '15' },
        }) end
        it 'should set wsgi_daemon_process_options' do
          is_expected.to contain_file("25-#{title}.conf").with_content(
            /^  WSGIDaemonProcess example.org processes=2 threads=15$/
          )
        end
      end

      describe 'when wsgi_import_script and wsgi_import_script_options are specified' do
        let :params do default_params.merge({
          :wsgi_import_script         => '/var/www/demo.wsgi',
          :wsgi_import_script_options => { 'application-group' => '%{GLOBAL}', 'process-group' => 'wsgi' },
        }) end
        it 'should set wsgi_import_script_options' do
          is_expected.to contain_file("25-#{title}.conf").with_content(
            /^  WSGIImportScript \/var\/www\/demo.wsgi application-group=%{GLOBAL} process-group=wsgi$/
          )
        end
      end

      describe 'when rewrites are specified' do
        let :params do default_params.merge({
          :rewrites => [
            {
              'comment'      => 'test rewrites',
              'rewrite_base' => '/mytestpath/',
              'rewrite_cond' => ['%{HTTP_USER_AGENT} ^Lynx/ [OR]', '%{HTTP_USER_AGENT} ^Mozilla/[12]'],
              'rewrite_rule' => ['^index\.html$ welcome.html', '^index\.cgi$ index.php'],
            }
          ]
        }) end
        it 'should set RewriteConds and RewriteRules' do
          is_expected.to contain_file("25-#{title}.conf").with_content(
            /^  #test rewrites$/
          )
          is_expected.to contain_file("25-#{title}.conf").with_content(
            /^  RewriteCond %\{HTTP_USER_AGENT\} \^Lynx\/ \[OR\]$/
          )
          is_expected.to contain_file("25-#{title}.conf").with_content(
            /^  RewriteBase \/mytestpath\/$/
          )
          is_expected.to contain_file("25-#{title}.conf").with_content(
            /^  RewriteCond %\{HTTP_USER_AGENT\} \^Mozilla\/\[12\]$/
          )
          is_expected.to contain_file("25-#{title}.conf").with_content(
            /^  RewriteRule \^index\\.html\$ welcome.html$/
          )
          is_expected.to contain_file("25-#{title}.conf").with_content(
            /^  RewriteRule \^index\\.cgi\$ index.php$/
          )
        end
      end

      describe 'when rewrite_rule and rewrite_cond are specified' do
        let :params do default_params.merge({
          :rewrite_cond => '%{HTTPS} off',
          :rewrite_rule => '(.*) https://%{HTTPS_HOST}%{REQUEST_URI}',
        }) end
        it 'should set RewriteCond' do
          is_expected.to contain_file("25-#{title}.conf").with_content(
            /^  RewriteCond %\{HTTPS\} off$/
          )
        end
      end

      describe 'when action is specified specified' do
        let :params do default_params.merge({
          :action => 'php-fastcgi',
        }) end
        it 'should set Action' do
          is_expected.to contain_file("25-#{title}.conf").with_content(
            /^  Action php-fastcgi \/cgi-bin virtual$/
          )
        end
      end

      describe 'when suphp_engine is on and suphp_configpath is specified' do
        let :params do default_params.merge({
          :suphp_engine     => 'on',
          :suphp_configpath => '/etc/php5/apache2',
        }) end
        it 'should set suphp_configpath' do
          is_expected.to contain_file("25-#{title}.conf").with_content(
            /^  suPHP_ConfigPath "\/etc\/php5\/apache2"$/
          )
        end
      end

      describe 'when suphp_engine is on and suphp_addhandler is specified' do
        let :params do default_params.merge({
          :suphp_engine     => 'on',
          :suphp_addhandler => 'x-httpd-php',
        }) end
        it 'should set suphp_addhandler' do
          is_expected.to contain_file("25-#{title}.conf").with_content(
            /^  suPHP_AddHandler x-httpd-php/
          )
        end
      end

      describe 'when suphp_engine is on and suphp { user & group } is specified' do
        let :params do default_params.merge({
          :suphp_engine     => 'on',
          :directories      => { 'path' => '/srv/www',
            'suphp' => { 'user' => 'myappuser', 'group' => 'myappgroup' },
          }
        }) end
        it 'should set suphp_UserGroup' do
          is_expected.to contain_file("25-#{title}.conf").with_content(
            /^    suPHP_UserGroup myappuser myappgroup/
          )
        end
      end

      describe 'priority/default settings' do
        describe 'when neither priority/default is specified' do
          let :params do default_params end
          it { is_expected.to contain_file("25-#{title}.conf").with_path(
            /25-#{title}.conf/
          ) }
        end
        describe 'when both priority/default_vhost is specified' do
          let :params do
            default_params.merge({
              :priority      => 15,
              :default_vhost => true,
            })
          end
          it { is_expected.to contain_file("15-#{title}.conf").with_path(
            /15-#{title}.conf/
          ) }
        end
        describe 'when only priority is specified' do
          let :params do
            default_params.merge({ :priority => 14, })
          end
          it { is_expected.to contain_file("14-#{title}.conf").with_path(
            /14-#{title}.conf/
          ) }
        end
        describe 'when only default is specified' do
          let :params do
            default_params.merge({ :default_vhost => true, })
          end
          it { is_expected.to contain_file("10-#{title}.conf").with_path(
            /10-#{title}.conf/
          ) }
        end
      end

      describe 'fcgid directory options' do
        describe 'No fcgiwrapper' do
          let :params do
            default_params.merge({
              :directories      => { 'path' => '/srv/www' },
            })
          end

          it { is_expected.not_to contain_file("25-#{title}.conf").with_content(%r{FcgidWrapper}) }
        end

        describe 'Only a command' do
          let :params do
            default_params.merge({
              :directories      => { 'path' => '/srv/www',
                'fcgiwrapper' => { 'command' => '/usr/local/bin/fcgiwrapper' },
              }
            })
          end

          it { is_expected.to contain_file("25-#{title}.conf").with_content(%r{^    FcgidWrapper /usr/local/bin/fcgiwrapper  $}) }
        end

        describe 'All parameters' do
          let :params do
            default_params.merge({
              :directories    => { 'path' => '/srv/www',
                'fcgiwrapper' => { 'command' => '/usr/local/bin/fcgiwrapper', 'suffix' => '.php', 'virtual' => 'virtual' },
              }
            })
          end

          it { is_expected.to contain_file("25-#{title}.conf").with_content(%r{^    FcgidWrapper /usr/local/bin/fcgiwrapper .php virtual$}) }
        end
      end

      describe 'various ip/port combos' do
        describe 'when ip_based is true' do
          let :params do default_params.merge({ :ip_based => true }) end
          it 'should not specify a NameVirtualHost' do
            is_expected.to contain_apache__listen(params[:port])
            is_expected.not_to contain_apache__namevirtualhost("*:#{params[:port]}")
          end
        end

        describe 'when ip_based is default' do
          let :params do default_params end
          it 'should specify a NameVirtualHost' do
            is_expected.to contain_apache__listen(params[:port])
            is_expected.to contain_apache__namevirtualhost("*:#{params[:port]}")
          end
        end

        describe 'when an ip is set' do
          let :params do default_params.merge({ :ip => '10.0.0.1' }) end
          it 'should specify a NameVirtualHost for the ip' do
            is_expected.not_to contain_apache__listen(params[:port])
            is_expected.to contain_apache__listen("10.0.0.1:#{params[:port]}")
            is_expected.to contain_apache__namevirtualhost("10.0.0.1:#{params[:port]}")
          end
        end

        describe 'an ip_based vhost without a port' do
          let :params do
            {
              :docroot  => '/fake',
              :ip       => '10.0.0.1',
              :ip_based => true,
            }
          end
          it 'should specify a NameVirtualHost for the ip' do
            is_expected.not_to contain_apache__listen(params[:ip])
            is_expected.not_to contain_apache__namevirtualhost(params[:ip])
            is_expected.to contain_file("25-#{title}.conf").with_content %r{<VirtualHost 10\.0\.0\.1>}
          end
        end
      end

      describe 'when suexec_user_group is specified' do
        let :params do
          default_params.merge({
            :suexec_user_group => 'nobody nogroup',
          })
        end

        it { is_expected.to contain_file("25-#{title}.conf").with_content %r{^  SuexecUserGroup nobody nogroup$} }
      end

      describe 'redirect rules' do
        describe 'without lockstep arrays' do
          let :params do
            default_params.merge({
              :redirect_source => [
                '/login',
                '/logout',
              ],
              :redirect_dest   => [
                'http://10.0.0.10/login',
                'http://10.0.0.10/logout',
              ],
              :redirect_status   => [
                'permanent',
                '',
              ],
            })
          end

          it { is_expected.to contain_file("25-#{title}.conf").with_content %r{  Redirect permanent /login http://10\.0\.0\.10/login} }
          it { is_expected.to contain_file("25-#{title}.conf").with_content %r{  Redirect  /logout http://10\.0\.0\.10/logout} }
        end
        describe 'redirect match rules' do
          let :params do
            default_params.merge({
              :redirectmatch_status => [
                '404',
              ],
              :redirectmatch_regexp   => [
                '/\.git(/.*|$)',
              ],
            })
          end

          it { is_expected.to contain_file("25-#{title}.conf").with_content %r{  RedirectMatch 404 } }
        end
        describe 'without a status' do
          let :params do
            default_params.merge({
              :redirect_source => [
                '/login',
                '/logout',
              ],
              :redirect_dest   => [
                'http://10.0.0.10/login',
                'http://10.0.0.10/logout',
              ],
            })
          end

          it { is_expected.to contain_file("25-#{title}.conf").with_content %r{  Redirect  /login http://10\.0\.0\.10/login} }
          it { is_expected.to contain_file("25-#{title}.conf").with_content %r{  Redirect  /logout http://10\.0\.0\.10/logout} }
        end
        describe 'with a single status and dest' do
          let :params do
            default_params.merge({
              :redirect_source => [
                '/login',
                '/logout',
              ],
              :redirect_dest   => 'http://10.0.0.10/test',
              :redirect_status => 'permanent',
            })
          end

          it { is_expected.to contain_file("25-#{title}.conf").with_content %r{  Redirect permanent /login http://10\.0\.0\.10/test} }
          it { is_expected.to contain_file("25-#{title}.conf").with_content %r{  Redirect permanent /logout http://10\.0\.0\.10/test} }
        end

        describe 'with a directoryindex specified' do
          let :params do
            default_params.merge({
              :directoryindex => 'index.php'
            })
          end
          it { is_expected.to contain_file("25-#{title}.conf").with_content %r{DirectoryIndex index.php} }
	end
      end
    end
  end
end
# This is a file only for spec testing

LanguagePriority en ca cs da de el eo es et fr he hr it ja ko ltz nl nn no pl pt pt-BR ru sv zh-CN zh-TW
ForceLanguagePriority Prefer Fallback
# This is a file only for spec testing
Fake template for rspec.
# This is a template only for spec testing

LanguagePriority en ca cs da de el eo es et fr he hr it ja ko ltz nl nn no pl pt pt-BR ru sv zh-CN zh-TW
ForceLanguagePriority Prefer Fallback
s
mtime
require 'puppetlabs_spec_helper/module_spec_helper'

RSpec.configure do |c|
  c.treat_symbols_as_metadata_keys_with_true_values = true

  c.before :each do
    # Ensure that we don't accidentally cache facts and environment
    # between test cases.
    Facter::Util::Loader.any_instance.stubs(:load_all)
    Facter.clear
    Facter.clear_messages

    # Store any environment variables away to be restored later
    @old_env = {}
    ENV.each_key {|k| @old_env[k] = ENV[k]}

    if ENV['STRICT_VARIABLES'] == 'yes'
      Puppet.settings[:strict_variables]=true
    end
  end
end

shared_examples :compile, :compile => true do
  it { should compile.with_all_deps }
end
require 'beaker-rspec/spec_helper'
require 'beaker-rspec/helpers/serverspec'


unless ENV['RS_PROVISION'] == 'no'
  hosts.each do |host|
    if host['platform'] =~ /debian/
      on host, 'echo \'export PATH=/var/lib/gems/1.8/bin/:${PATH}\' >> ~/.bashrc'
    end
    if host.is_pe?
      install_pe
    else
      install_puppet
      on host, "mkdir -p #{host['distmoduledir']}"
    end
  end
end

UNSUPPORTED_PLATFORMS = ['Suse','windows','AIX','Solaris']

RSpec.configure do |c|
  # Project root
  proj_root = File.expand_path(File.join(File.dirname(__FILE__), '..'))

  # Readable test descriptions
  c.formatter = :documentation

  # Configure all nodes in nodeset
  c.before :suite do
    # Install module and dependencies
    puppet_module_install(:source => proj_root, :module_name => 'apache')
    hosts.each do |host|
      # Required for mod_passenger tests.
      if fact('osfamily') == 'RedHat'
        on host, puppet('module','install','stahnma/epel'), { :acceptable_exit_codes => [0,1] }
      end
      # Required for manifest to make mod_pagespeed repository available
      if fact('osfamily') == 'Debian'
        on host, puppet('module','install','puppetlabs-apt'), { :acceptable_exit_codes => [0,1] }
      end
      on host, puppet('module','install','puppetlabs-stdlib'), { :acceptable_exit_codes => [0,1] }
      on host, puppet('module','install','puppetlabs-concat'), { :acceptable_exit_codes => [0,1] }
    end
  end
end
#!/usr/bin/env rspec

require 'spec_helper'

provider_class = Puppet::Type.type(:a2mod).provider(:gentoo)

describe provider_class do
  before :each do
    provider_class.clear
  end

  [:conf_file, :instances, :modules, :initvars, :conf_file, :clear].each do |method|
    it "should respond to the class method #{method}" do
      expect(provider_class).to respond_to(method)
    end
  end

  describe "when fetching modules" do
    before do
      @filetype = mock()
    end

    it "should return a sorted array of the defined parameters" do
      @filetype.expects(:read).returns(%Q{APACHE2_OPTS="-D FOO -D BAR -D BAZ"\n})
      provider_class.expects(:filetype).returns(@filetype)

      expect(provider_class.modules).to eq(%w{bar baz foo})
    end

    it "should cache the module list" do
      @filetype.expects(:read).once.returns(%Q{APACHE2_OPTS="-D FOO -D BAR -D BAZ"\n})
      provider_class.expects(:filetype).once.returns(@filetype)

      2.times { expect(provider_class.modules).to eq(%w{bar baz foo}) }
    end

    it "should normalize parameters" do
      @filetype.expects(:read).returns(%Q{APACHE2_OPTS="-D FOO -D BAR -D BAR"\n})
      provider_class.expects(:filetype).returns(@filetype)

      expect(provider_class.modules).to eq(%w{bar foo})
    end
  end

  describe "when prefetching" do
    it "should match providers to resources" do
      provider = mock("ssl_provider", :name => "ssl")
      resource = mock("ssl_resource")
      resource.expects(:provider=).with(provider)

      provider_class.expects(:instances).returns([provider])
      provider_class.prefetch("ssl" => resource)
    end
  end

  describe "when flushing" do
    before :each do
      @filetype = mock()
      @filetype.stubs(:backup)
      provider_class.expects(:filetype).at_least_once.returns(@filetype)

      @info = mock()
      @info.stubs(:[]).with(:name).returns("info")
      @info.stubs(:provider=)

      @mpm = mock()
      @mpm.stubs(:[]).with(:name).returns("mpm")
      @mpm.stubs(:provider=)

      @ssl = mock()
      @ssl.stubs(:[]).with(:name).returns("ssl")
      @ssl.stubs(:provider=)
    end

    it "should add modules whose ensure is present" do
      @filetype.expects(:read).at_least_once.returns(%Q{APACHE2_OPTS=""})
      @filetype.expects(:write).with(%Q{APACHE2_OPTS="-D INFO"})

      @info.stubs(:should).with(:ensure).returns(:present)
      provider_class.prefetch("info" => @info)

      provider_class.flush
    end

    it "should remove modules whose ensure is present" do
      @filetype.expects(:read).at_least_once.returns(%Q{APACHE2_OPTS="-D INFO"})
      @filetype.expects(:write).with(%Q{APACHE2_OPTS=""})

      @info.stubs(:should).with(:ensure).returns(:absent)
      @info.stubs(:provider=)
      provider_class.prefetch("info" => @info)

      provider_class.flush
    end

    it "should not modify providers without resources" do
      @filetype.expects(:read).at_least_once.returns(%Q{APACHE2_OPTS="-D INFO -D MPM"})
      @filetype.expects(:write).with(%Q{APACHE2_OPTS="-D MPM -D SSL"})

      @info.stubs(:should).with(:ensure).returns(:absent)
      provider_class.prefetch("info" => @info)

      @ssl.stubs(:should).with(:ensure).returns(:present)
      provider_class.prefetch("ssl" => @ssl)

      provider_class.flush
    end

    it "should write the modules in sorted order" do
      @filetype.expects(:read).at_least_once.returns(%Q{APACHE2_OPTS=""})
      @filetype.expects(:write).with(%Q{APACHE2_OPTS="-D INFO -D MPM -D SSL"})

      @mpm.stubs(:should).with(:ensure).returns(:present)
      provider_class.prefetch("mpm" => @mpm)
      @info.stubs(:should).with(:ensure).returns(:present)
      provider_class.prefetch("info" => @info)
      @ssl.stubs(:should).with(:ensure).returns(:present)
      provider_class.prefetch("ssl" => @ssl)

      provider_class.flush
    end

    it "should write the records back once" do
      @filetype.expects(:read).at_least_once.returns(%Q{APACHE2_OPTS=""})
      @filetype.expects(:write).once.with(%Q{APACHE2_OPTS="-D INFO -D SSL"})

      @info.stubs(:should).with(:ensure).returns(:present)
      provider_class.prefetch("info" => @info)

      @ssl.stubs(:should).with(:ensure).returns(:present)
      provider_class.prefetch("ssl" => @ssl)

      provider_class.flush
    end

    it "should only modify the line containing APACHE2_OPTS" do
      @filetype.expects(:read).at_least_once.returns(%Q{# Comment\nAPACHE2_OPTS=""\n# Another comment})
      @filetype.expects(:write).once.with(%Q{# Comment\nAPACHE2_OPTS="-D INFO"\n# Another comment})

      @info.stubs(:should).with(:ensure).returns(:present)
      provider_class.prefetch("info" => @info)
      provider_class.flush
    end

    it "should restore any arbitrary arguments" do
      @filetype.expects(:read).at_least_once.returns(%Q{APACHE2_OPTS="-Y -D MPM -X"})
      @filetype.expects(:write).once.with(%Q{APACHE2_OPTS="-Y -X -D INFO -D MPM"})

      @info.stubs(:should).with(:ensure).returns(:present)
      provider_class.prefetch("info" => @info)
      provider_class.flush
    end

    it "should backup the file once if changes were made" do
      @filetype.expects(:read).at_least_once.returns(%Q{APACHE2_OPTS=""})
      @filetype.expects(:write).once.with(%Q{APACHE2_OPTS="-D INFO -D SSL"})

      @info.stubs(:should).with(:ensure).returns(:present)
      provider_class.prefetch("info" => @info)

      @ssl.stubs(:should).with(:ensure).returns(:present)
      provider_class.prefetch("ssl" => @ssl)

      @filetype.unstub(:backup)
      @filetype.expects(:backup)
      provider_class.flush
    end

    it "should not write the file or run backups if no changes were made" do
      @filetype.expects(:read).at_least_once.returns(%Q{APACHE2_OPTS="-X -D INFO -D SSL -Y"})
      @filetype.expects(:write).never

      @info.stubs(:should).with(:ensure).returns(:present)
      provider_class.prefetch("info" => @info)

      @ssl.stubs(:should).with(:ensure).returns(:present)
      provider_class.prefetch("ssl" => @ssl)

      @filetype.unstub(:backup)
      @filetype.expects(:backup).never
      provider_class.flush
    end
  end
end
<IfDefine NOHTTPACCEPT>
   AcceptFilter http none
   AcceptFilter https none
</IfDefine>
FastCGIExternalServer <%= @faux_path %> -idle-timeout <%= @timeout %> <%= if @flush then '-flush' end %> -host <%= @host %>
Alias <%= @fcgi_alias %> <%= @faux_path %>
Action <%= @file_type %> <%= @fcgi_alias %>
# Security
ServerTokens <%= @server_tokens %>
ServerSignature <%= @server_signature %>
TraceEnable <%= @trace_enable %>

ServerName "<%= @servername %>"
ServerRoot "<%= @server_root %>"
PidFile <%= @pidfile %>
Timeout <%= @timeout %>
KeepAlive <%= @keepalive %>
MaxKeepAliveRequests <%= @max_keepalive_requests %>
KeepAliveTimeout <%= @keepalive_timeout %>

User <%= @user %>
Group <%= @group %>

AccessFileName .htaccess
<FilesMatch "^\.ht">
<%- if scope.function_versioncmp([@apache_version, '2.4']) >= 0 -%>
    Require all denied
<%- else -%>
     Order allow,deny
     Deny from all
     Satisfy all
<%- end -%>
</FilesMatch>

<Directory />
  Options FollowSymLinks
  AllowOverride None
</Directory>

DefaultType none
HostnameLookups Off
ErrorLog "<%= @logroot %>/<%= @error_log %>"
LogLevel <%= @log_level %>
EnableSendfile <%= @sendfile %>

#Listen 80

<% if @apxs_workaround -%>
# Workaround: without this hack apxs would be confused about where to put
# LoadModule directives and fail entire procedure of apache package
# installation/reinstallation. This problem was observed on FreeBSD (apache22).
#LoadModule fake_module libexec/apache22/mod_fake.so
<% end -%>

Include "<%= @mod_load_dir %>/*.load"
<% if @mod_load_dir != @confd_dir and @mod_load_dir != @vhost_load_dir -%>
Include "<%= @mod_load_dir %>/*.conf"
<% end -%>
Include "<%= @ports_file %>"

LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %l %u %t \"%r\" %>s %b" common
LogFormat "%{Referer}i -> %U" referer
LogFormat "%{User-agent}i" agent
<% if @log_formats and !@log_formats.empty? -%>
  <%- @log_formats.each do |nickname,format| -%>
LogFormat "<%= format -%>" <%= nickname %>
  <%- end -%>
<% end -%>

<%- if scope.function_versioncmp([@apache_version, '2.4']) >= 0 -%>
IncludeOptional "<%= @confd_dir %>/*.conf"
<%- else -%>
Include "<%= @confd_dir %>/*.conf"
<%- end -%>
<% if @vhost_load_dir != @confd_dir -%>
Include "<%= @vhost_load_dir %>/*"
<% end -%>

<% if @error_documents -%>
# /usr/share/apache2/error on debian
Alias /error/ "<%= @error_documents_path %>/"

<Directory "<%= @error_documents_path %>">
  AllowOverride None
  Options IncludesNoExec
  AddOutputFilter Includes html
  AddHandler type-map var
<%- if scope.function_versioncmp([@apache_version, '2.4']) >= 0 -%>
  Require all granted
<%- else -%>
  Order allow,deny
  Allow from all
<%- end -%>
  LanguagePriority en cs de es fr it nl sv pt-br ro
  ForceLanguagePriority Prefer Fallback
</Directory>

ErrorDocument 400 /error/HTTP_BAD_REQUEST.html.var
ErrorDocument 401 /error/HTTP_UNAUTHORIZED.html.var
ErrorDocument 403 /error/HTTP_FORBIDDEN.html.var
ErrorDocument 404 /error/HTTP_NOT_FOUND.html.var
ErrorDocument 405 /error/HTTP_METHOD_NOT_ALLOWED.html.var
ErrorDocument 408 /error/HTTP_REQUEST_TIME_OUT.html.var
ErrorDocument 410 /error/HTTP_GONE.html.var
ErrorDocument 411 /error/HTTP_LENGTH_REQUIRED.html.var
ErrorDocument 412 /error/HTTP_PRECONDITION_FAILED.html.var
ErrorDocument 413 /error/HTTP_REQUEST_ENTITY_TOO_LARGE.html.var
ErrorDocument 414 /error/HTTP_REQUEST_URI_TOO_LARGE.html.var
ErrorDocument 415 /error/HTTP_UNSUPPORTED_MEDIA_TYPE.html.var
ErrorDocument 500 /error/HTTP_INTERNAL_SERVER_ERROR.html.var
ErrorDocument 501 /error/HTTP_NOT_IMPLEMENTED.html.var
ErrorDocument 502 /error/HTTP_BAD_GATEWAY.html.var
ErrorDocument 503 /error/HTTP_SERVICE_UNAVAILABLE.html.var
ErrorDocument 506 /error/HTTP_VARIANT_ALSO_VARIES.html.var
<% end -%>
<%# Listen should always be one of:
  - <port>
  - <ipv4>:<port>
  - [<ipv6]:<port>
-%>
Listen <%= @listen_addr_port %>
<IfModule alias_module>
Alias /icons/ "<%= @icons_path %>/"
<Directory "<%= @icons_path %>">
    Options Indexes MultiViews
    AllowOverride None
<%- if scope.function_versioncmp([@apache_version, '2.4']) >= 0 -%>
    Require all granted
<%- else -%>
     Order allow,deny
     Allow from all
<%- end -%>
</Directory>
</IfModule>
<% if @verifyServerCert == true -%>
LDAPVerifyServerCert On
<% else -%>
LDAPVerifyServerCert Off
<% end -%>
IndexOptions FancyIndexing VersionSort HTMLTable NameWidth=* DescriptionWidth=* Charset=UTF-8
AddIconByEncoding (CMP,/icons/compressed.gif) x-compress x-gzip x-bzip2

AddIconByType (TXT,/icons/text.gif) text/*
AddIconByType (IMG,/icons/image2.gif) image/*
AddIconByType (SND,/icons/sound2.gif) audio/*
AddIconByType (VID,/icons/movie.gif) video/*

AddIcon /icons/binary.gif .bin .exe
AddIcon /icons/binhex.gif .hqx
AddIcon /icons/tar.gif .tar
AddIcon /icons/world2.gif .wrl .wrl.gz .vrml .vrm .iv
AddIcon /icons/compressed.gif .Z .z .tgz .gz .zip
AddIcon /icons/a.gif .ps .ai .eps
AddIcon /icons/layout.gif .html .shtml .htm .pdf
AddIcon /icons/text.gif .txt
AddIcon /icons/c.gif .c
AddIcon /icons/p.gif .pl .py
AddIcon /icons/f.gif .for
AddIcon /icons/dvi.gif .dvi
AddIcon /icons/uuencoded.gif .uu
AddIcon /icons/script.gif .conf .sh .shar .csh .ksh .tcl
AddIcon /icons/tex.gif .tex
AddIcon /icons/bomb.gif /core
AddIcon (SND,/icons/sound2.gif) .ogg
AddIcon (VID,/icons/movie.gif) .ogm

AddIcon /icons/back.gif ..
AddIcon /icons/hand.right.gif README
AddIcon /icons/folder.gif ^^DIRECTORY^^
AddIcon /icons/blank.gif ^^BLANKICON^^

AddIcon /icons/odf6odt-20x22.png .odt
AddIcon /icons/odf6ods-20x22.png .ods
AddIcon /icons/odf6odp-20x22.png .odp
AddIcon /icons/odf6odg-20x22.png .odg
AddIcon /icons/odf6odc-20x22.png .odc
AddIcon /icons/odf6odf-20x22.png .odf
AddIcon /icons/odf6odb-20x22.png .odb
AddIcon /icons/odf6odi-20x22.png .odi
AddIcon /icons/odf6odm-20x22.png .odm

AddIcon /icons/odf6ott-20x22.png .ott
AddIcon /icons/odf6ots-20x22.png .ots
AddIcon /icons/odf6otp-20x22.png .otp
AddIcon /icons/odf6otg-20x22.png .otg
AddIcon /icons/odf6otc-20x22.png .otc
AddIcon /icons/odf6otf-20x22.png .otf
AddIcon /icons/odf6oti-20x22.png .oti
AddIcon /icons/odf6oth-20x22.png .oth

DefaultIcon /icons/unknown.gif
ReadmeName README.html
HeaderName HEADER.html

IndexIgnore .??* *~ *# HEADER* README* RCS CVS *,v *,t
ScriptSock "<%= @cgisock_path %>"
DAVLockDB "<%= @dav_lock %>"
<%- @types.sort.each do |type| -%>
AddOutputFilterByType DEFLATE <%= type %>
<%- end -%>

<%- @notes.sort.each do |type,note| -%>
DeflateFilterNote <%= type %> <%=note %>
<%- end -%>
DirectoryIndex <%= @indexes.join(' ') %>
<IfModule mod_proxy.c>
  <IfModule mod_disk_cache.c>
     CacheEnable disk /
     CacheRoot "<%= @cache_root %>"
     CacheDirLevels 2
     CacheDirLength 1
  </IfModule>
</IfModule>
<IfModule mpm_event_module>
  ServerLimit         <%= @serverlimit %>
  StartServers        <%= @startservers %>
  MaxClients          <%= @maxclients %>
  MinSpareThreads     <%= @minsparethreads %>
  MaxSpareThreads     <%= @maxsparethreads %>
  ThreadsPerChild     <%= @threadsperchild %>
  MaxRequestsPerChild <%= @maxrequestsperchild %>
</IfModule>
# The Fastcgi Apache module configuration file is being
# managed by Puppet and changes will be overwritten.
<IfModule mod_fastcgi.c>
  AddHandler fastcgi-script .fcgi
  FastCgiIpcDir "<%= @fastcgi_lib_path %>"
</IfModule>
<IfModule mod_fcgid.c>
<% @options.sort_by {|key, value| key}.each do |key, value| -%>
  <%= key %> <%= value %>
<% end -%>
</IfModule>
<Location /server-info>
    SetHandler server-info
<%- if @restrict_access -%>
  <%- if scope.function_versioncmp([@apache_version, '2.4']) >= 0 -%>
    Require ip <%= Array(@allow_from).join(" ") %>
  <%- else -%>
    Order deny,allow
    Deny from all
    <%- if @allow_from and ! @allow_from.empty? -%>
      <%- @allow_from.each do |allowed| -%>
    Allow from <%= allowed %>
      <%- end -%>
    <%- else -%>
    Allow from 127.0.0.1
    Allow from ::1
    <%- end -%>
  <%- end -%>
<%- end -%>
</Location>
<IfModule mpm_itk_module>
  StartServers        <%= @startservers %>
  MinSpareServers     <%= @minspareservers %>
  MaxSpareServers     <%= @maxspareservers %>
  ServerLimit         <%= @serverlimit %>
  MaxClients          <%= @maxclients %>
  MaxRequestsPerChild <%= @maxrequestsperchild %>
</IfModule>
<Location /ldap-status>
    SetHandler ldap-status
    <%- if scope.function_versioncmp([@apache_version, '2.4']) >= 0 -%>
    Require ip 127.0.0.1 ::1
    <%- else -%>
    Order deny,allow
    Deny from all
    Allow from 127.0.0.1 ::1
    Satisfy all
    <%- end -%>
</Location>
<% if @loadfiles -%>
<% Array(@loadfiles).each do |loadfile| -%>
LoadFile <%= loadfile %>
<% end -%>

<% end -%>
LoadModule <%= @_id %> <%= @_path %>
TypesConfig <%= @mime_types_config %>

AddType application/x-compress .Z
AddType application/x-gzip .gz .tgz
AddType application/x-bzip2 .bz2

AddLanguage ca .ca
AddLanguage cs .cz .cs
AddLanguage da .dk
AddLanguage de .de
AddLanguage el .el
AddLanguage en .en
AddLanguage eo .eo
AddLanguage es .es
AddLanguage et .et
AddLanguage fr .fr
AddLanguage he .he
AddLanguage hr .hr
AddLanguage it .it
AddLanguage ja .ja
AddLanguage ko .ko
AddLanguage ltz .ltz
AddLanguage nl .nl
AddLanguage nn .nn
AddLanguage no .no
AddLanguage pl .po
AddLanguage pt .pt
AddLanguage pt-BR .pt-br
AddLanguage ru .ru
AddLanguage sv .sv
AddLanguage zh-CN .zh-cn
AddLanguage zh-TW .zh-tw

AddHandler type-map var
AddType text/html .shtml
AddOutputFilter INCLUDES .shtml
MIMEMagicFile "<%= @magic_file %>"
<IfModule mpm_event_module>
  StartServers          2
  MinSpareThreads      25
  MaxSpareThreads      75
  ThreadLimit          64
  ThreadsPerChild      25
  MaxClients          150
  MaxRequestsPerChild   0
</IfModule>
LanguagePriority <%= Array(@language_priority).join(' ') %>
ForceLanguagePriority <%= Array(@force_language_priority).join(' ') %>
#
# This is the Apache server configuration file providing SSL support using.
# the mod_nss plugin.  It contains the configuration directives to instruct
# the server how to serve pages over an https connection.
#
# Do NOT simply read the instructions in here without understanding
# what they do.  They're here only as hints or reminders.  If you are unsure
# consult the online docs. You have been warned.
#

#LoadModule nss_module modules/libmodnss.so

#
# When we also provide SSL we have to listen to the
# standard HTTP port (see above) and to the HTTPS port
#
# Note: Configurations that use IPv6 but not IPv4-mapped addresses need two
#       Listen directives: "Listen [::]:8443" and "Listen 0.0.0.0:443"
#
Listen 8443

##
##  SSL Global Context
##
##  All SSL configuration in this context applies both to
##  the main server and all SSL-enabled virtual hosts.
##

#
#   Some MIME-types for downloading Certificates and CRLs
#
AddType application/x-x509-ca-cert .crt
AddType application/x-pkcs7-crl    .crl

#   Pass Phrase Dialog:
#   Configure the pass phrase gathering process.
#   The filtering dialog program (`builtin' is a internal
#   terminal dialog) has to provide the pass phrase on stdout.
<% if @passwd_file -%>
NSSPassPhraseDialog  "file:<%= @passwd_file %>"
<% else -%>
NSSPassPhraseDialog  builtin
<% end -%>

#   Pass Phrase Helper:
#   This helper program stores the token password pins between
#   restarts of Apache.
NSSPassPhraseHelper /usr/sbin/nss_pcache

#   Configure the SSL Session Cache.
#   NSSSessionCacheSize is the number of entries in the cache.
#   NSSSessionCacheTimeout is the SSL2 session timeout (in seconds).
#   NSSSession3CacheTimeout is the SSL3/TLS session timeout (in seconds).
NSSSessionCacheSize 10000
NSSSessionCacheTimeout 100
NSSSession3CacheTimeout 86400

#
# Pseudo Random Number Generator (PRNG):
# Configure one or more sources to seed the PRNG of the SSL library.
# The seed data should be of good random quality.
# WARNING! On some platforms /dev/random blocks if not enough entropy
# is available. Those platforms usually also provide a non-blocking
# device, /dev/urandom, which may be used instead.
#
# This does not support seeding the RNG with each connection.

NSSRandomSeed startup builtin
#NSSRandomSeed startup file:/dev/random  512
#NSSRandomSeed startup file:/dev/urandom 512

#
# TLS Negotiation configuration under RFC 5746
#
# Only renegotiate if the peer's hello bears the TLS renegotiation_info
# extension. Default off.
NSSRenegotiation off

# Peer must send Signaling Cipher Suite Value (SCSV) or
# Renegotiation Info (RI) extension in ALL handshakes.  Default: off
NSSRequireSafeNegotiation off

##
## SSL Virtual Host Context
##

<VirtualHost _default_:8443>

#   General setup for the virtual host
#DocumentRoot "/etc/httpd/htdocs"
#ServerName www.example.com:8443
#ServerAdmin you@example.com

# mod_nss can log to separate log files, you can choose to do that if you'd like
# LogLevel is not inherited from httpd.conf.
ErrorLog "<%= @error_log %>"
TransferLog "<%= @transfer_log %>"
LogLevel warn

#   SSL Engine Switch:
#   Enable/Disable SSL for this virtual host.
NSSEngine on

#   SSL Cipher Suite:
#   List the ciphers that the client is permitted to negotiate.
#   See the mod_nss documentation for a complete list.

# SSL 3 ciphers. SSL 2 is disabled by default.
NSSCipherSuite +rsa_rc4_128_md5,+rsa_rc4_128_sha,+rsa_3des_sha,-rsa_des_sha,-rsa_rc4_40_md5,-rsa_rc2_40_md5,-rsa_null_md5,-rsa_null_sha,+fips_3des_sha,-fips_des_sha,-fortezza,-fortezza_rc4_128_sha,-fortezza_null,-rsa_des_56_sha,-rsa_rc4_56_sha,+rsa_aes_128_sha,+rsa_aes_256_sha

# SSL 3 ciphers + ECC ciphers. SSL 2 is disabled by default.
#
# Comment out the NSSCipherSuite line above and use the one below if you have
# ECC enabled NSS and mod_nss and want to use Elliptical Curve Cryptography
#NSSCipherSuite +rsa_rc4_128_md5,+rsa_rc4_128_sha,+rsa_3des_sha,-rsa_des_sha,-rsa_rc4_40_md5,-rsa_rc2_40_md5,-rsa_null_md5,-rsa_null_sha,+fips_3des_sha,-fips_des_sha,-fortezza,-fortezza_rc4_128_sha,-fortezza_null,-rsa_des_56_sha,-rsa_rc4_56_sha,+rsa_aes_128_sha,+rsa_aes_256_sha,-ecdh_ecdsa_null_sha,+ecdh_ecdsa_rc4_128_sha,+ecdh_ecdsa_3des_sha,+ecdh_ecdsa_aes_128_sha,+ecdh_ecdsa_aes_256_sha,-ecdhe_ecdsa_null_sha,+ecdhe_ecdsa_rc4_128_sha,+ecdhe_ecdsa_3des_sha,+ecdhe_ecdsa_aes_128_sha,+ecdhe_ecdsa_aes_256_sha,-ecdh_rsa_null_sha,+ecdh_rsa_128_sha,+ecdh_rsa_3des_sha,+ecdh_rsa_aes_128_sha,+ecdh_rsa_aes_256_sha,-echde_rsa_null,+ecdhe_rsa_rc4_128_sha,+ecdhe_rsa_3des_sha,+ecdhe_rsa_aes_128_sha,+ecdhe_rsa_aes_256_sha

#   SSL Protocol:
#   Cryptographic protocols that provide communication security.
#   NSS handles the specified protocols as "ranges", and automatically
#   negotiates the use of the strongest protocol for a connection starting
#   with the maximum specified protocol and downgrading as necessary to the
#   minimum specified protocol that can be used between two processes.
#   Since all protocol ranges are completely inclusive, and no protocol in the
#   middle of a range may be excluded, the entry "NSSProtocol SSLv3,TLSv1.1"
#   is identical to the entry "NSSProtocol SSLv3,TLSv1.0,TLSv1.1".
NSSProtocol SSLv3,TLSv1.0,TLSv1.1

#   SSL Certificate Nickname:
#   The nickname of the RSA server certificate you are going to use.
NSSNickname Server-Cert

#   SSL Certificate Nickname:
#   The nickname of the ECC server certificate you are going to use, if you
#   have an ECC-enabled version of NSS and mod_nss
#NSSECCNickname Server-Cert-ecc

#   Server Certificate Database:
#   The NSS security database directory that holds the certificates and
#   keys. The database consists of 3 files: cert8.db, key3.db and secmod.db.
#   Provide the directory that these files exist.
NSSCertificateDatabase "<%= @httpd_dir -%>/alias"

#   Database Prefix:
#   In order to be able to store multiple NSS databases in one directory
#   they need unique names. This option sets the database prefix used for
#   cert8.db and key3.db.
#NSSDBPrefix my-prefix-

#   Client Authentication (Type):
#   Client certificate verification type.  Types are none, optional and
#   require.
#NSSVerifyClient none

#
#   Online Certificate Status Protocol (OCSP).
#   Verify that certificates have not been revoked before accepting them.
#NSSOCSP off

#
#   Use a default OCSP responder. If enabled this will be used regardless
#   of whether one is included in a client certificate. Note that the
#   server certificate is verified during startup.
#
#   NSSOCSPDefaultURL defines the service URL of the OCSP responder
#   NSSOCSPDefaultName is the nickname of the certificate to trust to
#       sign the OCSP responses.
#NSSOCSPDefaultResponder on
#NSSOCSPDefaultURL http://example.com/ocsp/status
#NSSOCSPDefaultName ocsp-nickname

#   Access Control:
#   With SSLRequire you can do per-directory access control based
#   on arbitrary complex boolean expressions containing server
#   variable checks and other lookup directives.  The syntax is a
#   mixture between C and Perl.  See the mod_nss documentation
#   for more details.
#<Location />
#NSSRequire (    %{SSL_CIPHER} !~ m/^(EXP|NULL)/ \
#            and %{SSL_CLIENT_S_DN_O} eq "Snake Oil, Ltd." \
#            and %{SSL_CLIENT_S_DN_OU} in {"Staff", "CA", "Dev"} \
#            and %{TIME_WDAY} >= 1 and %{TIME_WDAY} <= 5 \
#            and %{TIME_HOUR} >= 8 and %{TIME_HOUR} <= 20       ) \
#           or %{REMOTE_ADDR} =~ m/^192\.76\.162\.[0-9]+$/
#</Location>

#   SSL Engine Options:
#   Set various options for the SSL engine.
#   o FakeBasicAuth:
#     Translate the client X.509 into a Basic Authorisation.  This means that
#     the standard Auth/DBMAuth methods can be used for access control.  The
#     user name is the `one line' version of the client's X.509 certificate.
#     Note that no password is obtained from the user. Every entry in the user
#     file needs this password: `xxj31ZMTZzkVA'.
#   o ExportCertData:
#     This exports two additional environment variables: SSL_CLIENT_CERT and
#     SSL_SERVER_CERT. These contain the PEM-encoded certificates of the
#     server (always existing) and the client (only existing when client
#     authentication is used). This can be used to import the certificates
#     into CGI scripts.
#   o StdEnvVars:
#     This exports the standard SSL/TLS related `SSL_*' environment variables.
#     Per default this exportation is switched off for performance reasons,
#     because the extraction step is an expensive operation and is usually
#     useless for serving static content. So one usually enables the
#     exportation for CGI and SSI requests only.
#   o StrictRequire:
#     This denies access when "NSSRequireSSL" or "NSSRequire" applied even
#     under a "Satisfy any" situation, i.e. when it applies access is denied
#     and no other module can change it.
#   o OptRenegotiate:
#     This enables optimized SSL connection renegotiation handling when SSL
#     directives are used in per-directory context.
#NSSOptions +FakeBasicAuth +ExportCertData +CompatEnvVars +StrictRequire
<FilesMatch "\.(cgi|shtml|phtml|php3?)$">
    NSSOptions +StdEnvVars
</FilesMatch>
<Directory "/var/www/cgi-bin">
    NSSOptions +StdEnvVars
</Directory>

#   Per-Server Logging:
#   The home of a custom SSL log file. Use this when you want a
#   compact non-error SSL logfile on a virtual host basis.
#CustomLog /home/rcrit/redhat/apache/logs/ssl_request_log \
#          "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"

</VirtualHost>

ModPagespeed on

ModPagespeedInheritVHostConfig <%= @inherit_vhost_config %>
AddOutputFilterByType MOD_PAGESPEED_OUTPUT_FILTER text/html
<% if @filter_xhtml -%>
AddOutputFilterByType MOD_PAGESPEED_OUTPUT_FILTER application/xhtml+xml
<% end -%>
ModPagespeedFileCachePath "<%= @cache_path %>"
ModPagespeedLogDir "<%= @log_dir %>"
    
<% @memache_servers.each do |server| -%>
ModPagespeedMemcachedServers <%= server -%>
<% end -%>

ModPagespeedRewriteLevel <%= @rewrite_level -%>

<% @disable_filters.each do |filter| -%>
ModPagespeedDisableFilters <%= filter -%>
<% end -%>
    
<% @enable_filters.each do |filter| -%>
ModPagespeedEnableFilters <%= filter -%>
<% end -%>

<% @forbid_filters.each do |filter| -%>
ModPagespeedForbidFilters <%= filter -%>
<% end -%>

ModPagespeedRewriteDeadlinePerFlushMs <%= @rewrite_deadline_per_flush_ms %>

<% if @additional_domains -%>
ModPagespeedDomain <%= @additional_domains -%>
<% end -%>

ModPagespeedFileCacheSizeKb          <%= @file_cache_size_kb %>
ModPagespeedFileCacheCleanIntervalMs <%= @file_cache_clean_interval_ms %>
ModPagespeedLRUCacheKbPerProcess     <%= @lru_cache_per_process %>
ModPagespeedLRUCacheByteLimit        <%= @lru_cache_byte_limit %>
ModPagespeedCssFlattenMaxBytes       <%= @css_flatten_max_bytes %>
ModPagespeedCssInlineMaxBytes        <%= @css_inline_max_bytes %>
ModPagespeedCssImageInlineMaxBytes   <%= @css_image_inline_max_bytes %>
ModPagespeedImageInlineMaxBytes      <%= @image_inline_max_bytes %>
ModPagespeedJsInlineMaxBytes         <%= @js_inline_max_bytes %>
ModPagespeedCssOutlineMinBytes       <%= @css_outline_min_bytes %>
ModPagespeedJsOutlineMinBytes        <%= @js_outline_min_bytes %>


ModPagespeedFileCacheInodeLimit <%= @inode_limit %>
ModPagespeedImageMaxRewritesAtOnce <%= @image_max_rewrites_at_once %>

ModPagespeedNumRewriteThreads <%= @num_rewrite_threads %>
ModPagespeedNumExpensiveRewriteThreads <%= @num_expensive_rewrite_threads %>

ModPagespeedStatistics <%= @collect_statistics %>

<Location /mod_pagespeed_statistics>
    # You may insert other "Allow from" lines to add hosts you want to
    # allow to look at generated statistics.  Another possibility is
    # to comment out the "Order" and "Allow" options from the config
    # file, to allow any client that can reach your server to examine
    # statistics.  This might be appropriate in an experimental setup or
    # if the Apache server is protected by a reverse proxy that will
    # filter URLs in some fashion.
    <%- if scope.function_versioncmp([@apache_version, '2.4']) >= 0 -%>
    Require ip 127.0.0.1 ::1 <%= Array(@allow_view_stats).join(" ") %>
    <%- else -%>
    Order allow,deny
    Allow from 127.0.0.1 ::1 <%= Array(@allow_view_stats).join(" ") %>
    <%- end -%>
    SetHandler mod_pagespeed_statistics
</Location>

ModPagespeedStatisticsLogging <%= @statistics_logging %>
<Location /pagespeed_console>
    <%- if scope.function_versioncmp([@apache_version, '2.4']) >= 0 -%>
    Require ip 127.0.0.1 ::1 <%= Array(@allow_pagespeed_console).join(" ") %>
    <%- else -%>
    Order allow,deny
    Allow from 127.0.0.1 ::1 <%= Array(@allow_pagespeed_console).join(" ") %>
    <%- end -%>
    SetHandler pagespeed_console
</Location>

ModPagespeedMessageBufferSize <%= @message_buffer_size %>

<Location /mod_pagespeed_message>
    <%- if scope.function_versioncmp([@apache_version, '2.4']) >= 0 -%>
    Require ip 127.0.0.1 ::1 <%= Array(@allow_pagespeed_message).join(" ") %>
    <%- else -%>
    Order allow,deny
    Allow from 127.0.0.1 ::1 <%= Array(@allow_pagespeed_message).join(" ") %>
    <%- end -%>
    SetHandler mod_pagespeed_message
</Location>

<% @additional_configuration.each_pair do |key, value| -%>
<%= key %> <%= value %>
<% end -%>
# The Passanger Apache module configuration file is being
# managed by Puppet and changes will be overwritten.
<IfModule mod_passenger.c>
  <%- if @passenger_root -%>
  PassengerRoot "<%= @passenger_root %>"
  <%- end -%>
  <%- if @passenger_ruby -%>
  PassengerRuby "<%= @passenger_ruby %>"
  <%- end -%>
  <%- if @passenger_default_ruby -%>
  PassengerDefaultRuby "<%= @passenger_default_ruby %>"
  <%- end -%>
  <%- if @passenger_high_performance -%>
  PassengerHighPerformance <%= @passenger_high_performance %>
  <%- end -%>
  <%- if @passenger_max_pool_size -%>
  PassengerMaxPoolSize <%= @passenger_max_pool_size %>
  <%- end -%>
  <%- if @passenger_pool_idle_time -%>
  PassengerPoolIdleTime <%= @passenger_pool_idle_time %>
  <%- end -%>
  <%- if @passenger_max_requests -%>
  PassengerMaxRequests <%= @passenger_max_requests %>
  <%- end -%>
  <%- if @passenger_stat_throttle_rate -%>
  PassengerStatThrottleRate <%= @passenger_stat_throttle_rate %>
  <%- end -%>
  <%- if @rack_autodetect -%>
  RackAutoDetect <%= @rack_autodetect %>
  <%- end -%>
  <%- if @rails_autodetect -%>
  RailsAutoDetect <%= @rails_autodetect %>
  <%- end -%>
  <%- if @passenger_use_global_queue -%>
  PassengerUseGlobalQueue <%= @passenger_use_global_queue %>
  <%- end -%>
</IfModule>
<IfModule mpm_peruser_module>
  MinSpareProcessors  <%= @minspareprocessors %>
  MinProcessors       <%= @minprocessors %>
  MaxProcessors       <%= @maxprocessors %>
  MaxClients          <%= @maxclients %>
  MaxRequestsPerChild <%= @maxrequestsperchild %>
  IdleTimeout         <%= @idletimeout %>
  ExpireTimeout       <%= @expiretimeout %>
  KeepAlive           <%= @keepalive %>
  Include             "<%= @mod_dir %>/peruser/multiplexers/*.conf"
  Include             "<%= @mod_dir %>/peruser/processors/*.conf"
</IfModule>
#
# PHP is an HTML-embedded scripting language which attempts to make it
# easy for developers to write dynamically generated webpages.
#
#<IfModule prefork.c>
#  LoadModule php5_module modules/libphp5.so
#</IfModule>
#<IfModule worker.c>
#  # Use of the "ZTS" build with worker is experimental, and no shared
#  # modules are supported.
#  LoadModule php5_module modules/libphp5-zts.so
#</IfModule>

#
# Cause the PHP interpreter to handle files with a .php extension.
#
AddHandler php5-script <%= @extensions.flatten.compact.join(' ') %>
AddType text/html .php

#
# Add index.php to the list of files that will be served as directory
# indexes.
#
DirectoryIndex index.php

#
# Uncomment the following line to allow PHP to pretty-print .phps
# files as PHP source code:
#
#AddType application/x-httpd-php-source .phps
<IfModule mpm_prefork_module>
  StartServers        <%= @startservers %>
  MinSpareServers     <%= @minspareservers %>
  MaxSpareServers     <%= @maxspareservers %>
  ServerLimit         <%= @serverlimit %>
  MaxClients          <%= @maxclients %>
  MaxRequestsPerChild <%= @maxrequestsperchild %>
</IfModule>
#
# Proxy Server directives. Uncomment the following lines to
# enable the proxy server:
#
<IfModule mod_proxy.c>
  # Do not enable proxying with ProxyRequests until you have secured your
  # server.  Open proxy servers are dangerous both to your network and to the
  # Internet at large.
  ProxyRequests <%= @proxy_requests %>

  <% if @proxy_requests != 'Off' or ( @allow_from and ! @allow_from.empty? ) -%>
  <Proxy *>
    <%- if scope.function_versioncmp([@apache_version, '2.4']) >= 0 -%>
    Require ip <%= Array(@allow_from).join(" ") %>
    <%- else -%>
    Order deny,allow
    Deny from all
    Allow from <%= Array(@allow_from).join(" ") %>
    <%- end -%>
  </Proxy>
  <% end -%>

  # Enable/disable the handling of HTTP/1.1 "Via:" headers.
  # ("Full" adds the server version; "Block" removes all outgoing Via: headers)
  # Set to one of: Off | On | Full | Block
  ProxyVia On
</IfModule>
ProxyHTMLLinks  a               href
ProxyHTMLLinks  area            href
ProxyHTMLLinks  link            href
ProxyHTMLLinks  img             src longdesc usemap
ProxyHTMLLinks  object          classid codebase data usemap
ProxyHTMLLinks  q               cite
ProxyHTMLLinks  blockquote      cite
ProxyHTMLLinks  ins             cite
ProxyHTMLLinks  del             cite
ProxyHTMLLinks  form            action
ProxyHTMLLinks  input           src usemap
ProxyHTMLLinks  head            profileProxyHTMLLinks  base            href
ProxyHTMLLinks  script          src for

ProxyHTMLEvents onclick ondblclick onmousedown onmouseup \
                onmouseover onmousemove onmouseout onkeypress \
                onkeydown onkeyup onfocus onblur onload \
                onunload onsubmit onreset onselect onchange
RequestReadTimeout header=20-40,minrate=500
RequestReadTimeout body=10,minrate=500
# Enable reverse proxy add forward
RPAFenable On
# RPAFsethostname will, when enabled, take the incoming X-Host header and
# update the virtual host settings accordingly. This allows to have the same
# hostnames as in the "real" configuration for the forwarding proxy.
<% if @sethostname -%>
RPAFsethostname On
<% else -%>
RPAFsethostname Off
<% end -%>
# Which IPs are forwarding requests to us
RPAFproxy_ips <%= Array(@proxy_ips).join(" ") %>
# Setting RPAFheader allows you to change the header name to parse from the
# default X-Forwarded-For to something of your choice.
RPAFheader <%= @header %>
#
# The following directives modify normal HTTP response behavior to
# handle known problems with browser implementations.
#
BrowserMatch "Mozilla/2" nokeepalive
BrowserMatch "MSIE 4\.0b2;" nokeepalive downgrade-1.0 force-response-1.0
BrowserMatch "RealPlayer 4\.0" force-response-1.0
BrowserMatch "Java/1\.0" force-response-1.0
BrowserMatch "JDK/1\.0" force-response-1.0

#
# The following directive disables redirects on non-GET requests for
# a directory that does not include the trailing slash.  This fixes a 
# problem with Microsoft WebFolders which does not appropriately handle 
# redirects for folders with DAV methods.
# Same deal with Apple's DAV filesystem and Gnome VFS support for DAV.
#
BrowserMatch "Microsoft Data Access Internet Publishing Provider" redirect-carefully
BrowserMatch "MS FrontPage" redirect-carefully
BrowserMatch "^WebDrive" redirect-carefully
BrowserMatch "^WebDAVFS/1.[0123]" redirect-carefully
BrowserMatch "^gnome-vfs/1.0" redirect-carefully
BrowserMatch "^gvfs/1" redirect-carefully
BrowserMatch "^XML Spy" redirect-carefully
BrowserMatch "^Dreamweaver-WebDAV-SCM1" redirect-carefully
BrowserMatch " Konqueror/4" redirect-carefully

<IfModule mod_ssl.c>
  BrowserMatch "MSIE [2-6]" \
    nokeepalive ssl-unclean-shutdown \
    downgrade-1.0 force-response-1.0
  # MSIE 7 and newer should be able to use keepalive
  BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown
</IfModule>
<IfModule mod_ssl.c>
  SSLRandomSeed startup builtin
  SSLRandomSeed startup file:/dev/urandom 512
  SSLRandomSeed connect builtin
  SSLRandomSeed connect file:/dev/urandom 512

  AddType application/x-x509-ca-cert .crt
  AddType application/x-pkcs7-crl    .crl

  SSLPassPhraseDialog  builtin
  SSLSessionCache "shmcb:<%= @session_cache %>"
  SSLSessionCacheTimeout 300
<% if @ssl_compression -%>
  SSLCompression On
<% end -%>
  <% if scope.function_versioncmp([@apache_version, '2.4']) >= 0 -%>
  Mutex <%= @ssl_mutex %>
  <% else -%>
  SSLMutex <%= @ssl_mutex %>
  <% end -%>
  SSLCryptoDevice builtin
  SSLHonorCipherOrder On
  SSLCipherSuite <%= @ssl_cipher %>
  SSLProtocol all -SSLv2
<% if @ssl_options -%>
  SSLOptions <%= @ssl_options.compact.join(' ') %>
<% end -%>
</IfModule>
<Location /server-status>
    SetHandler server-status
    <%- if scope.function_versioncmp([@apache_version, '2.4']) >= 0 -%>
    Require ip <%= Array(@allow_from).join(" ") %>
    <%- else -%>
    Order deny,allow
    Deny from all
    Allow from <%= Array(@allow_from).join(" ") %>
    <%- end -%>
</Location>
ExtendedStatus <%= @extended_status %>

<IfModule mod_proxy.c>
    # Show Proxy LoadBalancer status in mod_status
    ProxyStatus On
</IfModule>
<IfModule mod_suphp.c>
    AddType application/x-httpd-suphp .php .php3 .php4 .php5 .phtml
    suPHP_AddHandler application/x-httpd-suphp

    <Directory />
        suPHP_Engine on
    </Directory>

    # By default, disable suPHP for debian packaged web applications as files
    # are owned by root and cannot be executed by suPHP because of min_uid.
    <Directory /usr/share>
        suPHP_Engine off
    </Directory>

# # Use a specific php config file (a dir which contains a php.ini file)
#       suPHP_ConfigPath /etc/php4/cgi/suphp/
# # Tells mod_suphp NOT to handle requests with the type <mime-type>.
#       suPHP_RemoveHandler <mime-type>
</IfModule>
<IfModule mod_userdir.c>
<% if @disable_root -%>
  UserDir disabled root
<% end -%>
  UserDir <%= @dir %>

  <Directory "<%= @home %>/*/<%= @dir %>">
    AllowOverride FileInfo AuthConfig Limit Indexes
    Options MultiViews Indexes SymLinksIfOwnerMatch IncludesNoExec
    <Limit GET POST OPTIONS>
      <%- if scope.function_versioncmp([@apache_version, '2.4']) >= 0 -%>
      Require all denied
      <%- else -%>
      Order allow,deny
      Allow from all
      <%- end -%>
    </Limit>
    <LimitExcept GET POST OPTIONS>
      <%- if scope.function_versioncmp([@apache_version, '2.4']) >= 0 -%>
      Require all denied
      <%- else -%>
      Order allow,deny
      Allow from all
      <%- end -%>
    </LimitExcept>
  </Directory>
</IfModule>
<IfModule mpm_worker_module>
  ServerLimit         <%= @serverlimit %>
  StartServers        <%= @startservers %>
  MaxClients          <%= @maxclients %>
  MinSpareThreads     <%= @minsparethreads %>
  MaxSpareThreads     <%= @maxsparethreads %>
  ThreadsPerChild     <%= @threadsperchild %>
  MaxRequestsPerChild <%= @maxrequestsperchild %>
  ThreadLimit         <%= @threadlimit %>
</IfModule>
# The WSGI Apache module configuration file is being
# managed by Puppet an changes will be overwritten.
<IfModule mod_wsgi.c>
  <%- if @wsgi_socket_prefix -%>
  WSGISocketPrefix <%= @wsgi_socket_prefix %>
  <%- end -%>
  <%- if @wsgi_python_home -%>
  WSGIPythonHome "<%= @wsgi_python_home %>"
  <%- end -%>
  <%- if @wsgi_python_path -%>
  WSGIPythonPath "<%= @wsgi_python_path %>"
  <%- end -%>
</IfModule>
<%# NameVirtualHost should always be one of:
  - *
  - *:<port>
  - _default_:<port>
  - <ip>
  - <ip>:<port>
-%>
NameVirtualHost <%= @addr_port %>
# ************************************
# Listen & NameVirtualHost resources in module puppetlabs-apache
# Managed by Puppet
# ************************************

# ************************************
# Vhost template in module puppetlabs-apache
# Managed by Puppet
# ************************************

<VirtualHost <%= @nvh_addr_port %>>
  ServerName <%= @servername %>
<% if @serveradmin -%>
  ServerAdmin <%= @serveradmin %>
<% end -%>

  ## Vhost docroot
<% if @virtual_docroot -%>
  VirtualDocumentRoot "<%= @virtual_docroot %>"
<% else -%>
  DocumentRoot "<%= @docroot %>"
<% end -%>
<%= scope.function_template(['apache/vhost/_aliases.erb']) -%>

<%= scope.function_template(['apache/vhost/_itk.erb']) -%>

<% if @fallbackresource -%>
  FallbackResource <%= @fallbackresource %>
<% end -%>

  ## Directories, there should at least be a declaration for <%= @docroot %>
<%= scope.function_template(['apache/vhost/_directories.erb']) -%>

  ## Load additional static includes
<% Array(@additional_includes).each do |include| %>
  Include "<%= include %>"
<% end %>

  ## Logging
<% if @error_log -%>
  ErrorLog "<%= @error_log_destination %>"
<% end -%>
<% if @log_level -%>
  LogLevel <%= @log_level %>
<% end -%>
  ServerSignature Off
<% if @access_log and @_access_log_env_var -%>
  CustomLog "<%= @access_log_destination %>" <%= @_access_log_format %> <%= @_access_log_env_var %>
<% elsif @access_log -%>
  CustomLog "<%= @access_log_destination %>" <%= @_access_log_format %>
<% end -%>
<%= scope.function_template(['apache/vhost/_action.erb']) -%>
<%= scope.function_template(['apache/vhost/_block.erb']) -%>
<%= scope.function_template(['apache/vhost/_error_document.erb']) -%>
<%= scope.function_template(['apache/vhost/_proxy.erb']) -%>
<%= scope.function_template(['apache/vhost/_rack.erb']) -%>
<%= scope.function_template(['apache/vhost/_redirect.erb']) -%>
<%= scope.function_template(['apache/vhost/_rewrite.erb']) -%>
<%= scope.function_template(['apache/vhost/_scriptalias.erb']) -%>
<%= scope.function_template(['apache/vhost/_serveralias.erb']) -%>
<%= scope.function_template(['apache/vhost/_setenv.erb']) -%>
<%= scope.function_template(['apache/vhost/_ssl.erb']) -%>
<%= scope.function_template(['apache/vhost/_suphp.erb']) -%>
<%= scope.function_template(['apache/vhost/_php_admin.erb']) -%>
<%= scope.function_template(['apache/vhost/_header.erb']) -%>
<%= scope.function_template(['apache/vhost/_requestheader.erb']) -%>
<%= scope.function_template(['apache/vhost/_wsgi.erb']) -%>
<%= scope.function_template(['apache/vhost/_custom_fragment.erb']) -%>
<%= scope.function_template(['apache/vhost/_fastcgi.erb']) -%>
<%= scope.function_template(['apache/vhost/_suexec.erb']) -%>
</VirtualHost>
<% if @action -%>

  Action <%= @action %> /cgi-bin virtual
<% end -%>
<% if @aliases and ! @aliases.empty? -%>
  ## Alias declarations for resources outside the DocumentRoot
  <%- [@aliases].flatten.compact.each do |alias_statement| -%>
    <%- if alias_statement["path"] != '' -%>
      <%- if alias_statement["alias"] and alias_statement["alias"] != '' -%>
  Alias <%= alias_statement["alias"] %> "<%= alias_statement["path"] %>"
      <%- elsif alias_statement["aliasmatch"] and alias_statement["aliasmatch"] != '' -%>
  AliasMatch <%= alias_statement["aliasmatch"] %> "<%= alias_statement["path"] %>"
      <%- end -%>
    <%- end -%>
  <%- end -%>
<% end -%>
<% if @block and ! @block.empty? -%>

  ## Block access statements
<% if @block.include? 'scm' -%>
  # Block access to SCM directories.
  <DirectoryMatch .*\.(svn|git|bzr)/.*>
  <%- if scope.function_versioncmp([@apache_version, '2.4']) >= 0 -%>
    Require all denied
  <%- else -%>
    Deny From All
  <%- end -%>
  </DirectoryMatch>
<% end -%>
<% end -%>
<% if @custom_fragment -%>

  ## Custom fragment
<%= @custom_fragment %>
<% end -%>
<% if @_directories and ! @_directories.empty? -%>
  <%- [@_directories].flatten.compact.each do |directory| -%>
    <%- if directory['path'] and directory['path'] != '' -%>
  <%- if directory['provider'] and directory['provider'].match('(directory|location|files)') -%>
    <%- if /^(.*)match$/ =~ directory['provider'] -%>
      <%- provider = $1.capitalize + 'Match' -%>
    <%- else -%>
      <%- provider = directory['provider'].capitalize -%>
    <%- end -%>
  <%- else -%>
    <%- provider = 'Directory' -%>
  <%- end -%>
  <%- path = directory['path'] -%>

  <<%= provider %> "<%= path %>">
    <%- if directory['headers'] -%>
      <%- Array(directory['headers']).each do |header| -%>
    Header <%= header %>
      <%- end -%>
    <%- end -%>
    <%- if directory['options'] -%>
    Options <%= Array(directory['options']).join(' ') %>
    <%- end -%>
    <%- if provider == 'Directory' -%>
      <%- if directory['index_options'] -%>
    IndexOptions <%= Array(directory['index_options']).join(' ') %>
      <%- end -%>
      <%- if directory['index_order_default'] -%>
    IndexOrderDefault <%= Array(directory['index_order_default']).join(' ') %>
      <%- end -%>
      <%- if directory['allow_override'] -%>
    AllowOverride <%= Array(directory['allow_override']).join(' ') %>
      <%- elsif provider == 'Directory' -%>
    AllowOverride None
      <%- end -%>
    <%- end -%>
    <%- if scope.function_versioncmp([@apache_version, '2.4']) >= 0 -%>
      <%- if directory['require'] and directory['require'] != '' -%>
    Require <%= Array(directory['require']).join(' ') %>
      <%- else -%>
    Require all granted
      <%- end -%>
    <%- else -%>
      <%- if directory['order'] and directory['order'] != '' -%>
    Order <%= Array(directory['order']).join(',') %>
      <%- else -%>
    Order allow,deny
      <%- end -%>
      <%- if directory['deny'] and directory['deny'] != '' -%>
    Deny <%= directory['deny'] %>
      <%- end -%>
      <%- if directory['allow'] and ! [ false, 'false', '' ].include?(directory['allow']) -%>
        <%- if directory['allow'].kind_of?(Array) -%>
          <%- Array(directory['allow']).each do |access| -%>
    Allow <%=  access %>
        <%- end -%>
      <%- else -%>
    Allow <%= directory['allow'] %>
      <%- end -%>
      <%- elsif [ 'from all', 'from All' ].include?(directory['deny']) -%>
      <%- elsif ! directory['deny'] and [ false, 'false', '' ].include?(directory['allow']) -%>
    Deny from all
      <%- else -%>
    Allow from all
      <%- end -%>
      <%- if directory['satisfy'] and directory['satisfy'] != '' -%>
    Satisfy <%= directory['satisfy'] %>
      <%- end -%>
    <%- end -%>
    <%- if directory['addhandlers'] and ! directory['addhandlers'].empty? -%>
      <%- [directory['addhandlers']].flatten.compact.each do |addhandler| -%>
    AddHandler <%= addhandler['handler'] %> <%= Array(addhandler['extensions']).join(' ') %>
      <%- end -%>
    <%- end -%>
    <%- if directory['sethandler'] and directory['sethandler'] != '' -%>
    SetHandler <%= directory['sethandler'] %>
    <%- end -%>
    <%- if directory['passenger_enabled'] and directory['passenger_enabled'] != '' -%>
    PassengerEnabled <%= directory['passenger_enabled'] %>
    <%- end -%>
    <%- if directory['php_admin_flags'] and ! directory['php_admin_flags'].empty? -%>
      <%- directory['php_admin_flags'].each do |flag,value| -%>
      <%- value = if value =~ /true|yes|on|1/i then 'on' else 'off' end -%>
    php_admin_flag <%= "#{flag} #{value}" %>
      <%- end -%>
    <%- end -%>
    <%- if directory['php_admin_values'] and ! directory['php_admin_values'].empty? -%>
      <%- directory['php_admin_values'].each do |key,value| -%>
    php_admin_value <%= "#{key} #{value}" %>
      <%- end -%>
    <%- end -%>
    <%- if directory['directoryindex'] and directory['directoryindex'] != '' -%>
    DirectoryIndex <%= directory['directoryindex'] %>
    <%- end -%>
    <%- if directory['error_documents'] and ! directory['error_documents'].empty? -%>
      <%- [directory['error_documents']].flatten.compact.each do |error_document| -%>
    ErrorDocument <%= error_document['error_code'] %> <%= error_document['document'] %>
      <%- end -%>
    <%- end -%>
    <%- if directory['auth_type'] -%>
    AuthType <%= directory['auth_type'] %>
    <%- end -%>
    <%- if directory['auth_name'] -%>
    AuthName "<%= directory['auth_name'] %>"
    <%- end -%>
    <%- if directory['auth_digest_algorithm'] -%>
    AuthDigestAlgorithm <%= directory['auth_digest_algorithm'] %>
    <%- end -%>
    <%- if directory['auth_digest_domain'] -%>
    AuthDigestDomain <%= Array(directory['auth_digest_domain']).join(' ') %>
    <%- end -%>
    <%- if directory['auth_digest_nonce_lifetime'] -%>
    AuthDigestNonceLifetime <%= directory['auth_digest_nonce_lifetime'] %>
    <%- end -%>
    <%- if directory['auth_digest_provider'] -%>
    AuthDigestProvider <%= directory['auth_digest_provider'] %>
    <%- end -%>
    <%- if directory['auth_digest_qop'] -%>
    AuthDigestQop <%= directory['auth_digest_qop'] %>
    <%- end -%>
    <%- if directory['auth_digest_shmem_size'] -%>
    AuthDigestShmemSize <%= directory['auth_digest_shmem_size'] %>
    <%- end -%>
    <%- if directory['auth_basic_authoritative'] -%>
    AuthBasicAuthoritative <%= directory['auth_basic_authoritative'] %>
    <%- end -%>
    <%- if directory['auth_basic_fake'] -%>
    AuthBasicFake <%= directory['auth_basic_fake'] %>
    <%- end -%>
    <%- if directory['auth_basic_provider'] -%>
    AuthBasicProvider <%= directory['auth_basic_provider'] %>
    <%- end -%>
    <%- if directory['auth_user_file'] -%>
    AuthUserFile <%= directory['auth_user_file'] %>
    <%- end -%>
    <%- if directory['auth_group_file'] -%>
    AuthGroupFile <%= directory['auth_group_file'] %>
    <%- end -%>
    <%- if directory['auth_require'] -%>
    Require <%= directory['auth_require'] %>
    <%- end -%>
    <%- if directory['fallbackresource'] -%>
    FallbackResource <%= directory['fallbackresource'] %>
    <%- end -%>
    <%- if directory['expires_active'] -%>
    ExpiresActive <%= directory['expires_active'] %>
    <%- end -%>
    <%- if directory['expires_default'] -%>
    ExpiresDefault <%= directory['expires_default'] %>
    <%- end -%>
    <%- if directory['expires_by_type'] -%>
    <%- Array(directory['expires_by_type']).each do |rule| -%>
    ExpiresByType <%= rule %>
    <%- end -%>
    <%- end -%>
    <%- if directory['force_type'] -%>
    ForceType <%= directory['force_type'] %>
    <%- end -%>
    <%- if directory['ssl_options'] -%>
    SSLOptions <%= Array(directory['ssl_options']).join(' ') %>
    <%- end -%>
    <%- if directory['suphp'] and @suphp_engine == 'on' -%>
    suPHP_UserGroup <%= directory['suphp']['user'] %> <%= directory['suphp']['group'] %>
    <%- end -%>
    <%- if directory['fcgiwrapper'] -%>
    FcgidWrapper <%= directory['fcgiwrapper']['command'] %> <%= directory['fcgiwrapper']['suffix'] %> <%= directory['fcgiwrapper']['virtual'] %>
    <%- end -%>
    <%- if directory['custom_fragment'] -%>
    <%= directory['custom_fragment'] %>
    <%- end -%>
  </<%= provider %>>
    <%- end -%>
  <%- end -%>
<% end -%>
<% if @error_documents and ! @error_documents.empty? -%>
  <%- [@error_documents].flatten.compact.each do |error_document| -%>
    <%- if error_document["error_code"] != '' and error_document["document"] != '' -%>
  ErrorDocument <%= error_document["error_code"] %> <%= error_document["document"] %>
    <%- end -%>
  <%- end -%>
<% end -%>
<% if @fastcgi_server -%>

  FastCgiExternalServer <%= @fastcgi_server %> -socket <%= @fastcgi_socket %>
<% end -%>
<% if @fastcgi_dir -%>

  <Directory "<%= @fastcgi_dir %>">
    Options +ExecCGI
    AllowOverride All
    SetHandler fastcgi-script
  <%- if scope.function_versioncmp([@apache_version, '2.4']) >= 0 -%>
    Require all granted
  <%- else -%>
    Order allow,deny
    Allow From All
  <%- end -%>
    AuthBasicAuthoritative Off
  </Directory>

  AllowEncodedSlashes On
  ServerSignature Off
<% end -%>
<% if @headers and ! @headers.empty? -%>

  ## Header rules
  ## as per http://httpd.apache.org/docs/2.2/mod/mod_headers.html#header
  <%- Array(@headers).each do |header_statement| -%>
    <%- if header_statement != '' -%>
  Header <%= header_statement %>
    <%- end -%>
  <%- end -%>
<% end -%>
<% if @itk and ! @itk.empty? -%>
  ## ITK statement
  <IfModule mpm_itk_module>
     <%- if @itk["user"] and @itk["group"] -%>
     AssignUserId <%= @itk["user"] %> <%= @itk["group"] %>
     <%- end -%>
     <%- if @itk["assignuseridexpr"] -%>
     AssignUserIdExpr <%= @itk["assignuseridexpr"] %>
     <%- end -%>
     <%- if @itk["assigngroupidexpr"] -%>
     AssignGroupIdExpr <%= @itk["assigngroupidexpr"] %>
     <%- end -%>
     <%- if @itk["maxclientvhost"] -%>
     MaxClientsVHost <%= @itk["maxclientvhost"] %>
     <%- end -%>
     <%- if @itk["nice"] -%>
     NiceValue <%= @itk["nice"] %>
     <%- end -%>
     <%- if @kernelversion >= '3.5.0' -%>
       <%- if @itk["limituidrange"] -%>
     LimitUIDRange <%= @itk["limituidrange"] %>
       <%- end -%>
       <%- if @itk["limitgidrange"] -%>
     LimitGIDRange <%= @itk["limitgidrange"] %>
       <%- end -%>
     <%- end -%>
  </IfModule>
<% end -%>
<% if @php_admin_values and not @php_admin_values.empty? -%>
<% @php_admin_values.each do |key,value| -%>
  php_admin_value <%= key %> <%= value %>
<% end -%>
<% end -%>
<% if @php_admin_flags and not @php_admin_flags.empty? -%>
<% @php_admin_flags.each do |key,flag| -%>
<%# normalize flag -%>
<% if flag =~ /true|yes|on|1/i then flag = 'on' else flag = 'off' end -%>
  php_admin_flag <%= key %> <%= flag %>
<% end -%>
<% end -%>
<% if @proxy_dest or @proxy_pass -%>

  ## Proxy rules
  ProxyRequests Off
<%- end -%>
<% if @proxy_preserve_host %>
  ProxyPreserveHost On
<%- end -%>
<%- [@proxy_pass].flatten.compact.each do |proxy| -%>
  ProxyPass <%= proxy['path'] %> <%= proxy['url'] %>
  <Location <%= proxy['path']%>>
    ProxyPassReverse <%= proxy['url'] %>
  </Location>
<% end %>
<% if @proxy_dest -%>
<%- Array(@no_proxy_uris).each do |uri| -%>
  ProxyPass        <%= uri %> !
<% end %>
  ProxyPass          / <%= @proxy_dest %>/
  <Location          />
    ProxyPassReverse <%= @proxy_dest %>/
  </Location>
<% end -%>
<% if @rack_base_uris -%>

  ## Enable rack
<% Array(@rack_base_uris).each do |uri| -%>
  RackBaseURI <%= uri %>
<% end -%>
<% end -%>
<% if @redirect_source and @redirect_dest -%>
<% @redirect_dest_a   = Array(@redirect_dest) -%>
<% @redirect_source_a = Array(@redirect_source) -%>
<% @redirect_status_a = Array(@redirect_status) -%>

  ## Redirect rules
<% @redirect_source_a.each_with_index do |source, i| -%>
<% @redirect_dest_a[i] ||= @redirect_dest_a[0] -%>
<% @redirect_status_a[i] ||= @redirect_status_a[0] -%>
  Redirect <%= "#{@redirect_status_a[i]} " %><%= source %> <%= @redirect_dest_a[i] %>
<% end -%>
<% end -%>

<%- if @redirectmatch_status and @redirectmatch_regexp -%>
<% @redirectmatch_status_a = Array(@redirectmatch_status) -%>
<% @redirectmatch_regexp_a = Array(@redirectmatch_regexp) -%>

  ## RedirectMatch rules
<% @redirectmatch_status_a.each_with_index do |status, i| -%>
<% @redirectmatch_status_a[i] ||= @redirectmatch_status_a[0] -%>
<% @redirectmatch_regexp_a[i] ||= @redirectmatch_regexp_a[0] -%>
  RedirectMatch <%= "#{@redirectmatch_status_a[i]} " %> <%= @redirectmatch_regexp_a[i] %>
<% end -%>
<% end -%>
<% if @request_headers and ! @request_headers.empty? -%>

  ## Request header rules
  ## as per http://httpd.apache.org/docs/2.2/mod/mod_headers.html#requestheader
  <%- Array(@request_headers).each do |request_statement| -%>
    <%- if request_statement != '' -%>
  RequestHeader <%= request_statement %>
    <%- end -%>
  <%- end -%>
<% end -%>
<%- if @rewrites -%>
  ## Rewrite rules
  RewriteEngine On
  <%- if @rewrite_base -%>
  RewriteBase <%= @rewrite_base %>
  <%- end -%>

  <%- [@rewrites].flatten.compact.each do |rewrite_details| -%>
    <%- if rewrite_details['comment'] -%>
  #<%= rewrite_details['comment'] %>
    <%- end -%>
    <%- if rewrite_details['rewrite_base'] -%>
  RewriteBase <%= rewrite_details['rewrite_base'] %>
    <%- end -%>
    <%- if rewrite_details['rewrite_cond'] -%>
      <%- Array(rewrite_details['rewrite_cond']).each do |commands| -%>
        <%- Array(commands).each do |command| -%>
  RewriteCond <%= command %>
        <%- end -%>
      <%- end -%>
    <%- end -%>
    <%- Array(rewrite_details['rewrite_rule']).each do |commands| -%>
      <%- Array(commands).each do |command| -%>
  RewriteRule <%= command %>
      <%- end -%>

    <%- end -%>
  <%- end -%>
<%- end -%>
<%# reverse compatibility %>
<% if @rewrite_rule and !@rewrites -%>
  ## Rewrite rules
  RewriteEngine On
<% if @rewrite_base -%>
  RewriteBase <%= @rewrite_base %>
<% end -%>
<% if @rewrite_cond -%>
<% Array(@rewrite_cond).each do |cond| -%>
  RewriteCond <%= cond %>
<% end -%>
<% end -%>
  RewriteRule <%= @rewrite_rule %>
<%- end -%>
<%- if @scriptaliases.is_a?(Array) -%>
<%-  aliases = @scriptaliases -%>
<%- elsif @scriptaliases.is_a?(Hash) -%>
<%-  aliases = [@scriptaliases] -%>
<%- else -%>
<%-  # Nothing to do with any other data type -%>
<%-  aliases = [] -%>
<%- end -%>
<%- if @scriptalias or !aliases.empty? -%>
  ## Script alias directives
<%# Combine scriptalais and scriptaliases into a single data structure -%>
<%# for backward compatibility and ease of implementation -%>
<%- aliases << { 'alias' => '/cgi-bin', 'path' => @scriptalias } if @scriptalias -%>
<%- aliases.flatten.compact! -%>
<%- aliases.each do |salias| -%>
  <%- if salias["path"] != '' -%>
    <%- if salias["alias"] and salias["alias"] != '' -%>
  ScriptAlias <%= salias['alias'] %> "<%= salias['path'] %>"
    <%- elsif salias["aliasmatch"] and salias["aliasmatch"] != '' -%>
  ScriptAliasMatch <%= salias['aliasmatch'] %> "<%= salias['path'] %>"
    <%- end -%>
  <%- end -%>
<%- end -%>
<%- end -%>
<% if @serveraliases and ! @serveraliases.empty? -%>

  ## Server aliases
<% Array(@serveraliases).each do |serveralias| -%>
  ServerAlias <%= serveralias %>
<% end -%>
<% end -%>
<% if @setenv and ! @setenv.empty? -%>

  ## SetEnv/SetEnvIf for environment variables
<% Array(@setenv).each do |envvar| -%>
  SetEnv <%= envvar %>
<% end -%>
<% end -%>
<% if @setenvif and ! @setenvif.empty? -%>
<% Array(@setenvif).each do |envifvar| -%>
  SetEnvIf <%= envifvar %>
<% end -%>
<% end -%>
<% if @ssl -%>

  ## SSL directives
  SSLEngine on
  SSLCertificateFile      "<%= @ssl_cert %>"
  SSLCertificateKeyFile   "<%= @ssl_key %>"
<% if @ssl_chain -%>
  SSLCertificateChainFile "<%= @ssl_chain %>"
<% end -%>
<% if @ssl_certs_dir -%>
  SSLCACertificatePath    "<%= @ssl_certs_dir %>"
<% end -%>
<% if @ssl_ca -%>
  SSLCACertificateFile    "<%= @ssl_ca %>"
<% end -%>
<% if @ssl_crl_path -%>
  SSLCARevocationPath     "<%= @ssl_crl_path %>"
<% end -%>
<% if @ssl_crl -%>
  SSLCARevocationFile     "<%= @ssl_crl %>"
<% end -%>
<% if @ssl_proxyengine -%>
  SSLProxyEngine On
<% end -%>
<% if @ssl_protocol -%>
  SSLProtocol             <%= @ssl_protocol %>
<% end -%>
<% if @ssl_cipher -%>
  SSLCipherSuite          <%= @ssl_cipher %>
<% end -%>
<% if @ssl_honorcipherorder -%>
  SSLHonorCipherOrder     <%= @ssl_honorcipherorder %>
<% end -%>
<% if @ssl_verify_client -%>
  SSLVerifyClient         <%= @ssl_verify_client %>
<% end -%>
<% if @ssl_verify_depth -%>
  SSLVerifyDepth          <%= @ssl_verify_depth %>
<% end -%>
<% if @ssl_options -%>
  SSLOptions <%= Array(@ssl_options).join(' ') %>
<% end -%>
<% end -%>
<% if @suexec_user_group -%>

  SuexecUserGroup <%= @suexec_user_group %>
<% end -%>
<% if @suphp_engine == 'on' -%>
<% if @suphp_addhandler -%>
  suPHP_AddHandler <%= @suphp_addhandler %>
<% end -%>
<% if @suphp_engine -%>
  suPHP_Engine <%= @suphp_engine %>
<% end -%>
<% if @suphp_configpath -%>
  suPHP_ConfigPath "<%= @suphp_configpath %>"
<% end -%>
<% end -%>
<% if @wsgi_application_group -%>
  WSGIApplicationGroup <%= @wsgi_application_group %>
<% end -%>
<% if @wsgi_daemon_process and @wsgi_daemon_process_options -%>
  WSGIDaemonProcess <%= @wsgi_daemon_process %> <%= @wsgi_daemon_process_options.collect { |k,v| "#{k}=#{v}"}.sort.join(' ') %>
<% elsif @wsgi_daemon_process and !@wsgi_daemon_process_options -%>
  WSGIDaemonProcess <%= @wsgi_daemon_process %>
<% end -%>
<% if @wsgi_import_script and @wsgi_import_script_options -%>
  WSGIImportScript <%= @wsgi_import_script %> <%= @wsgi_import_script_options.collect { |k,v| "#{k}=#{v}"}.sort.join(' ') %>
<% end -%>
<% if @wsgi_process_group -%>
  WSGIProcessGroup <%= @wsgi_process_group %>
<% end -%>
<% if @wsgi_script_aliases and ! @wsgi_script_aliases.empty? -%>
  <%- @wsgi_script_aliases.each do |a, p| -%>
    <%- if a != '' and p != ''-%>
  WSGIScriptAlias <%= a %> "<%= p %>"
    <%- end -%>
  <%- end -%>
<% end -%>
<% if @wsgi_pass_authorization -%>
  WSGIPassAuthorization <%= @wsgi_pass_authorization %>
<% end -%>
include apache
include apache::mod::php
include apache::mod::cgi
include apache::mod::userdir
include apache::mod::disk_cache
include apache::mod::proxy_http
include apache::dev
include apache
# Tests the path and identifier parameters for the apache::mod class

# Base class for clarity:
class { 'apache': }


# Exaple parameter usage:
apache::mod { 'testmod':
  path => '/usr/some/path/mod_testmod.so',
  id   => 'testmod_custom_name',
}
## Default mods

# Base class. Declares default vhost on port 80 and default ssl
# vhost on port 443 listening on all interfaces and serving
# $apache::docroot, and declaring our default set of modules.
class { 'apache':
  default_mods => true,
}

## custom mods

# Base class. Declares default vhost on port 80 and default ssl
# vhost on port 443 listening on all interfaces and serving
# $apache::docroot, and declaring a custom set of modules.
class { 'apache':
  default_mods => [
    'info',
    'alias',
    'mime',
    'env',
    'setenv',
    'expires',
  ],
}

class { 'apache':
  mpm_module => 'prefork',
}
include apache::mod::php
## Default vhosts, and custom vhosts
# NB: Please see the other vhost_*.pp example files for further
# examples.

# Base class. Declares default vhost on port 80 and default ssl
# vhost on port 443 listening on all interfaces and serving
# $apache::docroot
class { 'apache': }

# Most basic vhost
apache::vhost { 'first.example.com':
  port    => '80',
  docroot => '/var/www/first',
}

# Vhost with different docroot owner/group/mode
apache::vhost { 'second.example.com':
  port          => '80',
  docroot       => '/var/www/second',
  docroot_owner => 'third',
  docroot_group => 'third',
  docroot_mode  => '0770',
}

# Vhost with serveradmin
apache::vhost { 'third.example.com':
  port        => '80',
  docroot     => '/var/www/third',
  serveradmin => 'admin@example.com',
}

# Vhost with ssl (uses default ssl certs)
apache::vhost { 'ssl.example.com':
  port    => '443',
  docroot => '/var/www/ssl',
  ssl     => true,
}

# Vhost with ssl and specific ssl certs
apache::vhost { 'fourth.example.com':
  port     => '443',
  docroot  => '/var/www/fourth',
  ssl      => true,
  ssl_cert => '/etc/ssl/fourth.example.com.cert',
  ssl_key  => '/etc/ssl/fourth.example.com.key',
}

# Vhost with english title and servername parameter
apache::vhost { 'The fifth vhost':
  servername => 'fifth.example.com',
  port       => '80',
  docroot    => '/var/www/fifth',
}

# Vhost with server aliases
apache::vhost { 'sixth.example.com':
  serveraliases => [
    'sixth.example.org',
    'sixth.example.net',
  ],
  port          => '80',
  docroot       => '/var/www/fifth',
}

# Vhost with alternate options
apache::vhost { 'seventh.example.com':
  port    => '80',
  docroot => '/var/www/seventh',
  options => [
    'Indexes',
    'MultiViews',
  ],
}

# Vhost with AllowOverride for .htaccess
apache::vhost { 'eighth.example.com':
  port     => '80',
  docroot  => '/var/www/eighth',
  override => 'All',
}

# Vhost with access and error logs disabled
apache::vhost { 'ninth.example.com':
  port       => '80',
  docroot    => '/var/www/ninth',
  access_log => false,
  error_log  => false,
}

# Vhost with custom access and error logs and logroot
apache::vhost { 'tenth.example.com':
  port            => '80',
  docroot         => '/var/www/tenth',
  access_log_file => 'tenth_vhost.log',
  error_log_file  => 'tenth_vhost_error.log',
  logroot         => '/var/log',
}

# Vhost with a cgi-bin
apache::vhost { 'eleventh.example.com':
  port        => '80',
  docroot     => '/var/www/eleventh',
  scriptalias => '/usr/lib/cgi-bin',
}

# Vhost with a proxypass configuration
apache::vhost { 'twelfth.example.com':
  port          => '80',
  docroot       => '/var/www/twelfth',
  proxy_dest    => 'http://internal.example.com:8080/twelfth',
  no_proxy_uris => ['/login','/logout'],
}

# Vhost to redirect /login and /logout
apache::vhost { 'thirteenth.example.com':
  port            => '80',
  docroot         => '/var/www/thirteenth',
  redirect_source => [
    '/login',
    '/logout',
  ],
  redirect_dest   => [
    'http://10.0.0.10/login',
    'http://10.0.0.10/logout',
  ],
}

# Vhost to permamently redirect
apache::vhost { 'fourteenth.example.com':
  port            => '80',
  docroot         => '/var/www/fourteenth',
  redirect_source => '/blog',
  redirect_dest   => 'http://blog.example.com',
  redirect_status => 'permanent',
}

# Vhost with a rack configuration
apache::vhost { 'fifteenth.example.com':
  port           => '80',
  docroot        => '/var/www/fifteenth',
  rack_base_uris => ['/rackapp1', '/rackapp2'],
}

# Vhost to redirect non-ssl to ssl
apache::vhost { 'sixteenth.example.com non-ssl':
  servername   => 'sixteenth.example.com',
  port         => '80',
  docroot      => '/var/www/sixteenth',
  rewrites     => [
    {
      comment       => 'redirect non-SSL traffic to SSL site',
      rewrite_cond  => ['%{HTTPS} off'],
      rewrite_rule  => ['(.*) https://%{HTTPS_HOST}%{REQUEST_URI}'],
    }
  ]
}
apache::vhost { 'sixteenth.example.com ssl':
  servername => 'sixteenth.example.com',
  port       => '443',
  docroot    => '/var/www/sixteenth',
  ssl        => true,
}

# Vhost to redirect non-ssl to ssl using old rewrite method
apache::vhost { 'sixteenth.example.com non-ssl old rewrite':
  servername   => 'sixteenth.example.com',
  port         => '80',
  docroot      => '/var/www/sixteenth',
  rewrite_cond => '%{HTTPS} off',
  rewrite_rule => '(.*) https://%{HTTPS_HOST}%{REQUEST_URI}',
}
apache::vhost { 'sixteenth.example.com ssl old rewrite':
  servername => 'sixteenth.example.com',
  port       => '443',
  docroot    => '/var/www/sixteenth',
  ssl        => true,
}

# Vhost to block repository files
apache::vhost { 'seventeenth.example.com':
  port    => '80',
  docroot => '/var/www/seventeenth',
  block   => 'scm',
}

# Vhost with special environment variables
apache::vhost { 'eighteenth.example.com':
  port    => '80',
  docroot => '/var/www/eighteenth',
  setenv  => ['SPECIAL_PATH /foo/bin','KILROY was_here'],
}

apache::vhost { 'nineteenth.example.com':
  port     => '80',
  docroot  => '/var/www/nineteenth',
  setenvif => 'Host "^([^\.]*)\.website\.com$" CLIENT_NAME=$1',
}

# Vhost with additional include files
apache::vhost { 'twentyieth.example.com':
  port                => '80',
  docroot             => '/var/www/twelfth',
  additional_includes => ['/tmp/proxy_group_a','/tmp/proxy_group_b'],
}

# Vhost with alias for subdomain mapped to same named directory
# http://example.com.loc => /var/www/example.com
apache::vhost { 'subdomain.loc':
  vhost_name      => '*',
  port            => '80',
  virtual_docroot => '/var/www/%-2+',
  docroot         => '/var/www',
  serveraliases   => ['*.loc',],
}

# Vhost with SSLProtocol,SSLCipherSuite, SSLHonorCipherOrder
apache::vhost { 'securedomain.com':
        priority              => '10',
        vhost_name            => 'www.securedomain.com',
        port                  => '443',
        docroot               => '/var/www/secure',
        ssl                   => true,
        ssl_cert              => '/etc/ssl/securedomain.cert',
        ssl_key               => '/etc/ssl/securedomain.key',
        ssl_chain             => '/etc/ssl/securedomain.crt',
        ssl_protocol          => '-ALL +SSLv3 +TLSv1',
        ssl_cipher            => 'ALL:!aNULL:!ADH:!eNULL:!LOW:!EXP:RC4+RSA:+HIGH:+MEDIUM',
        ssl_honorcipherorder  => 'On',
        add_listen            => false,
}

# Vhost with access log environment variables writing control
apache::vhost { 'twentyfirst.example.com':
  port               => '80',
  docroot            => '/var/www/twentyfirst',
  access_log_env_var => 'admin',
}

# Base class. Declares default vhost on port 80 and default ssl
# vhost on port 443 listening on all interfaces and serving
# $apache::docroot
class { 'apache': }

# Example from README adapted.
apache::vhost { 'readme.example.net':
  docroot     => '/var/www/readme',
  directories => [
    {
      'path'         => '/var/www/readme',
      'ServerTokens' => 'prod' ,
    },
    {
      'path'  => '/usr/share/empty',
      'allow' => 'from all',
    },
  ],
}

# location test
apache::vhost { 'location.example.net':
  docroot     => '/var/www/location',
  directories => [
    {
      'path'         => '/location',
      'provider'     => 'location',
      'ServerTokens' => 'prod'
    },
  ],
}

# files test, curedly disable access to accidental backup files.
apache::vhost { 'files.example.net':
  docroot     => '/var/www/files',
  directories => [
    {
      'path'     => '(\.swp|\.bak|~)$',
      'provider' => 'filesmatch',
      'deny'     => 'from all'
    },
  ],
}

## IP-based vhosts on any listen port
# IP-based vhosts respond to requests on specific IP addresses.

# Base class. Turn off the default vhosts; we will be declaring
# all vhosts below.
class { 'apache':
  default_vhost => false,
}

# Listen on port 80 and 81; required because the following vhosts
# are not declared with a port parameter.
apache::listen { '80': }
apache::listen { '81': }

# IP-based vhosts
apache::vhost { 'first.example.com':
  ip       => '10.0.0.10',
  docroot  => '/var/www/first',
  ip_based => true,
}
apache::vhost { 'second.example.com':
  ip       => '10.0.0.11',
  docroot  => '/var/www/second',
  ip_based => true,
}
## SSL-enabled vhosts
# SSL-enabled vhosts respond only to HTTPS queries.

# Base class. Turn off the default vhosts; we will be declaring
# all vhosts below.
class { 'apache':
  default_vhost => false,
}

# Non-ssl vhost
apache::vhost { 'first.example.com non-ssl':
  servername => 'first.example.com',
  port       => '80',
  docroot    => '/var/www/first',
}

# SSL vhost at the same domain
apache::vhost { 'first.example.com ssl':
  servername => 'first.example.com',
  port       => '443',
  docroot    => '/var/www/first',
  ssl        => true,
}
## Declare ip-based and name-based vhosts
# Mixing Name-based vhost with IP-specific vhosts requires `add_listen =>
# 'false'` on the non-IP vhosts

# Base class. Turn off the default vhosts; we will be declaring
# all vhosts below.
class { 'apache':
  default_vhost => false,
}


# Add two an IP-based vhost on 10.0.0.10, ssl and non-ssl
apache::vhost { 'The first IP-based vhost, non-ssl':
  servername => 'first.example.com',
  ip         => '10.0.0.10',
  port       => '80',
  ip_based   => true,
  docroot    => '/var/www/first',
}
apache::vhost { 'The first IP-based vhost, ssl':
  servername => 'first.example.com',
  ip         => '10.0.0.10',
  port       => '443',
  ip_based   => true,
  docroot    => '/var/www/first-ssl',
  ssl        => true,
}

# Two name-based vhost listening on 10.0.0.20
apache::vhost { 'second.example.com':
  ip      => '10.0.0.20',
  port    => '80',
  docroot => '/var/www/second',
}
apache::vhost { 'third.example.com':
  ip      => '10.0.0.20',
  port    => '80',
  docroot => '/var/www/third',
}

# Two name-based vhosts without IPs specified, so that they will answer on either 10.0.0.10 or 10.0.0.20 . It is requried to declare
# `add_listen => 'false'` to disable declaring "Listen 80" which will conflict
# with the IP-based preceeding vhosts.
apache::vhost { 'fourth.example.com':
  port       => '80',
  docroot    => '/var/www/fourth',
  add_listen => false,
}
apache::vhost { 'fifth.example.com':
  port       => '80',
  docroot    => '/var/www/fifth',
  add_listen => false,
}
fixtures:
  repositories:
    "stdlib":
      "repo": "git://github.com/puppetlabs/puppetlabs-stdlib.git"
      "ref": "v2.2.1"
  symlinks:
    "apt": "#{source_dir}"
branches:
  only:
    - master
language: ruby
bundler_args: --without development
script: bundle exec rake spec SPEC_OPTS='--format documentation'
after_success:
  - git clone -q git://github.com/puppetlabs/ghpublisher.git .forge-release
  - .forge-release/publish
rvm:
  - 1.8.7
  - 1.9.3
  - 2.0.0
env:
  matrix:
    - PUPPET_GEM_VERSION="~> 2.7.0"
    - PUPPET_GEM_VERSION="~> 3.0.0"
    - PUPPET_GEM_VERSION="~> 3.1.0"
    - PUPPET_GEM_VERSION="~> 3.2.0"
  global:
  - PUBLISHER_LOGIN=puppetlabs
  - secure: |-
      ipB/CV1rVSTXU9ZDuzrFOlzJrRmJob36tKns2xszuH4r9s5P9qivNAngRGdV
      msb69xvOlzQykM0WRF+4kJ6TZ7AbMiDI+VZ8GDtsRaU5/q3BpsvFe8aato+6
      QeyFtBG62OsosTEhGws4mqiFsPDu3dHlakuJc9zevlTuhNwbKSs=
matrix:
  fast_finish: true
  exclude:
    - rvm: 1.9.3
      env: PUPPET_GEM_VERSION="~> 2.7.0"
    - rvm: 2.0.0
      env: PUPPET_GEM_VERSION="~> 2.7.0"
    - rvm: 2.0.0
      env: PUPPET_GEM_VERSION="~> 3.0.0"
    - rvm: 2.0.0
      env: PUPPET_GEM_VERSION="~> 3.1.0"
    - rvm: 1.8.7
      env: PUPPET_GEM_VERSION="~> 3.2.0"
notifications:
  email: false
##2014-03-04 - Supported Release 1.4.2
###Summary

This is a supported release. This release tidies up 1.4.1 and re-enables
support for Ubuntu 10.04

####Features

####Bugfixes
- Fix apt:ppa to include the -y Ubuntu 10.04 requires.
- Documentation changes.
- Test fixups.

####Known Bugs

* No known issues.



##2014-02-13 1.4.1
###Summary
This is a bugfix release.

####Bugfixes
- Fix apt::force unable to upgrade packages from releases other than its original
- Removed a few refeneces to aptitude instead of apt-get for portability
- Removed call to getparam() due to stdlib dependency
- Correct apt::source template when architecture is provided
- Retry package installs if apt is locked
- Use root to exec in apt::ppa
- Updated tests and converted acceptance tests to beaker

##2013-10-08 - Release 1.4.0

###Summary

Minor bugfix and allow the timeout to be adjusted.

####Features
- Add an `updates_timeout` to apt::params

####Bugfixes
- Ensure apt::ppa can read a ppa removed by hand.


##2013-10-08 - Release 1.3.0
###Summary

This major feature in this release is the new apt::unattended_upgrades class,
allowing you to handle Ubuntu's unattended feature.  This allows you to select
specific packages to automatically upgrade without any further user
involvement.

In addition we extend our Wheezy support, add proxy support to apt:ppa and do
various cleanups and tweaks.

####Features
- Add apt::unattended_upgrades support for Ubuntu.
- Add wheezy backports support.
- Use the geoDNS http.debian.net instead of the main debian ftp server.
- Add `options` parameter to apt::ppa in order to pass options to apt-add-repository command.
- Add proxy support for apt::ppa (uses proxy_host and proxy_port from apt).

####Bugfixes
- Fix regsubst() calls to quote single letters (for future parser).
- Fix lint warnings and other misc cleanup.


##2013-07-03 - Release 1.2.0

####Features
- Add geppetto `.project` natures
- Add GH auto-release
- Add `apt::key::key_options` parameter
- Add complex pin support using distribution properties for `apt::pin` via new properties:
  - `apt::pin::codename`
  - `apt::pin::release_version`
  - `apt::pin::component`
  - `apt::pin::originator`
  - `apt::pin::label`
- Add source architecture support to `apt::source::architecture`

####Bugfixes
- Use apt-get instead of aptitude in apt::force
- Update default backports location
- Add dependency for required packages before apt-get update


##2013-06-02 - Release 1.1.1
###Summary

This is a bug fix release that resolves a number of issues:

* By changing template variable usage, we remove the deprecation warnings
  for Puppet 3.2.x
* Fixed proxy file removal, when proxy absent

Some documentation, style and whitespaces changes were also merged. This
release also introduced proper rspec-puppet unit testing on Travis-CI to help
reduce regression.

Thanks to all the community contributors below that made this patch possible.

#### Detail Changes

* fix minor comment type (Chris Rutter)
* whitespace fixes (Michael Moll)
* Update travis config file (William Van Hevelingen)
* Build all branches on travis (William Van Hevelingen)
* Standardize travis.yml on pattern introduced in stdlib (William Van Hevelingen)
* Updated content to conform to README best practices template (Lauren Rother)
* Fix apt::release example in readme (Brian Galey)
* add @ to variables in template (Peter Hoeg)
* Remove deprecation warnings for pin.pref.erb as well (Ken Barber)
* Update travis.yml to latest versions of puppet (Ken Barber)
* Fix proxy file removal (Scott Barber)
* Add spec test for removing proxy configuration (Dean Reilly)
* Fix apt::key listing longer than 8 chars (Benjamin Knofe)




## Release 1.1.0
###Summary

This release includes Ubuntu 12.10 (Quantal) support for PPAs.


##2012-05-25 - Puppet Labs <info@puppetlabs.com> - Release 0.0.4
###Summary

 * Fix ppa list filename when there is a period in the PPA name
 * Add .pref extension to apt preferences files
 * Allow preferences to be purged
 * Extend pin support


##2012-05-04 - Puppet Labs <info@puppetlabs.com> - Release 0.0.3
###Summary
 
 * only invoke apt-get update once
 * only install python-software-properties if a ppa is added
 * support 'ensure => absent' for all defined types
 * add apt::conf
 * add apt::backports
 * fixed Modulefile for module tool dependency resolution
 * configure proxy before doing apt-get update
 * use apt-get update instead of aptitude for apt::ppa
 * add support to pin release


##2012-03-26 - Puppet Labs <info@puppetlabs.com> - Release 0.0.2
###Summary

* 41cedbb (#13261) Add real examples to smoke tests.
* d159a78 (#13261) Add key.pp smoke test
* 7116c7a (#13261) Replace foo source with puppetlabs source
* 1ead0bf Ignore pkg directory.
* 9c13872 (#13289) Fix some more style violations
* 0ea4ffa (#13289) Change test scaffolding to use a module & manifest dir fixture path
* a758247 (#13289) Clean up style violations and fix corresponding tests
* 99c3fd3 (#13289) Add puppet lint tests to Rakefile
* 5148cbf (#13125) Apt keys should be case insensitive
* b9607a4 Convert apt::key to use anchors


##2012-03-07 - Puppet Labs <info@puppetlabs.com> - Release 0.0.1
###Summary

* d4fec56 Modify apt::source release parameter test
* 1132a07 (#12917) Add contributors to README
* 8cdaf85 (#12823) Add apt::key defined type and modify apt::source to use it
* 7c0d10b (#12809) $release should use $lsbdistcodename and fall back to manual input
* be2cc3e (#12522) Adjust spec test for splitting purge
* 7dc60ae (#12522) Split purge option to spare sources.list
* 9059c4e Fix source specs to test all key permutations
* 8acb202 Add test for python-software-properties package
* a4af11f Check if python-software-properties is defined before attempting to define it.
* 1dcbf3d Add tests for required_packages change
* f3735d2 Allow duplicate $required_packages
* 74c8371 (#12430) Add tests for changes to apt module
* 97ebb2d Test two sources with the same key
* 1160bcd (#12526) Add ability to reverse apt { disable_keys => true }
* 2842d73 Add Modulefile to puppet-apt
* c657742 Allow the use of the same key in multiple sources
* 8c27963 (#12522) Adding purge option to apt class
* 997c9fd (#12529) Add unit test for apt proxy settings
* 50f3cca (#12529) Add parameter to support setting a proxy for apt
* d522877 (#12094) Replace chained .with_* with a hash
* 8cf1bd0 (#12094) Remove deprecated spec.opts file
* 2d688f4 (#12094) Add rspec-puppet tests for apt
* 0fb5f78 (#12094) Replace name with path in file resources
* f759bc0 (#11953) Apt::force passes $version to aptitude
* f71db53 (#11413) Add spec test for apt::force to verify changes to unless
* 2f5d317 (#11413) Update dpkg query used by apt::force
* cf6caa1 (#10451) Add test coverage to apt::ppa
* 0dd697d include_src parameter in example; Whitespace cleanup
* b662eb8 fix typos in "repositories"
* 1be7457 Fix (#10451) - apt::ppa fails to "apt-get update" when new PPA source is added
* 864302a Set the pin priority before adding the source (Fix #10449)
* 1de4e0a Refactored as per mlitteken
* 1af9a13 Added some crazy bash madness to check if the ppa is installed already. Otherwise the manifest tries to add it on every run!
* 52ca73e (#8720) Replace Apt::Ppa with Apt::Builddep
* 5c05fa0 added builddep command.
* a11af50 added the ability to specify the content of a key
* c42db0f Fixes ppa test.
* 77d2b0d reformatted whitespace to match recommended style of 2 space indentation.
* 27ebdfc ignore swap files.
* 377d58a added smoke tests for module.
* 18f614b reformatted apt::ppa according to recommended style.
* d8a1e4e Created a params class to hold global data.
* 636ae85 Added two params for apt class
* 148fc73 Update LICENSE.
* ed2d19e Support ability to add more than one PPA
* 420d537 Add call to apt-update after add-apt-repository in apt::ppa
* 945be77 Add package definition for python-software-properties
* 71fc425 Abs paths for all commands
* 9d51cd1 Adding LICENSE
* 71796e3 Heading fix in README
* 87777d8 Typo in README
* f848bac First commit
source ENV['GEM_SOURCE'] || 'https://rubygems.org'

group :development, :test do
  gem 'rake',                    :require => false
  gem 'pry',                     :require => false
  gem 'rspec-puppet',            :require => false
  gem 'puppet-lint',             :require => false
  gem 'puppetlabs_spec_helper',  :require => false
  gem 'serverspec',              :require => false
  gem 'beaker',                  :require => false
  gem 'beaker-rspec',            :require => false
end

if puppetversion = ENV['PUPPET_GEM_VERSION']
  gem 'puppet', puppetversion, :require => false
else
  gem 'puppet', :require => false
end
Copyright (c) 2011 Evolving Web Inc.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.


Copyright 2014 Puppet Labs

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
name    'puppetlabs-apt'
version '1.4.2'
source  'https://github.com/puppetlabs/puppetlabs-apt'
author  'Evolving Web / Puppet Labs'
license 'Apache License 2.0'
summary 'Puppet Labs Apt Module'
description 'APT Module for Puppet'
project_page 'https://github.com/puppetlabs/puppetlabs-apt'

## Add dependencies, if any:
#dependency 'puppetlabs/stdlib', '2.x'
# The dependency should be written as above but librarian-puppet
# does not support the expression as the PMT does.
dependency 'puppetlabs/stdlib', '>= 2.2.1'
apt
===

[![Build Status](https://travis-ci.org/puppetlabs/puppetlabs-apt.png?branch=master)](https://travis-ci.org/puppetlabs/puppetlabs-apt)

## Description

Provides helpful definitions for dealing with Apt.

=======

Overview

The APT module provides a simple interface for managing APT source, key, and definitions with Puppet.

Module Description

APT automates obtaining and installing software packages on \*nix systems.

Setup

**What APT affects:**

* package/service/configuration files for APT
* your system's `sources.list` file and `sources.list.d` directory
    * NOTE: Setting the `purge_sources_list` and `purge_sources_list_d` parameters to 'true' will destroy any existing content that was not declared with Puppet. The default for these parameters is 'false'.
* system repositories
* authentication keys
* wget (optional)

### Beginning with APT

To begin using the APT module with default parameters, declare the class

    include apt

Puppet code that uses anything from the APT module requires that the core apt class be declared/\s\+$//e

Usage

Using the APT module consists predominantly in declaring classes that provide desired functionality and features.

### apt

`apt` provides a number of common resources and options that are shared by the various defined types in this module, so you MUST always include this class in your manifests.

The parameters for `apt` are not required in general and are predominantly for development environment use-cases.

    class { 'apt':
      always_apt_update    => false,
      disable_keys         => undef,
      proxy_host           => false,
      proxy_port           => '8080',
      purge_sources_list   => false,
      purge_sources_list_d => false,
      purge_preferences_d  => false,
      update_timeout       => undef
    }

Puppet will manage your system's `sources.list` file and `sources.list.d` directory but will do its best to respect existing content.

If you declare your apt class with `purge_sources_list` and `purge_sources_list_d` set to 'true', Puppet will unapologetically purge any existing content it finds that wasn't declared with Puppet.

### apt::builddep

Installs the build depends of a specified package.

    apt::builddep { 'glusterfs-server': }

### apt::force

Forces a package to be installed from a specific release.  This class is particularly useful when using repositories, like Debian, that are unstable in Ubuntu.

    apt::force { 'glusterfs-server':
      release => 'unstable',
      version => '3.0.3',
      require => Apt::Source['debian_unstable'],
    }

### apt::key

Adds a key to the list of keys used by APT to authenticate packages.

    apt::key { 'puppetlabs':
      key        => '4BD6EC30',
      key_server => 'pgp.mit.edu',
    }

    apt::key { 'jenkins':
      key        => 'D50582E6',
      key_source => 'http://pkg.jenkins-ci.org/debian/jenkins-ci.org.key',
    }

Note that use of `key_source` requires wget to be installed and working.

### apt::pin

Adds an apt pin for a certain release.

    apt::pin { 'karmic': priority => 700 }
    apt::pin { 'karmic-updates': priority => 700 }
    apt::pin { 'karmic-security': priority => 700 }

Note you can also specifying more complex pins using distribution properties.

    apt::pin { 'stable':
      priority        => -10,
      originator      => 'Debian',
      release_version => '3.0',
      component       => 'main',
      label           => 'Debian'
    }

### apt::ppa

Adds a ppa repository using `add-apt-repository`.

    apt::ppa { 'ppa:drizzle-developers/ppa': }

### apt::release

Sets the default apt release. This class is particularly useful when using repositories, like Debian, that are unstable in Ubuntu.

    class { 'apt::release':
      release_id => 'precise',
    }

### apt::source

Adds an apt source to `/etc/apt/sources.list.d/`.

    apt::source { 'debian_unstable':
      location          => 'http://debian.mirror.iweb.ca/debian/',
      release           => 'unstable',
      repos             => 'main contrib non-free',
      required_packages => 'debian-keyring debian-archive-keyring',
      key               => '46925553',
      key_server        => 'subkeys.pgp.net',
      pin               => '-10',
      include_src       => true
    }

If you would like to configure your system so the source is the Puppet Labs APT repository

    apt::source { 'puppetlabs':
      location   => 'http://apt.puppetlabs.com',
      repos      => 'main',
      key        => '4BD6EC30',
      key_server => 'pgp.mit.edu',
    }

### Testing

The APT module is mostly a collection of defined resource types, which provide reusable logic that can be leveraged to manage APT. It does provide smoke tests for testing functionality on a target system, as well as spec tests for checking a compiled catalog against an expected set of resources.

#### Example Test

This test will set up a Puppet Labs apt repository. Start by creating a new smoke test in the apt module's test folder. Call it puppetlabs-apt.pp. Inside, declare a single resource representing the Puppet Labs APT source and gpg key

    apt::source { 'puppetlabs':
      location   => 'http://apt.puppetlabs.com',
      repos      => 'main',
      key        => '4BD6EC30',
      key_server => 'pgp.mit.edu',
    }

This resource creates an apt source named puppetlabs and gives Puppet information about the repository's location and key used to sign its packages. Puppet leverages Facter to determine the appropriate release, but you can set it directly by adding the release type.

Check your smoke test for syntax errors

    $ puppet parser validate tests/puppetlabs-apt.pp

If you receive no output from that command, it means nothing is wrong. Then apply the code

    $ puppet apply --verbose tests/puppetlabs-apt.pp
    notice: /Stage[main]//Apt::Source[puppetlabs]/File[puppetlabs.list]/ensure: defined content as '{md5}3be1da4923fb910f1102a233b77e982e'
    info: /Stage[main]//Apt::Source[puppetlabs]/File[puppetlabs.list]: Scheduling refresh of Exec[puppetlabs apt update]
    notice: /Stage[main]//Apt::Source[puppetlabs]/Exec[puppetlabs apt update]: Triggered 'refresh' from 1 events>

The above example used a smoke test to easily lay out a resource declaration and apply it on your system. In production, you may want to declare your APT sources inside the classes where they’re needed.

Implementation

### apt::backports

Adds the necessary components to get backports for Ubuntu and Debian. The release name defaults to `$lsbdistcodename`. Setting this manually can cause undefined behavior (read: universe exploding).

Limitations

This module should work across all versions of Debian/Ubuntu and support all major APT repository management features.

Development

Puppet Labs modules on the Puppet Forge are open projects, and community contributions are essential for keeping them great. We can’t access the huge number of platforms and myriad of hardware, software, and deployment configurations that Puppet is intended to serve.

We want to keep it as easy as possible to contribute changes so that our modules work in your environment. There are a few guidelines that we need contributors to follow so that we can have a chance of keeping on top of things.

You can read the complete module contribution guide [on the Puppet Labs wiki.](http://projects.puppetlabs.com/projects/module-site/wiki/Module_contributing)

License

The original code for this module comes from Evolving Web and was licensed under the MIT license. Code added since the fork of this module is licensed under the Apache 2.0 License like the rest of the Puppet Labs products.

The LICENSE contains both licenses.

Contributors

A lot of great people have contributed to this module. A somewhat current list follows:

* Ben Godfrey <ben.godfrey@wonga.com>
* Branan Purvine-Riley <branan@puppetlabs.com>
* Christian G. Warden <cwarden@xerus.org>
* Dan Bode <bodepd@gmail.com> <dan@puppetlabs.com>
* Garrett Honeycutt <github@garretthoneycutt.com>
* Jeff Wallace <jeff@evolvingweb.ca> <jeff@tjwallace.ca>
* Ken Barber <ken@bob.sh>
* Matthaus Litteken <matthaus@puppetlabs.com> <mlitteken@gmail.com>
* Matthias Pigulla <mp@webfactory.de>
* Monty Taylor <mordred@inaugust.com>
* Peter Drake <pdrake@allplayers.com>
* Reid Vandewiele <marut@cat.pdx.edu>
* Robert Navarro <rnavarro@phiivo.com>
* Ryan Coleman <ryan@puppetlabs.com>
* Scott McLeod <scott.mcleod@theice.com>
* Spencer Krum <spencer@puppetlabs.com>
* William Van Hevelingen <blkperl@cat.pdx.edu> <wvan13@gmail.com>
* Zach Leslie <zach@puppetlabs.com>
require 'puppetlabs_spec_helper/rake_tasks'
require 'puppet-lint/tasks/puppet-lint'

PuppetLint.configuration.send('disable_single_quote_string_with_variables')
# This adds the necessary components to get backports for ubuntu and debian
#
# == Parameters
#
# [*release*]
#   The ubuntu/debian release name. Defaults to $lsbdistcodename. Setting this
#   manually can cause undefined behavior. (Read: universe exploding)
#
# == Examples
#
#   include apt::backports
#
#   class { 'apt::backports':
#     release => 'natty',
#   }
#
# == Authors
#
# Ben Hughes, I think. At least blame him if this goes wrong.
# I just added puppet doc.
#
# == Copyright
#
# Copyright 2011 Puppet Labs Inc, unless otherwise noted.
class apt::backports(
  $release  = $::lsbdistcodename,
  $location = $apt::params::backports_location
) inherits apt::params {

  $release_real = downcase($release)
  $key = $::lsbdistid ? {
    'debian' => '46925553',
    'ubuntu' => '437D05B5',
  }
  $repos = $::lsbdistid ? {
    'debian' => 'main contrib non-free',
    'ubuntu' => 'main universe multiverse restricted',
  }

  apt::source { 'backports':
    location   => $location,
    release    => "${release_real}-backports",
    repos      => $repos,
    key        => $key,
    key_server => 'pgp.mit.edu',
    pin        => '200',
  }
}
# builddep.pp

define apt::builddep() {
  include apt::update

  exec { "apt-builddep-${name}":
    command   => "/usr/bin/apt-get -y --force-yes build-dep ${name}",
    logoutput => 'on_failure',
    notify    => Exec['apt_update'],
  }

  # Need anchor to provide containment for dependencies.
  anchor { "apt::builddep::${name}":
    require => Class['apt::update'],
  }
}
define apt::conf (
  $content,
  $ensure   = present,
  $priority = '50'
) {

  include apt::params

  $apt_conf_d = $apt::params::apt_conf_d

  file { "${apt_conf_d}/${priority}${name}":
    ensure  => $ensure,
    content => $content,
    owner   => root,
    group   => root,
    mode    => '0644',
  }
}
# testing.pp

class apt::debian::testing {
  include apt

  # deb http://debian.mirror.iweb.ca/debian/ testing main contrib non-free
  # deb-src http://debian.mirror.iweb.ca/debian/ testing main contrib non-free
  # Key: 46925553  Server: subkeys.pgp.net
  # debian-keyring
  # debian-archive-keyring

  apt::source { 'debian_testing':
    location          => 'http://debian.mirror.iweb.ca/debian/',
    release           => 'testing',
    repos             => 'main contrib non-free',
    required_packages => 'debian-keyring debian-archive-keyring',
    key               => '46925553',
    key_server        => 'subkeys.pgp.net',
    pin               => '-10',
  }
}
# unstable.pp

class apt::debian::unstable {
  include apt

  # deb http://debian.mirror.iweb.ca/debian/ unstable main contrib non-free
  # deb-src http://debian.mirror.iweb.ca/debian/ unstable main contrib non-free
  # Key: 46925553  Server: subkeys.pgp.net
  # debian-keyring
  # debian-archive-keyring

  apt::source { 'debian_unstable':
    location          => 'http://debian.mirror.iweb.ca/debian/',
    release           => 'unstable',
    repos             => 'main contrib non-free',
    required_packages => 'debian-keyring debian-archive-keyring',
    key               => '46925553',
    key_server        => 'subkeys.pgp.net',
    pin               => '-10',
  }
}
# force.pp
# force a package from a specific release

define apt::force(
  $release = 'testing',
  $version = false,
  $timeout = 300
) {

  $provider = $apt::params::provider

  $version_string = $version ? {
    false   => undef,
    default => "=${version}",
  }

  $release_string = $release ? {
    false   => undef,
    default => "-t ${release}",
  }

  if $version == false {
    if $release == false {
      $install_check = "/usr/bin/dpkg -s ${name} | grep -q 'Status: install'"
    } else {
      # If installed version and candidate version differ, this check returns 1 (false).
      $install_check = "/usr/bin/test \$(/usr/bin/apt-cache policy -t ${release} ${name} | /bin/grep -E 'Installed|Candidate' | /usr/bin/uniq -s 14 | /usr/bin/wc -l) -eq 1"
    }
  } else {
    if $release == false {
      $install_check = "/usr/bin/dpkg -s ${name} | grep -q 'Version: ${version}'"
    } else {
      $install_check = "/usr/bin/apt-cache policy -t ${release} ${name} | /bin/grep -q 'Installed: ${version}'"
    }
  }

  exec { "${provider} -y ${release_string} install ${name}${version_string}":
    unless    => $install_check,
    logoutput => 'on_failure',
    timeout   => $timeout,
  }
}
# Class: apt
#
# This module manages the initial configuration of apt.
#
# Parameters:
#   The parameters listed here are not required in general and were
#     added for use cases related to development environments.
#   disable_keys - disables the requirement for all packages to be signed
#   always_apt_update - rather apt should be updated on every run (intended
#     for development environments where package updates are frequent)
#   purge_sources_list - Accepts true or false. Defaults to false If set to
#     true, Puppet will purge all unmanaged entries from sources.list
#   purge_sources_list_d - Accepts true or false. Defaults to false. If set
#     to true, Puppet will purge all unmanaged entries from sources.list.d
#   update_timeout - Overrides the exec timeout in seconds for apt-get update.
#     If not set defaults to Exec's default (300)
#
# Actions:
#
# Requires:
#   puppetlabs/stdlib
# Sample Usage:
#  class { 'apt': }

class apt(
  $always_apt_update    = false,
  $disable_keys         = undef,
  $proxy_host           = undef,
  $proxy_port           = '8080',
  $purge_sources_list   = false,
  $purge_sources_list_d = false,
  $purge_preferences_d  = false,
  $update_timeout       = undef
) {

  include apt::params
  include apt::update

  validate_bool($purge_sources_list, $purge_sources_list_d, $purge_preferences_d)

  $sources_list_content = $purge_sources_list ? {
    false => undef,
    true  => "# Repos managed by puppet.\n",
  }

  if $always_apt_update == true {
    Exec <| title=='apt_update' |> {
      refreshonly => false,
    }
  }

  $root           = $apt::params::root
  $apt_conf_d     = $apt::params::apt_conf_d
  $sources_list_d = $apt::params::sources_list_d
  $preferences_d  = $apt::params::preferences_d
  $provider       = $apt::params::provider

  file { 'sources.list':
    ensure  => present,
    path    => "${root}/sources.list",
    owner   => root,
    group   => root,
    mode    => '0644',
    content => $sources_list_content,
    notify  => Exec['apt_update'],
  }

  file { 'sources.list.d':
    ensure  => directory,
    path    => $sources_list_d,
    owner   => root,
    group   => root,
    purge   => $purge_sources_list_d,
    recurse => $purge_sources_list_d,
    notify  => Exec['apt_update'],
  }

  file { 'preferences.d':
    ensure  => directory,
    path    => $preferences_d,
    owner   => root,
    group   => root,
    purge   => $purge_preferences_d,
    recurse => $purge_preferences_d,
  }

  case $disable_keys {
    true: {
      file { '99unauth':
        ensure  => present,
        content => "APT::Get::AllowUnauthenticated 1;\n",
        path    => "${apt_conf_d}/99unauth",
      }
    }
    false: {
      file { '99unauth':
        ensure => absent,
        path   => "${apt_conf_d}/99unauth",
      }
    }
    undef:   { } # do nothing
    default: { fail('Valid values for disable_keys are true or false') }
  }

  $proxy_set = $proxy_host ? {
    undef   => absent,
    default => present
  }

  file { 'configure-apt-proxy':
    ensure  => $proxy_set,
    path    => "${apt_conf_d}/proxy",
    content => "Acquire::http::Proxy \"http://${proxy_host}:${proxy_port}\";",
    notify  => Exec['apt_update'],
  }

  # Need anchor to provide containment for dependencies.
  anchor { 'apt::update':
    require => Class['apt::update'],
  }
}
define apt::key (
  $key = $title,
  $ensure = present,
  $key_content = false,
  $key_source = false,
  $key_server = 'keyserver.ubuntu.com',
  $key_options = false
) {

  include apt::params

  $upkey = upcase($key)
  # trim the key to the last 8 chars so we can match longer keys with apt-key list too
  $trimmedkey = regsubst($upkey, '^.*(.{8})$', '\1')

  if $key_content {
    $method = 'content'
  } elsif $key_source {
    $method = 'source'
  } elsif $key_server {
    $method = 'server'
  }

  # This is a hash of the parts of the key definition that we care about.
  # It is used as a unique identifier for this instance of apt::key. It gets
  # hashed to ensure that the resource name doesn't end up being pages and
  # pages (e.g. in the situation where key_content is specified).
  $digest = sha1("${upkey}/${key_content}/${key_source}/${key_server}/")

  # Allow multiple ensure => present for the same key to account for many
  # apt::source resources that all reference the same key.
  case $ensure {
    present: {

      anchor { "apt::key/${title}": }

      if defined(Exec["apt::key ${upkey} absent"]) {
        fail("Cannot ensure Apt::Key[${upkey}] present; ${upkey} already ensured absent")
      }

      if !defined(Anchor["apt::key ${upkey} present"]) {
        anchor { "apt::key ${upkey} present": }
      }

      if $key_options{
        $options_string = "--keyserver-options ${key_options}"
      }
      else{
        $options_string = ''
      }

      if !defined(Exec[$digest]) {
        $digest_command = $method ? {
          'content' => "echo '${key_content}' | /usr/bin/apt-key add -",
          'source'  => "wget -q '${key_source}' -O- | apt-key add -",
          'server'  => "apt-key adv --keyserver '${key_server}' ${options_string} --recv-keys '${upkey}'",
        }
        exec { $digest:
          command   => $digest_command,
          path      => '/bin:/usr/bin',
          unless    => "/usr/bin/apt-key list | /bin/grep '${trimmedkey}'",
          logoutput => 'on_failure',
          before    => Anchor["apt::key ${upkey} present"],
        }
      }

      Anchor["apt::key ${upkey} present"] -> Anchor["apt::key/${title}"]

    }
    absent: {

      if defined(Anchor["apt::key ${upkey} present"]) {
        fail("Cannot ensure Apt::Key[${upkey}] absent; ${upkey} already ensured present")
      }

      exec { "apt::key ${upkey} absent":
        command   => "apt-key del '${upkey}'",
        path      => '/bin:/usr/bin',
        onlyif    => "apt-key list | grep '${trimmedkey}'",
        user      => 'root',
        group     => 'root',
        logoutput => 'on_failure',
      }
    }

    default: {
      fail "Invalid 'ensure' value '${ensure}' for aptkey"
    }
  }
}
class apt::params {
  $root           = '/etc/apt'
  $provider       = '/usr/bin/apt-get'
  $sources_list_d = "${root}/sources.list.d"
  $apt_conf_d     = "${root}/apt.conf.d"
  $preferences_d  = "${root}/preferences.d"

  case $::lsbdistid {
    'debian': {
      case $::lsbdistcodename {
        'squeeze': {
          $backports_location = 'http://backports.debian.org/debian-backports'
        }
        'wheezy': {
          $backports_location = 'http://ftp.debian.org/debian/'
        }
        default: {
          $backports_location = 'http://http.debian.net/debian/'
        }
      }
    }
    'ubuntu': {
      case $::lsbdistcodename {
        'hardy','maverick','natty','oneiric','precise': {
          $backports_location = 'http://us.archive.ubuntu.com/ubuntu'
          $ppa_options = '-y'
        }
        'lucid': {
          $backports_location = 'http://us.archive.ubuntu.com/ubuntu'
          $ppa_options = undef
        }
        default: {
          $backports_location = 'http://old-releases.ubuntu.com/ubuntu'
          $ppa_options = '-y'
        }
      }
    }
    default: {
      fail("Unsupported osfamily (${::osfamily}) or lsbdistid (${::lsbdistid})")
    }
  }
}
# pin.pp
# pin a release in apt, useful for unstable repositories

define apt::pin(
  $ensure          = present,
  $explanation     = "${::caller_module_name}: ${name}",
  $order           = '',
  $packages        = '*',
  $priority        = 0,
  $release         = '', # a=
  $origin          = '',
  $version         = '',
  $codename        = '', # n=
  $release_version = '', # v=
  $component       = '', # c=
  $originator      = '', # o=
  $label           = ''  # l=
) {

  include apt::params

  $preferences_d = $apt::params::preferences_d

  if $order != '' and !is_integer($order) {
    fail('Only integers are allowed in the apt::pin order param')
  }

  $pin_release_array = [
    $release,
    $codename,
    $release_version,
    $component,
    $originator,
    $label]
  $pin_release = join($pin_release_array, '')

  # Read the manpage 'apt_preferences(5)', especially the chapter
  # 'Thea Effect of APT Preferences' to understand the following logic
  # and the difference between specific and general form
  if $packages != '*' { # specific form

    if ( $pin_release != '' and ( $origin != '' or $version != '' )) or
      ( $origin != '' and ( $pin_release != '' or $version != '' )) or
      ( $version != '' and ( $pin_release != '' or $origin != '' )) {
      fail('parameters release, origin, and version are mutually exclusive')
    }

  } else { # general form

    if $version != '' {
      fail('parameter version cannot be used in general form')
    }

    if ( $pin_release != '' and $origin != '' ) or
      ( $origin != '' and $pin_release != '' ) {
      fail('parmeters release and origin are mutually exclusive')
    }

  }

  $path = $order ? {
    ''      => "${preferences_d}/${name}.pref",
    default => "${preferences_d}/${order}-${name}.pref",
  }
  file { "${name}.pref":
    ensure  => $ensure,
    path    => $path,
    owner   => root,
    group   => root,
    mode    => '0644',
    content => template('apt/pin.pref.erb'),
  }
}
# ppa.pp

define apt::ppa(
  $release = $::lsbdistcodename,
  $options = $apt::params::ppa_options,
) {
  $ensure  = 'present'
  include apt::params
  include apt::update

  $sources_list_d = $apt::params::sources_list_d

  if ! $release {
    fail('lsbdistcodename fact not available: release parameter required')
  }

  if $::operatingsystem != 'Ubuntu' {
    fail("apt::ppa is currently supported on Ubuntu only.")
  }

  $filename_without_slashes = regsubst($name, '/', '-', 'G')
  $filename_without_dots    = regsubst($filename_without_slashes, '\.', '_', 'G')
  $filename_without_ppa     = regsubst($filename_without_dots, '^ppa:', '', 'G')
  $sources_list_d_filename  = "${filename_without_ppa}-${release}.list"

  if $ensure == 'present' {
    $package = $::lsbdistrelease ? {
        /^[1-9]\..*|1[01]\..*|12.04$/ => 'python-software-properties',
        default  => 'software-properties-common',
    }

    if ! defined(Package[$package]) {
        package { $package: }
    }

    if defined(Class[apt]) {
        $proxy_host = $apt::proxy_host
        $proxy_port = $apt::proxy_port
        case  $proxy_host {
        false, '': {
            $proxy_env = []
        }
        default: {$proxy_env = ["http_proxy=http://${proxy_host}:${proxy_port}", "https_proxy=http://${proxy_host}:${proxy_port}"]}
        }
    } else {
        $proxy_env = []
    }
    exec { "add-apt-repository-${name}":
        environment  => $proxy_env,
        command      => "/usr/bin/add-apt-repository ${options} ${name}",
        unless       => "/usr/bin/test -s ${sources_list_d}/${sources_list_d_filename}",
        user         => 'root',
        logoutput    => 'on_failure',
        notify       => Exec['apt_update'],
        require      => [
        File['sources.list.d'],
        Package[$package],
        ],
    }

    file { "${sources_list_d}/${sources_list_d_filename}":
        ensure  => file,
        require => Exec["add-apt-repository-${name}"],
    }
  }
  else {

    file { "${sources_list_d}/${sources_list_d_filename}":
        ensure => 'absent',
        mode   => '0644',
        owner  => 'root',
        gruop  => 'root',
        notify => Exec['apt_update'],
    }
  }

  # Need anchor to provide containment for dependencies.
  anchor { "apt::ppa::${name}":
    require => Class['apt::update'],
  }
}
# release.pp

class apt::release (
  $release_id
) {

  include apt::params

  $root = $apt::params::root

  file { "${root}/apt.conf.d/01release":
    owner   => root,
    group   => root,
    mode    => '0644',
    content => "APT::Default-Release \"${release_id}\";"
  }
}
# source.pp
# add an apt source

define apt::source(
  $ensure            = present,
  $location          = '',
  $release           = 'UNDEF',
  $repos             = 'main',
  $include_src       = true,
  $required_packages = false,
  $key               = false,
  $key_server        = 'keyserver.ubuntu.com',
  $key_content       = false,
  $key_source        = false,
  $pin               = false,
  $architecture      = undef
) {

  include apt::params
  include apt::update

  $sources_list_d = $apt::params::sources_list_d
  $provider       = $apt::params::provider

  if $release == 'UNDEF' {
    if $::lsbdistcodename == undef {
      fail('lsbdistcodename fact not available: release parameter required')
    } else {
      $release_real = $::lsbdistcodename
    }
  } else {
    $release_real = $release
  }

  file { "${name}.list":
    ensure  => $ensure,
    path    => "${sources_list_d}/${name}.list",
    owner   => root,
    group   => root,
    mode    => '0644',
    content => template("${module_name}/source.list.erb"),
    notify  => Exec['apt_update'],
  }


  if ($pin != false) {
    # Get the host portion out of the url so we can pin to origin
    $url_split = split($location, '/')
    $host      = $url_split[2]

    apt::pin { $name:
      ensure   => $ensure,
      priority => $pin,
      before   => File["${name}.list"],
      origin   => $host,
    }
  }

  if ($required_packages != false) and ($ensure == 'present') {
    exec { "Required packages: '${required_packages}' for ${name}":
      command     => "${provider} -y install ${required_packages}",
      logoutput   => 'on_failure',
      refreshonly => true,
      tries       => 3,
      try_sleep   => 1,
      subscribe   => File["${name}.list"],
      before      => Exec['apt_update'],
    }
  }

  # We do not want to remove keys when the source is absent.
  if ($key != false) and ($ensure == 'present') {
    apt::key { "Add key: ${key} from Apt::Source ${title}":
      ensure      => present,
      key         => $key,
      key_server  => $key_server,
      key_content => $key_content,
      key_source  => $key_source,
      before      => File["${name}.list"],
    }
  }

  # Need anchor to provide containment for dependencies.
  anchor { "apt::source::${name}":
    require => Class['apt::update'],
  }
}
# Class: apt::unattended_upgrades
#
# This class manages the unattended-upgrades package and related configuration
# files for ubuntu
#
# origins are the repositories to automatically upgrade included packages
# blacklist is a list of packages to not automatically upgrade
# update is how often to run "apt-get update" in days
# download is how often to run "apt-get upgrade --download-only" in days
# upgrade is how often to upgrade packages included in the origins list in days
# autoclean is how often to run "apt-get autoclean" in days
#
# information on the other options can be found in the 50unattended-upgrades
# file and in /etc/cron.daily/apt
#
class apt::unattended_upgrades (
  $origins = ['${distro_id}:${distro_codename}-security'],
  $blacklist = [],
  $update = "1",
  $download = "1",
  $upgrade = "1",
  $autoclean = "7",
  $auto_fix = true,
  $minimal_steps = false,
  $install_on_shutdown = false,
  $mail_to = "NONE",
  $mail_only_on_error = false,
  $remove_unused = true,
  $auto_reboot = false,
  $dl_limit = "NONE",
  $enable = "1",
  $backup_interval = "0",
  $backup_level = "3",
  $max_age = "0",
  $min_age = "0",
  $max_size = "0",
  $download_delta = "0",
  $verbose = "0",
) {
  include apt::params

  validate_bool(
    $auto_fix,
    $minimal_steps,
    $install_on_shutdown,
    $mail_only_on_error,
    $remove_unused,
    $auto_reboot
  )

  package { 'unattended-upgrades':
    ensure => present,
  }

  File {
    ensure  => file,
    owner   => 'root',
    group   => 'root',
    mode    => '0644',
    require => Package['unattended-upgrades'],
  }

  file {
    '/etc/apt/apt.conf.d/50unattended-upgrades':
      content => template('apt/50unattended-upgrades.erb');
    '/etc/apt/apt.conf.d/10periodic':
      content => template('apt/10periodic.erb');
  }
}
class apt::update {
  include apt::params

  exec { 'apt_update':
    command     => "${apt::params::provider} update",
    logoutput   => 'on_failure',
    refreshonly => true,
    timeout     => $apt::update_timeout,
  }
}
{
    "name": "puppetlabs-apt",
    "version": "1.4.1",
    "source": "https://github.com/puppetlabs/puppetlabs-apt",
    "author": "Puppet Labs",
    "license": "Apache-2.0",
    "project_page": "https://github.com/puppetlabs/puppetlabs-apt",
    "summary": "Puppet Labs Apt Module",
    "operatingsystem_support": [
      {
        "operatingsystem": "Debian",
        "operatingsystemrelease": [
          "6",
          "7"
        ]
      },
      {
        "operatingsystem": "Ubuntu",
        "operatingsystemrelease": [
          "10.04",
          "12.04"
        ]
      }
    ],
    "requirements": [
      { "name": "pe", "version_requirement": "3.2.x" },
      { "name": "puppet", "version_requirement": "3.x" }
    ],
    "dependencies": []
}
require 'spec_helper_acceptance'

describe 'apt::builddep', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do

  context 'reset' do
    it 'removes packages' do
      shell('apt-get -y remove znc')
      shell('apt-get -y remove g++')
    end
  end

  context 'apt::builddep' do
    it 'should work with no errors' do
      pp = <<-EOS
      include '::apt'
      apt::builddep { 'znc': }
      EOS

      apply_manifest(pp, :catch_failures => true)
    end

    describe 'should install g++ as a dependency' do
      describe package('g++') do
        it { should be_installed }
      end
    end
  end

  context 'reset' do
    it 'removes packages' do
      shell('apt-get -y remove znc')
      shell('apt-get -y remove g++')
    end
  end

end
require 'spec_helper_acceptance'

describe 'apt::key', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
  context 'apt::key' do
    it 'should work with no errors' do
      pp = <<-EOS
      include '::apt'
      apt::key { 'puppetlabs':
        key        => '4BD6EC30',
        key_server => 'pgp.mit.edu',
      }

      apt::key { 'jenkins':
        key        => 'D50582E6',
        key_source => 'http://pkg.jenkins-ci.org/debian/jenkins-ci.org.key',
      }
      EOS

      shell('apt-key del 4BD6EC30', :acceptable_exit_codes => [0,1,2])
      shell('apt-key del D50582E6', :acceptable_exit_codes => [0,1,2])
      apply_manifest(pp, :catch_failures => true)
    end

    describe 'keys should exist' do
      it 'finds puppetlabs key' do
        shell('apt-key list | grep 4BD6EC30')
      end
      it 'finds jenkins key' do
        shell('apt-key list | grep D50582E6')
      end
    end
  end
  context 'ensure' do
    context 'absent' do
      it 'should work with no errors' do
        pp = <<-EOS
        include '::apt'
        apt::key { 'puppetlabs':
          ensure     => absent,
          key        => '4BD6EC30',
          key_server => 'pgp.mit.edu',
        }

        apt::key { 'jenkins':
          ensure     => absent,
          key        => 'D50582E6',
          key_source => 'http://pkg.jenkins-ci.org/debian/jenkins-ci.org.key',
        }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      describe 'keys shouldnt exist' do
        it 'fails' do
          shell('apt-key list | grep 4BD6EC30', :acceptable_exit_codes => [1])
        end
        it 'fails' do
          shell('apt-key list | grep D50582E6', :acceptable_exit_codes => [1])
        end
      end
    end
  end

  context 'reset' do
    it 'clean up keys' do
      shell('apt-key del 4BD6EC30', :acceptable_exit_codes => [0,1,2])
      shell('apt-key del D50582E6', :acceptable_exit_codes => [0,1,2])
    end
  end

  context 'key options' do
    context 'key_content' do

      it 'should work with no errors' do
        pp = <<-EOS
        include '::apt'
        apt::key { 'puppetlabs':
          key         => '4BD6EC30',
          key_content => '-----BEGIN PGP PUBLIC KEY BLOCK-----
          Version: GnuPG v1.4.12 (GNU/Linux)
          Comment: GPGTools - http://gpgtools.org

          mQINBEw3u0ABEAC1+aJQpU59fwZ4mxFjqNCgfZgDhONDSYQFMRnYC1dzBpJHzI6b
          fUBQeaZ8rh6N4kZ+wq1eL86YDXkCt4sCvNTP0eF2XaOLbmxtV9bdpTIBep9bQiKg
          5iZaz+brUZlFk/MyJ0Yz//VQ68N1uvXccmD6uxQsVO+gx7rnarg/BGuCNaVtGwy+
            S98g8Begwxs9JmGa8pMCcSxtC7fAfAEZ02cYyrw5KfBvFI3cHDdBqrEJQKwKeLKY
          GHK3+H1TM4ZMxPsLuR/XKCbvTyl+OCPxU2OxPjufAxLlr8BWUzgJv6ztPe9imqpH
          Ppp3KuLFNorjPqWY5jSgKl94W/CO2x591e++a1PhwUn7iVUwVVe+mOEWnK5+Fd0v
          VMQebYCXS+3dNf6gxSvhz8etpw20T9Ytg4EdhLvCJRV/pYlqhcq+E9le1jFOHOc0
          Nc5FQweUtHGaNVyn8S1hvnvWJBMxpXq+Bezfk3X8PhPT/l9O2lLFOOO08jo0OYiI
          wrjhMQQOOSZOb3vBRvBZNnnxPrcdjUUm/9cVB8VcgI5KFhG7hmMCwH70tpUWcZCN
          NlI1wj/PJ7Tlxjy44f1o4CQ5FxuozkiITJvh9CTg+k3wEmiaGz65w9jRl9ny2gEl
          f4CR5+ba+w2dpuDeMwiHJIs5JsGyJjmA5/0xytB7QvgMs2q25vWhygsmUQARAQAB
          tEdQdXBwZXQgTGFicyBSZWxlYXNlIEtleSAoUHVwcGV0IExhYnMgUmVsZWFzZSBL
          ZXkpIDxpbmZvQHB1cHBldGxhYnMuY29tPokCPgQTAQIAKAUCTDe7QAIbAwUJA8Jn
          AAYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AACgkQEFS3okvW7DAZaw//aLmE/eob
          pXpIUVyCUWQxEvPtM/h/SAJsG3KoHN9u216ews+UHsL/7F91ceVXQQdD2e8CtYWF
          eLNM0RSM9i/KM60g4CvIQlmNqdqhi1HsgGqInZ72/XLAXun0gabfC36rLww2kel+
            aMpRf58SrSuskY321NnMEJl4OsHV2hfNtAIgw2e/zm9RhoMpGKxoHZCvFhnP7u2M
          2wMq7iNDDWb6dVsLpzdlVf242zCbubPCxxQXOpA56rzkUPuJ85mdVw4i19oPIFIZ
          VL5owit1SxCOxBg4b8oaMS36hEl3qtZG834rtLfcqAmqjhx6aJuJLOAYN84QjDEU
          3NI5IfNRMvluIeTcD4Dt5FCYahN045tW1Rc6s5GAR8RW45GYwQDzG+kkkeeGxwEh
          qCW7nOHuwZIoVJufNhd28UFn83KGJHCQt4NBBr3K5TcY6bDQEIrpSplWSDBbd3p1
          IaoZY1WSDdP9OTVOSbsz0JiglWmUWGWCdd/CMSW/D7/3VUOJOYRDwptvtSYcjJc8
          1UV+1zB+rt5La/OWe4UOORD+jU1ATijQEaFYxBbqBBkFboAEXq9btRQyegqk+eVp
          HhzacP5NYFTMThvHuTapNytcCso5au/cMywqCgY1DfcMJyjocu4bCtrAd6w4kGKN
          MUdwNDYQulHZDI+UjJInhramyngdzZLjdeGJARwEEAECAAYFAkw3wEYACgkQIVr+
            UOQUcDKvEwgAoBuOPnPioBwYp8oHVPTo/69cJn1225kfraUYGebCcrRwuoKd8Iyh
          R165nXYJmD8yrAFBk8ScUVKsQ/pSnqNrBCrlzQD6NQvuIWVFegIdjdasrWX6Szj+
            N1OllbzIJbkE5eo0WjCMEKJVI/GTY2AnTWUAm36PLQC5HnSATykqwxeZDsJ/s8Rc
          kd7+QN5sBVytG3qb45Q7jLJpLcJO6KYH4rz9ZgN7LzyyGbu9DypPrulADG9OrL7e
          lUnsGDG4E1M8Pkgk9Xv9MRKao1KjYLD5zxOoVtdeoKEQdnM+lWMJin1XvoqJY7FT
          DJk6o+cVqqHkdKL+sgsscFVQljgCEd0EgIkCHAQQAQgABgUCTPlA6QAKCRBcE9bb
          kwUuAxdYD/40FxAeNCYByxkr/XRT0gFT+NCjPuqPWCM5tf2NIhSapXtb2+32WbAf
          DzVfqWjC0G0RnQBve+vcjpY4/rJu4VKIDGIT8CtnKOIyEcXTNFOehi65xO4ypaei
          BPSb3ip3P0of1iZZDQrNHMW5VcyL1c+PWT/6exXSGsePtO/89tc6mupqZtC05f5Z
          XG4jswMF0U6Q5s3S0tG7Y+oQhKNFJS4sH4rHe1o5CxKwNRSzqccA0hptKy3MHUZ2
          +zeHzuRdRWGjb2rUiVxnIvPPBGxF2JHhB4ERhGgbTxRZ6wZbdW06BOE8r7pGrUpU
          fCw/WRT3gGXJHpGPOzFAvr3Xl7VcDUKTVmIajnpd3SoyD1t2XsvJlSQBOWbViucH
          dvE4SIKQ77vBLRlZIoXXVb6Wu7Vq+eQs1ybjwGOhnnKjz8llXcMnLzzN86STpjN4
          qGTXQy/E9+dyUP1sXn3RRwb+ZkdI77m1YY95QRNgG/hqh77IuWWg1MtTSgQnP+F2
          7mfo0/522hObhdAe73VO3ttEPiriWy7tw3bS9daP2TAVbYyFqkvptkBb1OXRUSzq
          UuWjBmZ35UlXjKQsGeUHlOiEh84aondF90A7gx0X/ktNIPRrfCGkHJcDu+HVnR7x
          Kk+F0qb9+/pGLiT3rqeQTr8fYsb4xLHT7uEg1gVFB1g0kd+RQHzV74kCPgQTAQIA
          KAIbAwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AFAk/x5PoFCQtIMjoACgkQEFS3
          okvW7DAIKQ/9HvZyf+LHVSkCk92Kb6gckniin3+5ooz67hSr8miGBfK4eocqQ0H7
          bdtWjAILzR/IBY0xj6OHKhYP2k8TLc7QhQjt0dRpNkX+Iton2AZryV7vUADreYz4
          4B0bPmhiE+LL46ET5IThLKu/KfihzkEEBa9/t178+dO9zCM2xsXaiDhMOxVE32gX
          vSZKP3hmvnK/FdylUY3nWtPedr+lHpBLoHGaPH7cjI+MEEugU3oAJ0jpq3V8n4w0
          jIq2V77wfmbD9byIV7dXcxApzciK+ekwpQNQMSaceuxLlTZKcdSqo0/qmS2A863Y
          ZQ0ZBe+Xyf5OI33+y+Mry+vl6Lre2VfPm3udgR10E4tWXJ9Q2CmG+zNPWt73U1FD
          7xBI7PPvOlyzCX4QJhy2Fn/fvzaNjHp4/FSiCw0HvX01epcersyun3xxPkRIjwwR
          M9m5MJ0o4hhPfa97zibXSh8XXBnosBQxeg6nEnb26eorVQbqGx0ruu/W2m5/JpUf
          REsFmNOBUbi8xlKNS5CZypH3Zh88EZiTFolOMEh+hT6s0l6znBAGGZ4m/Unacm5y
          DHmg7unCk4JyVopQ2KHMoqG886elu+rm0ASkhyqBAk9sWKptMl3NHiYTRE/m9VAk
          ugVIB2pi+8u84f+an4Hml4xlyijgYu05pqNvnLRyJDLd61hviLC8GYU=
            =a34C
          -----END PGP PUBLIC KEY BLOCK-----
          ',
        }
        EOS

        shell('apt-key del 4BD6EC30', :acceptable_exit_codes => [0,1,2])
        apply_manifest(pp, :catch_failures => true)
      end
    end
    describe 'keys should exist' do
      it 'finds puppetlabs key' do
        shell('apt-key list | grep 4BD6EC30')
      end
    end

    context 'key_source' do

      it 'should work with no errors' do
        pp = <<-EOS
        include '::apt'
        apt::key { 'puppetlabs':
          key        => '4BD6EC30',
          key_source => 'http://apt.puppetlabs.com/pubkey.gpg',
        }
        EOS

        shell('apt-key del 4BD6EC30', :acceptable_exit_codes => [0,1,2])
        apply_manifest(pp, :catch_failures => true)
      end

      describe 'keys should exist' do
        it 'finds puppetlabs key' do
          shell('apt-key list | grep 4BD6EC30')
        end
      end
    end

    context 'key_options' do

      it 'should work with no errors' do
        pp = <<-EOS
        include '::apt'
        apt::key { 'puppetlabs':
          key        => '4BD6EC30',
          key_source => 'http://apt.puppetlabs.com/pubkey.gpg',
          key_options => 'debug'
        }
        EOS

        shell('apt-key del 4BD6EC30', :acceptable_exit_codes => [0,1,2])
        apply_manifest(pp, :catch_failures => true)
      end

      describe 'keys should exist' do
        it 'finds puppetlabs key' do
          shell('apt-key list | grep 4BD6EC30')
        end
      end
    end
  end

end
require 'spec_helper_acceptance'

if fact('operatingsystem') == 'Ubuntu'
  describe 'apt::ppa', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do

    context 'reset' do
      it 'removes ppa' do
        shell('rm /etc/apt/sources.list.d/canonical-kernel-team-ppa-*', :acceptable_exit_codes => [0,1,2])
        shell('rm /etc/apt/sources.list.d/raravena80-collectd5-*', :acceptable_exit_codes => [0,1,2])
      end
    end

    context 'adding a ppa that doesnt exist' do
      it 'should work with no errors' do
        pp = <<-EOS
        include '::apt'
        apt::ppa { 'ppa:canonical-kernel-team/ppa': }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      describe 'contains the source file' do
        it 'contains a kernel ppa source' do
          shell('ls /etc/apt/sources.list.d/canonical-kernel-team-ppa-*', :acceptable_exit_codes => [0])
        end
      end
    end

    context 'reading a removed ppa.' do
      it 'setup' do
        # This leaves a blank file
        shell('echo > /etc/apt/sources.list.d/raravena80-collectd5-$(lsb_release -c -s).list')
      end

      it 'should read it successfully' do
        pp = <<-EOS
        include '::apt'
        apt::ppa { 'ppa:raravena80/collectd5': }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end
    end

    context 'reset' do
      it 'removes added ppas' do
        shell('rm /etc/apt/sources.list.d/canonical-kernel-team-ppa-*')
        shell('rm /etc/apt/sources.list.d/raravena80-collectd5-*')
      end
    end

    context 'release' do
      context 'precise' do
        it 'works without failure' do
          pp = <<-EOS
          include '::apt'
          apt::ppa { 'ppa:canonical-kernel-team/ppa':
            release => precise,
          }
          EOS

          shell('rm -rf /etc/apt/sources.list.d/canonical-kernel-team-ppa*', :acceptable_exit_codes => [0,1,2])
          apply_manifest(pp, :catch_failures => true)
        end

        describe file('/etc/apt/sources.list.d/canonical-kernel-team-ppa-precise.list') do
          it { should be_file }
        end
      end
    end

    context 'options' do
      context '-y', :unless => default[:platform].match(/10\.04/) do
        it 'works without failure' do
          pp = <<-EOS
          include '::apt'
          apt::ppa { 'ppa:canonical-kernel-team/ppa':
            release => precise,
            options => '-y',
          }
          EOS

          shell('rm -rf /etc/apt/sources.list.d/canonical-kernel-team-ppa*', :acceptable_exit_codes => [0,1,2])
          apply_manifest(pp, :catch_failures => true)
        end

        describe file('/etc/apt/sources.list.d/canonical-kernel-team-ppa-precise.list') do
          it { should be_file }
        end
      end
    end

    context 'reset' do
      it { shell('rm -rf /etc/apt/sources.list.d/canonical-kernel-team-ppa*', :acceptable_exit_codes => [0,1,2]) }
    end
  end
end
require 'spec_helper_acceptance'

describe 'apt::source', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do

  context 'apt::source' do
    context 'ensure => present' do
      it 'should work with no errors' do
        pp = <<-EOS
        include '::apt'
        apt::source { 'puppetlabs':
          ensure     => present,
          location   => 'http://apt.puppetlabs.com',
          repos      => 'main',
          key        => '4BD6EC30',
          key_server => 'pgp.mit.edu',
        }
        EOS

        shell('apt-key del 4BD6EC30', :acceptable_exit_codes => [0,1,2])
        shell('rm /etc/apt/sources.list.d/puppetlabs.list', :acceptable_exit_codes => [0,1,2])
        apply_manifest(pp, :catch_failures => true)
      end

      describe 'key should exist' do
        it 'finds puppetlabs key' do
          shell('apt-key list | grep 4BD6EC30', :acceptable_exit_codes => [0])
        end
      end

      describe file('/etc/apt/sources.list.d/puppetlabs.list') do
        it { should be_file }
      end
    end

    context 'ensure => absent' do
      it 'should work with no errors' do
        pp = <<-EOS
        include '::apt'
        apt::source { 'puppetlabs':
          ensure     => absent,
          location   => 'http://apt.puppetlabs.com',
          repos      => 'main',
          key        => '4BD6EC30',
          key_server => 'pgp.mit.edu',
        }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      # The key should remain -we don't delete those when deleting a source.
      describe 'key should exist' do
        it 'finds puppetlabs key' do
          shell('apt-key list | grep 4BD6EC30', :acceptable_exit_codes => [0])
        end
      end
      describe file('/etc/apt/sources.list.d/puppetlabs.list') do
        it { should_not be_file }
      end
    end

  end

  context 'release' do
    context 'test' do
      it 'should work with no errors' do
        pp = <<-EOS
        include '::apt'
        apt::source { 'puppetlabs':
          ensure     => present,
          location   => 'http://apt.puppetlabs.com',
          repos      => 'main',
          key        => '4BD6EC30',
          key_server => 'pgp.mit.edu',
          release    => 'precise',
        }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      describe file('/etc/apt/sources.list.d/puppetlabs.list') do
        it { should be_file }
        it { should contain 'deb http://apt.puppetlabs.com precise main' }
      end
    end
  end

  context 'include_src' do
    context 'true' do
      it 'should work with no errors' do
        pp = <<-EOS
        include '::apt'
        apt::source { 'puppetlabs':
          ensure      => present,
          location    => 'http://apt.puppetlabs.com',
          repos       => 'main',
          key         => '4BD6EC30',
          key_server  => 'pgp.mit.edu',
          include_src => true,
        }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      describe file('/etc/apt/sources.list.d/puppetlabs.list') do
        it { should be_file }
        it { should contain 'deb-src http://apt.puppetlabs.com' }
      end
    end

    context 'false' do
      it 'should work with no errors' do
        pp = <<-EOS
        include '::apt'
        apt::source { 'puppetlabs':
          ensure      => present,
          location    => 'http://apt.puppetlabs.com',
          repos       => 'main',
          key         => '4BD6EC30',
          key_server  => 'pgp.mit.edu',
          include_src => false,
        }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      describe file('/etc/apt/sources.list.d/puppetlabs.list') do
        it { should be_file }
        it { should_not contain 'deb-src http://apt.puppetlabs.com' }
      end
    end
  end

  context 'required_packages' do
    context 'vim' do
      it 'should work with no errors' do
        pp = <<-EOS
        include '::apt'
        apt::source { 'puppetlabs':
          ensure             => present,
          location           => 'http://apt.puppetlabs.com',
          repos              => 'main',
          key                => '4BD6EC30',
          key_server         => 'pgp.mit.edu',
          required_packages  => 'vim',
        }
        EOS

        shell('apt-get -y remove vim')
        apply_manifest(pp, :catch_failures => true)
      end

      describe package('vim') do
        it { should be_installed }
      end
    end
  end

  context 'key content' do
    context 'giant key' do
      it 'should work with no errors' do
        pp = <<-EOS
        include '::apt'
        apt::source { 'puppetlabs':
          ensure      => present,
          location    => 'http://apt.puppetlabs.com',
          repos       => 'main',
          key         => '4BD6EC30',
          key_content => '-----BEGIN PGP PUBLIC KEY BLOCK-----
          Version: GnuPG v1.4.12 (GNU/Linux)
          Comment: GPGTools - http://gpgtools.org

          mQINBEw3u0ABEAC1+aJQpU59fwZ4mxFjqNCgfZgDhONDSYQFMRnYC1dzBpJHzI6b
          fUBQeaZ8rh6N4kZ+wq1eL86YDXkCt4sCvNTP0eF2XaOLbmxtV9bdpTIBep9bQiKg
          5iZaz+brUZlFk/MyJ0Yz//VQ68N1uvXccmD6uxQsVO+gx7rnarg/BGuCNaVtGwy+
          S98g8Begwxs9JmGa8pMCcSxtC7fAfAEZ02cYyrw5KfBvFI3cHDdBqrEJQKwKeLKY
          GHK3+H1TM4ZMxPsLuR/XKCbvTyl+OCPxU2OxPjufAxLlr8BWUzgJv6ztPe9imqpH
          Ppp3KuLFNorjPqWY5jSgKl94W/CO2x591e++a1PhwUn7iVUwVVe+mOEWnK5+Fd0v
          VMQebYCXS+3dNf6gxSvhz8etpw20T9Ytg4EdhLvCJRV/pYlqhcq+E9le1jFOHOc0
          Nc5FQweUtHGaNVyn8S1hvnvWJBMxpXq+Bezfk3X8PhPT/l9O2lLFOOO08jo0OYiI
          wrjhMQQOOSZOb3vBRvBZNnnxPrcdjUUm/9cVB8VcgI5KFhG7hmMCwH70tpUWcZCN
          NlI1wj/PJ7Tlxjy44f1o4CQ5FxuozkiITJvh9CTg+k3wEmiaGz65w9jRl9ny2gEl
          f4CR5+ba+w2dpuDeMwiHJIs5JsGyJjmA5/0xytB7QvgMs2q25vWhygsmUQARAQAB
          tEdQdXBwZXQgTGFicyBSZWxlYXNlIEtleSAoUHVwcGV0IExhYnMgUmVsZWFzZSBL
          ZXkpIDxpbmZvQHB1cHBldGxhYnMuY29tPokCPgQTAQIAKAUCTDe7QAIbAwUJA8Jn
          AAYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AACgkQEFS3okvW7DAZaw//aLmE/eob
          pXpIUVyCUWQxEvPtM/h/SAJsG3KoHN9u216ews+UHsL/7F91ceVXQQdD2e8CtYWF
          eLNM0RSM9i/KM60g4CvIQlmNqdqhi1HsgGqInZ72/XLAXun0gabfC36rLww2kel+
          aMpRf58SrSuskY321NnMEJl4OsHV2hfNtAIgw2e/zm9RhoMpGKxoHZCvFhnP7u2M
          2wMq7iNDDWb6dVsLpzdlVf242zCbubPCxxQXOpA56rzkUPuJ85mdVw4i19oPIFIZ
          VL5owit1SxCOxBg4b8oaMS36hEl3qtZG834rtLfcqAmqjhx6aJuJLOAYN84QjDEU
          3NI5IfNRMvluIeTcD4Dt5FCYahN045tW1Rc6s5GAR8RW45GYwQDzG+kkkeeGxwEh
          qCW7nOHuwZIoVJufNhd28UFn83KGJHCQt4NBBr3K5TcY6bDQEIrpSplWSDBbd3p1
          IaoZY1WSDdP9OTVOSbsz0JiglWmUWGWCdd/CMSW/D7/3VUOJOYRDwptvtSYcjJc8
          1UV+1zB+rt5La/OWe4UOORD+jU1ATijQEaFYxBbqBBkFboAEXq9btRQyegqk+eVp
          HhzacP5NYFTMThvHuTapNytcCso5au/cMywqCgY1DfcMJyjocu4bCtrAd6w4kGKN
          MUdwNDYQulHZDI+UjJInhramyngdzZLjdeGJARwEEAECAAYFAkw3wEYACgkQIVr+
          UOQUcDKvEwgAoBuOPnPioBwYp8oHVPTo/69cJn1225kfraUYGebCcrRwuoKd8Iyh
          R165nXYJmD8yrAFBk8ScUVKsQ/pSnqNrBCrlzQD6NQvuIWVFegIdjdasrWX6Szj+
          N1OllbzIJbkE5eo0WjCMEKJVI/GTY2AnTWUAm36PLQC5HnSATykqwxeZDsJ/s8Rc
          kd7+QN5sBVytG3qb45Q7jLJpLcJO6KYH4rz9ZgN7LzyyGbu9DypPrulADG9OrL7e
          lUnsGDG4E1M8Pkgk9Xv9MRKao1KjYLD5zxOoVtdeoKEQdnM+lWMJin1XvoqJY7FT
          DJk6o+cVqqHkdKL+sgsscFVQljgCEd0EgIkCHAQQAQgABgUCTPlA6QAKCRBcE9bb
          kwUuAxdYD/40FxAeNCYByxkr/XRT0gFT+NCjPuqPWCM5tf2NIhSapXtb2+32WbAf
          DzVfqWjC0G0RnQBve+vcjpY4/rJu4VKIDGIT8CtnKOIyEcXTNFOehi65xO4ypaei
          BPSb3ip3P0of1iZZDQrNHMW5VcyL1c+PWT/6exXSGsePtO/89tc6mupqZtC05f5Z
          XG4jswMF0U6Q5s3S0tG7Y+oQhKNFJS4sH4rHe1o5CxKwNRSzqccA0hptKy3MHUZ2
          +zeHzuRdRWGjb2rUiVxnIvPPBGxF2JHhB4ERhGgbTxRZ6wZbdW06BOE8r7pGrUpU
          fCw/WRT3gGXJHpGPOzFAvr3Xl7VcDUKTVmIajnpd3SoyD1t2XsvJlSQBOWbViucH
          dvE4SIKQ77vBLRlZIoXXVb6Wu7Vq+eQs1ybjwGOhnnKjz8llXcMnLzzN86STpjN4
          qGTXQy/E9+dyUP1sXn3RRwb+ZkdI77m1YY95QRNgG/hqh77IuWWg1MtTSgQnP+F2
          7mfo0/522hObhdAe73VO3ttEPiriWy7tw3bS9daP2TAVbYyFqkvptkBb1OXRUSzq
          UuWjBmZ35UlXjKQsGeUHlOiEh84aondF90A7gx0X/ktNIPRrfCGkHJcDu+HVnR7x
          Kk+F0qb9+/pGLiT3rqeQTr8fYsb4xLHT7uEg1gVFB1g0kd+RQHzV74kCPgQTAQIA
          KAIbAwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AFAk/x5PoFCQtIMjoACgkQEFS3
          okvW7DAIKQ/9HvZyf+LHVSkCk92Kb6gckniin3+5ooz67hSr8miGBfK4eocqQ0H7
          bdtWjAILzR/IBY0xj6OHKhYP2k8TLc7QhQjt0dRpNkX+Iton2AZryV7vUADreYz4
          4B0bPmhiE+LL46ET5IThLKu/KfihzkEEBa9/t178+dO9zCM2xsXaiDhMOxVE32gX
          vSZKP3hmvnK/FdylUY3nWtPedr+lHpBLoHGaPH7cjI+MEEugU3oAJ0jpq3V8n4w0
          jIq2V77wfmbD9byIV7dXcxApzciK+ekwpQNQMSaceuxLlTZKcdSqo0/qmS2A863Y
          ZQ0ZBe+Xyf5OI33+y+Mry+vl6Lre2VfPm3udgR10E4tWXJ9Q2CmG+zNPWt73U1FD
          7xBI7PPvOlyzCX4QJhy2Fn/fvzaNjHp4/FSiCw0HvX01epcersyun3xxPkRIjwwR
          M9m5MJ0o4hhPfa97zibXSh8XXBnosBQxeg6nEnb26eorVQbqGx0ruu/W2m5/JpUf
          REsFmNOBUbi8xlKNS5CZypH3Zh88EZiTFolOMEh+hT6s0l6znBAGGZ4m/Unacm5y
          DHmg7unCk4JyVopQ2KHMoqG886elu+rm0ASkhyqBAk9sWKptMl3NHiYTRE/m9VAk
          ugVIB2pi+8u84f+an4Hml4xlyijgYu05pqNvnLRyJDLd61hviLC8GYU=
          =a34C
          -----END PGP PUBLIC KEY BLOCK-----',
        }
        EOS

        shell('apt-key del 4BD6EC30', :acceptable_exit_codes => [0,1,2])
        apply_manifest(pp, :catch_failures => true)
      end

      describe file('/etc/apt/sources.list.d/puppetlabs.list') do
        it { should be_file }
      end
      describe 'keys should exist' do
        it 'finds puppetlabs key' do
          shell('apt-key list | grep 4BD6EC30')
        end
      end
    end
  end

  context 'key_source' do
    context 'http://apt.puppetlabs.com/pubkey.gpg' do
      it 'should work with no errors' do
        pp = <<-EOS
        include '::apt'
        apt::source { 'puppetlabs':
          ensure     => present,
          location   => 'http://apt.puppetlabs.com',
          release    => 'precise',
          repos      => 'main',
          key        => '4BD6EC30',
          key_source  => 'http://apt.puppetlabs.com/pubkey.gpg',
        }
        EOS

        shell('apt-key del 4BD6EC30', :acceptable_exit_codes => [0,1,2])
        apply_manifest(pp, :catch_failures => true)
      end

      describe file('/etc/apt/sources.list.d/puppetlabs.list') do
        it { should be_file }
        it { should contain 'deb http://apt.puppetlabs.com precise main' }
      end
      describe 'keys should exist' do
        it 'finds puppetlabs key' do
          shell('apt-key list | grep 4BD6EC30')
        end
      end
    end
  end

  context 'pin' do
    context 'false' do
      it 'should work with no errors' do
        pp = <<-EOS
        include '::apt'
        apt::source { 'puppetlabs':
          ensure     => present,
          location   => 'http://apt.puppetlabs.com',
          repos      => 'main',
          key        => '4BD6EC30',
          key_server => 'pgp.mit.edu',
          pin        => false,
        }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      describe file('/etc/apt/preferences.d/puppetlabs.pref') do
        it { should_not be_file }
      end
    end
    context 'true' do
      it 'should work with no errors' do
        pp = <<-EOS
        include '::apt'
        apt::source { 'puppetlabs':
          ensure     => present,
          location   => 'http://apt.puppetlabs.com',
          repos      => 'main',
          key        => '4BD6EC30',
          key_server => 'pgp.mit.edu',
          pin        => true,
        }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      describe file('/etc/apt/preferences.d/puppetlabs.pref') do
        it { should be_file }
      end
    end
  end

end
require 'spec_helper_acceptance'

describe 'apt class', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do

  context 'reset' do
    it 'fixes the sources.list' do
      shell('cp /etc/apt/sources.list /tmp')
    end
  end

  context 'always_apt_update => true' do
    it 'should work with no errors' do
      pp = <<-EOS
      class { 'apt': always_apt_update => true }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/apt_update/)
      end
    end
  end
  context 'always_apt_update => false' do
    it 'should work with no errors' do
      pp = <<-EOS
      class { 'apt': always_apt_update => false }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to_not match(/apt_update/)
      end
    end
  end

  # disable_keys drops in a 99unauth file to ignore keys in
  # other files.
  context 'disable_keys => true' do
    it 'should work with no errors' do
      pp = <<-EOS
      class { 'apt': disable_keys => true }
      EOS

      apply_manifest(pp, :catch_failures => true)
    end

    describe file('/etc/apt/apt.conf.d/99unauth') do
      it { should be_file }
      it { should contain 'APT::Get::AllowUnauthenticated 1;' }
    end
  end
  context 'disable_keys => false' do
    it 'should work with no errors' do
      pp = <<-EOS
      class { 'apt': disable_keys => false }
      EOS

      apply_manifest(pp, :catch_failures => true)
    end

    describe file('/etc/apt/apt.conf.d/99unauth') do
      it { should_not be_file }
    end
  end

  # proxy_host sets the proxy to use for transfers.
  # proxy_port sets the proxy port to use.
  context 'proxy settings' do
    it 'should work with no errors' do
      pp = <<-EOS
      class { 'apt': 
        proxy_host => 'localhost',
        proxy_port => '7042',
      }
      EOS

      apply_manifest(pp, :catch_failures => true)
    end

    describe file('/etc/apt/apt.conf.d/proxy') do
      it { should be_file }
      it { should contain 'Acquire::http::Proxy "http://localhost:7042\";' }
    end
  end

  context 'purge_sources' do
    it 'creates a fake apt file' do
      shell('touch /etc/apt/sources.list.d/fake.list')
      shell('echo "deb fake" >> /etc/apt/sources.list')
    end
    it 'purge_sources_list and purge_sources_list_d => true' do
      pp = <<-EOS
      class { 'apt':
        purge_sources_list   => true,
        purge_sources_list_d => true,
      }
      EOS

      apply_manifest(pp, :catch_failures => true)
    end

    describe file('/etc/apt/sources.list') do
      it { should_not contain 'deb fake' }
    end

    describe file('/etc/apt/sources.list.d/fake.list') do
      it { should_not be_file }
    end
  end
  context 'proxy settings' do
    it 'should work with no errors' do
      pp = <<-EOS
      class { 'apt': 
        proxy_host => 'localhost',
        proxy_port => '7042',
      }
      EOS

      apply_manifest(pp, :catch_failures => true)
    end

    describe file('/etc/apt/apt.conf.d/proxy') do
      it { should be_file }
      it { should contain 'Acquire::http::Proxy "http://localhost:7042\";' }
    end
  end

  context 'purge_sources' do
    context 'false' do
      it 'creates a fake apt file' do
        shell('touch /etc/apt/sources.list.d/fake.list')
        shell('echo "deb fake" >> /etc/apt/sources.list')
      end
      it 'purge_sources_list and purge_sources_list_d => false' do
        pp = <<-EOS
        class { 'apt':
          purge_sources_list   => false,
          purge_sources_list_d => false,
        }
        EOS

        apply_manifest(pp, :catch_failures => false)
      end

      describe file('/etc/apt/sources.list') do
        it { should contain 'deb fake' }
      end

      describe file('/etc/apt/sources.list.d/fake.list') do
        it { should be_file }
      end
    end

    context 'true' do
      it 'creates a fake apt file' do
        shell('touch /etc/apt/sources.list.d/fake.list')
        shell('echo "deb fake" >> /etc/apt/sources.list')
      end
      it 'purge_sources_list and purge_sources_list_d => true' do
        pp = <<-EOS
        class { 'apt':
          purge_sources_list   => true,
          purge_sources_list_d => true,
        }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      describe file('/etc/apt/sources.list') do
        it { should_not contain 'deb fake' }
      end

      describe file('/etc/apt/sources.list.d/fake.list') do
        it { should_not be_file }
      end
    end
  end

  context 'purge_preferences_d' do
    context 'false' do
      it 'creates a preferences file' do
        shell('touch /etc/apt/preferences.d/test')
      end

      it 'should work with no errors' do
        pp = <<-EOS
        class { 'apt': purge_preferences_d => false }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      describe file('/etc/apt/preferences.d/test') do
        it { should be_file }
      end
    end
    context 'true' do
      it 'creates a preferences file' do
        shell('touch /etc/apt/preferences.d/test')
      end

      it 'should work with no errors' do
        pp = <<-EOS
        class { 'apt': purge_preferences_d => true }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      describe file('/etc/apt/preferences.d/test') do
        it { should_not be_file }
      end
    end
  end

  context 'update_timeout' do
    context '5000' do
      it 'should work with no errors' do
        pp = <<-EOS
        class { 'apt': update_timeout => '5000' }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end
    end
  end

  context 'reset' do
    it 'fixes the sources.list' do
      shell('cp /tmp/sources.list /etc/apt')
    end
  end

end
require 'spec_helper_acceptance'

codename = fact('lsbdistcodename')
case fact('operatingsystem')
when 'Ubuntu'
  repos = 'main universe multiverse restricted'
when 'Debian'
  repos = 'main contrib non-free'
end

describe 'apt::backports class', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
  context 'defaults' do
    it 'should work with no errors' do
      pp = <<-EOS
      class { 'apt::backports': }
      EOS

      apply_manifest(pp, :catch_failures => true)
    end
  end

  context 'release' do
    it 'should work with no errors' do
      pp = <<-EOS
      class { 'apt::backports': release => '#{codename}' }
      EOS

      apply_manifest(pp, :catch_failures => true)
    end

    describe file('/etc/apt/sources.list.d/backports.list') do
      it { should be_file }
      it { should contain "#{codename}-backports #{repos}" }
    end
  end

  context 'location' do
    it 'should work with no errors' do
      pp = <<-EOS
      class { 'apt::backports': release => 'precise', location => 'http://localhost/ubuntu' }
      EOS

      apply_manifest(pp, :catch_failures => true)
    end

    describe file('/etc/apt/sources.list.d/backports.list') do
      it { should be_file }
      it { should contain "deb http://localhost/ubuntu precise-backports #{repos}" }
    end
  end

  context 'reset' do
    it 'deletes backport files' do
      shell('rm -rf /etc/apt/sources.list.d/backports.list')
      shell('rm -rf /etc/apt/preferences.d/backports.pref')
    end
  end

end
require 'spec_helper_acceptance'

describe 'apt class', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do

  context 'default parameters' do
    # Using puppet_apply as a helper
    it 'should work with no errors' do
      pp = <<-EOS
      class { 'apt': }
      EOS

      # Run it twice and test for idempotency
      apply_manifest(pp, :catch_failures => true)
      apply_manifest(pp, :catch_failures => true)
    end
  end
end
require 'spec_helper_acceptance'

describe 'apt::conf define', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
  context 'defaults' do
    it 'should work with no errors' do
      pp = <<-EOS
      apt::conf { 'test':
        content => 'test',
      }
      EOS

      apply_manifest(pp, :catch_failures => true)
    end

    describe file('/etc/apt/apt.conf.d/50test') do
      it { should be_file }
      it { should contain 'test' }
    end
  end

  context 'ensure' do
    context 'absent' do
      it 'should work with no errors' do
        pp = <<-EOS
        apt::conf { 'test':
          ensure  => absent,
          content => 'test',
        }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      describe file('/etc/apt/apt.conf.d/50test') do
        it { should_not be_file }
      end
    end
  end

  context 'priority' do
    context '99' do
      it 'should work with no errors' do
        pp = <<-EOS
        apt::conf { 'test':
          ensure   => present,
          content  => 'test',
          priority => '99',
        }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      describe file('/etc/apt/apt.conf.d/99test') do
        it { should be_file }
        it { should contain 'test' }
      end
    end
  end

  context 'cleanup' do
    it 'deletes 99test' do
      shell ('rm -rf /etc/apt/apt.conf.d/99test')
    end
  end
end
require 'spec_helper_acceptance'

codename = fact('lsbdistcodename')

describe 'apt::force define', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
  context 'defaults' do
    it 'should work with no errors' do
      pp = <<-EOS
      include apt
      apt::force { 'vim': release => false, }
      EOS

      shell('apt-get remove -y vim')
      apply_manifest(pp, :catch_failures => true)
    end

    describe package('vim') do
      it { should be_installed }
    end
  end

  context 'release' do
    it 'should work with no errors' do
      pp = <<-EOS
      include apt
      apt::force { 'vim': release => '#{codename}' }
      EOS

      shell('apt-get remove -y vim')
      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/apt-get -y -t #{codename} install vim/)
      end
    end

    describe package('vim') do
      it { should be_installed }
    end
  end

  context 'version' do
    it 'should work with no errors' do
      pp = <<-EOS
      include apt
      apt::force { 'vim': version => '1.1.1', release => false, }
      EOS

      shell('apt-get remove -y vim')
      apply_manifest(pp, :catch_failures => false) do |r|
        expect(r.stdout).to match(/apt-get -y  install vim=1.1.1/)
      end
    end

    describe package('vim') do
      it { should_not be_installed }
    end
  end

  context 'timeout' do
    it 'should work with no errors' do
      pp = <<-EOS
      include apt
      apt::force { 'vim': release => false, timeout => '1' }
      EOS

      shell('apt-get clean')
      apply_manifest(pp, :expect_failures => true) do |r|
        expect(r.stderr).to match(/Error: Command exceeded timeout/)
      end
    end

    describe package('vim') do
      it { should_not be_installed }
    end
  end

end
HOSTS:
  debian-70rc1-x64:
    roles:
      - master
    platform: debian-70rc1-x64
    box : debian-70rc1-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/debian-70rc1-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: foss
HOSTS:
  ubuntu-server-12042-x64:
    roles:
      - master
    platform: ubuntu-server-12.04-amd64
    box : ubuntu-server-12042-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/ubuntu-server-12042-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: foss
HOSTS:
  ubuntu-server-10044-x64:
    roles:
      - master
    platform: ubuntu-10.04-amd64
    box : ubuntu-server-10044-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/ubuntu-server-10044-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  log_level: debug
  type: git
HOSTS:
  ubuntu-server-12042-x64:
    roles:
      - master
    platform: ubuntu-server-12.04-amd64
    box : ubuntu-server-12042-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/ubuntu-server-12042-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: foss
require 'spec_helper_acceptance'

describe 'apt::pin define', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
  context 'defaults' do
    it 'should work with no errors' do
      pp = <<-EOS
      include apt
      apt::pin { 'vim-puppet': }
      EOS

      apply_manifest(pp, :catch_failures => true)
    end

    describe file('/etc/apt/preferences.d/vim-puppet.pref') do
      it { should be_file }
      it { should contain 'Pin: release a=vim-puppet' }
    end
  end

  context 'ensure' do
    context 'present' do
      it 'should work with no errors' do
        pp = <<-EOS
        include apt
        apt::pin { 'vim-puppet': ensure => present }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      describe file('/etc/apt/preferences.d/vim-puppet.pref') do
        it { should be_file }
        it { should contain 'Pin: release a=vim-puppet' }
      end
    end

    context 'absent' do
      it 'should work with no errors' do
        pp = <<-EOS
        include apt
        apt::pin { 'vim-puppet': ensure => absent }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      describe file('/etc/apt/preferences.d/vim-puppet.pref') do
        it { should_not be_file }
      end
    end
  end

  context 'order' do
    context '99' do
      it 'should work with no errors' do
        pp = <<-EOS
        include apt
        apt::pin { 'vim-puppet':
          ensure => present,
          order  => '99',
        }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      describe file('/etc/apt/preferences.d/99-vim-puppet.pref') do
        it { should be_file }
        it { should contain 'Pin: release a=vim-puppet' }
      end
    end
  end

  context 'packages' do
    context 'test' do
      it 'should work with no errors' do
        pp = <<-EOS
        include apt
        apt::pin { 'vim-puppet':
          ensure   => present,
          packages => 'test',
        }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      describe file('/etc/apt/preferences.d/vim-puppet.pref') do
        it { should be_file }
        it { should contain 'Package: test' }
        it { should contain 'Pin: release a=vim-puppet' }
      end
    end
  end

  context 'release' do
    context 'testrelease' do
      it 'should work with no errors' do
        pp = <<-EOS
        include apt
        apt::pin { 'vim-puppet':
          ensure  => present,
          release => 'testrelease',
        }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      describe file('/etc/apt/preferences.d/vim-puppet.pref') do
        it { should be_file }
        it { should contain 'Pin: release a=testrelease' }
      end
    end
  end

  context 'origin' do
    context 'testrelease' do
      it 'should work with no errors' do
        pp = <<-EOS
        include apt
        apt::pin { 'vim-puppet':
          ensure  => present,
          origin  => 'testrelease',
        }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      describe file('/etc/apt/preferences.d/vim-puppet.pref') do
        it { should be_file }
        it { should contain 'Pin: origin testrelease' }
      end
    end
  end

  context 'version' do
    context '1.0.0' do
      it 'should work with no errors' do
        pp = <<-EOS
        include apt
        apt::pin { 'vim-puppet':
          ensure   => present,
          packages => 'test',
          version  => '1.0.0',
        }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      describe file('/etc/apt/preferences.d/vim-puppet.pref') do
        it { should be_file }
        it { should contain 'Package: test' }
        it { should contain 'Pin: version 1.0.0' }
      end
    end
  end

  context 'codename' do
    context 'testname' do
      it 'should work with no errors' do
        pp = <<-EOS
        include apt
        apt::pin { 'vim-puppet':
          ensure   => present,
          codename => 'testname',
        }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      describe file('/etc/apt/preferences.d/vim-puppet.pref') do
        it { should be_file }
        it { should contain 'Pin: release n=testname' }
      end
    end
  end

  context 'release_version' do
    context '1.1.1' do
      it 'should work with no errors' do
        pp = <<-EOS
        include apt
        apt::pin { 'vim-puppet':
          ensure          => present,
          release_version => '1.1.1',
        }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      describe file('/etc/apt/preferences.d/vim-puppet.pref') do
        it { should be_file }
        it { should contain 'Pin: release v=1.1.1' }
      end
    end
  end

  context 'component' do
    context 'testcomponent' do
      it 'should work with no errors' do
        pp = <<-EOS
        include apt
        apt::pin { 'vim-puppet':
          ensure    => present,
          component => 'testcomponent',
        }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      describe file('/etc/apt/preferences.d/vim-puppet.pref') do
        it { should be_file }
        it { should contain 'Pin: release c=testcomponent' }
      end
    end
  end

  context 'originator' do
    context 'testorigin' do
      it 'should work with no errors' do
        pp = <<-EOS
        include apt
        apt::pin { 'vim-puppet':
          ensure     => present,
          originator => 'testorigin',
        }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      describe file('/etc/apt/preferences.d/vim-puppet.pref') do
        it { should be_file }
        it { should contain 'Pin: release o=testorigin' }
      end
    end
  end

  context 'label' do
    context 'testlabel' do
      it 'should work with no errors' do
        pp = <<-EOS
        include apt
        apt::pin { 'vim-puppet':
          ensure => present,
          label  => 'testlabel',
        }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      describe file('/etc/apt/preferences.d/vim-puppet.pref') do
        it { should be_file }
        it { should contain 'Pin: release l=testlabel' }
      end
    end
  end

end
require 'spec_helper_acceptance'

describe 'apt::release class', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
  context 'release_id' do
    it 'should work with no errors' do
      pp = <<-EOS
      include apt
      class { 'apt::release': release_id => 'precise', }
      EOS

      apply_manifest(pp, :catch_failures => true)
    end

    describe file('/etc/apt/apt.conf.d/01release') do
      it { should be_file }
      it { should contain 'APT::Default-Release "precise";' }
    end
  end

  context 'reset' do
    it 'cleans up' do
      shell('rm -rf /etc/apt/apt.conf.d/01release')
    end
  end

end
require 'spec_helper_acceptance'

describe 'apt::unattended_upgrades class', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
  context 'defaults' do
    it 'should work with no errors' do
      pp = <<-EOS
      include apt
      include apt::unattended_upgrades
      EOS

      # Attempted workaround for problems seen on debian with
      # something holding the package database open.
      #shell('killall -9 apt-get')
      #shell('killall -9 dpkg')
      apply_manifest(pp, :catch_failures => true)
    end

    describe file('/etc/apt/apt.conf.d/10periodic') do
      it { should be_file }
    end
    describe file('/etc/apt/apt.conf.d/50unattended-upgrades') do
      it { should be_file }
    end
  end

  context 'origins' do
    it 'should work with no errors' do
      pp = <<-EOS
      include apt
      class { 'apt::unattended_upgrades':
        origins => ['${distro_id}:${distro_codename}-test'],
      }
      EOS

      apply_manifest(pp, :catch_failures => true)
    end

    describe file('/etc/apt/apt.conf.d/50unattended-upgrades') do
      it { should be_file }
      it { should contain '${distro_id}:${distro_codename}-test' }
    end
  end

  context 'blacklist' do
    it 'should work with no errors' do
      pp = <<-EOS
      include apt
      class { 'apt::unattended_upgrades':
        blacklist => ['puppet']
      }
      EOS

      apply_manifest(pp, :catch_failures => true)
    end

    describe file('/etc/apt/apt.conf.d/50unattended-upgrades') do
      it { should be_file }
      it { should contain 'puppet' }
    end
  end

  context 'update' do
    it 'should work with no errors' do
      pp = <<-EOS
      include apt
      class { 'apt::unattended_upgrades':
        update => '99'
      }
      EOS

      apply_manifest(pp, :catch_failures => true)
    end

    describe file('/etc/apt/apt.conf.d/10periodic') do
      it { should be_file }
      it { should contain 'APT::Periodic::Update-Package-Lists "99";' }
    end
  end

  context 'download' do
    it 'should work with no errors' do
      pp = <<-EOS
      include apt
      class { 'apt::unattended_upgrades':
        download => '99'
      }
      EOS

      apply_manifest(pp, :catch_failures => true)
    end

    describe file('/etc/apt/apt.conf.d/10periodic') do
      it { should be_file }
      it { should contain 'APT::Periodic::Download-Upgradeable-Packages "99";' }
    end
  end

  context 'upgrade' do
    it 'should work with no errors' do
      pp = <<-EOS
      include apt
      class { 'apt::unattended_upgrades':
        upgrade => '99'
      }
      EOS

      apply_manifest(pp, :catch_failures => true)
    end

    describe file('/etc/apt/apt.conf.d/10periodic') do
      it { should be_file }
      it { should contain 'APT::Periodic::Unattended-Upgrade "99";' }
    end
  end

  context 'autoclean' do
    it 'should work with no errors' do
      pp = <<-EOS
      include apt
      class { 'apt::unattended_upgrades':
        autoclean => '99'
      }
      EOS

      apply_manifest(pp, :catch_failures => true)
    end

    describe file('/etc/apt/apt.conf.d/10periodic') do
      it { should be_file }
      it { should contain 'APT::Periodic::AutocleanInterval "99";' }
    end
  end

  context 'auto_fix' do
    context 'true' do
      it 'should work with no errors' do
        pp = <<-EOS
        include apt
        class { 'apt::unattended_upgrades':
          auto_fix => true
        }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      describe file('/etc/apt/apt.conf.d/50unattended-upgrades') do
        it { should be_file }
        it { should contain 'Unattended-Upgrade::AutoFixInterruptedDpkg "true";' }
      end
    end

    context 'false' do
      it 'should work with no errors' do
        pp = <<-EOS
        include apt
        class { 'apt::unattended_upgrades':
          auto_fix => false
        }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      describe file('/etc/apt/apt.conf.d/50unattended-upgrades') do
        it { should be_file }
        it { should contain 'Unattended-Upgrade::AutoFixInterruptedDpkg "false";' }
      end
    end
  end

  context 'minimal_steps' do
    context 'true' do
      it 'should work with no errors' do
        pp = <<-EOS
        include apt
        class { 'apt::unattended_upgrades':
          minimal_steps => true
        }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      describe file('/etc/apt/apt.conf.d/50unattended-upgrades') do
        it { should be_file }
        it { should contain 'Unattended-Upgrade::MinimalSteps "true";' }
      end
    end

    context 'false' do
      it 'should work with no errors' do
        pp = <<-EOS
        include apt
        class { 'apt::unattended_upgrades':
          minimal_steps => false
        }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      describe file('/etc/apt/apt.conf.d/50unattended-upgrades') do
        it { should be_file }
        it { should contain 'Unattended-Upgrade::MinimalSteps "false";' }
      end
    end
  end

  context 'install_on_shutdown' do
    context 'true' do
      it 'should work with no errors' do
        pp = <<-EOS
        include apt
        class { 'apt::unattended_upgrades':
          install_on_shutdown => true
        }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      describe file('/etc/apt/apt.conf.d/50unattended-upgrades') do
        it { should be_file }
        it { should contain 'Unattended-Upgrade::InstallOnShutdown "true";' }
      end
    end

    context 'false' do
      it 'should work with no errors' do
        pp = <<-EOS
        include apt
        class { 'apt::unattended_upgrades':
          install_on_shutdown => false
        }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      describe file('/etc/apt/apt.conf.d/50unattended-upgrades') do
        it { should be_file }
        it { should contain 'Unattended-Upgrade::InstallOnShutdown "false";' }
      end
    end
  end

  context 'mail_to' do
    it 'should work with no errors' do
      pp = <<-EOS
      include apt
      class { 'apt::unattended_upgrades':
        mail_to => 'test@example.com'
      }
      EOS

      apply_manifest(pp, :catch_failures => true)
    end

    describe file('/etc/apt/apt.conf.d/50unattended-upgrades') do
      it { should be_file }
      it { should contain 'Unattended-Upgrade::Mail "test@example.com";' }
    end
  end

  context 'mail_only_on_error' do
    context 'true' do
      it 'should work with no errors' do
        pp = <<-EOS
        include apt
        class { 'apt::unattended_upgrades':
          mail_to            => 'test@example.com',
          mail_only_on_error => true
        }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      describe file('/etc/apt/apt.conf.d/50unattended-upgrades') do
        it { should be_file }
        it { should contain 'Unattended-Upgrade::MailOnlyOnError "true";' }
      end
    end

    context 'false' do
      it 'should work with no errors' do
        pp = <<-EOS
        include apt
        class { 'apt::unattended_upgrades':
          mail_to            => 'test@example.com',
          mail_only_on_error => false,
        }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      describe file('/etc/apt/apt.conf.d/50unattended-upgrades') do
        it { should be_file }
        it { should contain 'Unattended-Upgrade::MailOnlyOnError "false";' }
      end
    end

    context 'mail_to missing' do
      it 'should work with no errors' do
        pp = <<-EOS
        include apt
        class { 'apt::unattended_upgrades':
          mail_only_on_error => true,
        }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      describe file('/etc/apt/apt.conf.d/50unattended-upgrades') do
        it { should be_file }
        it { should_not contain 'Unattended-Upgrade::MailOnlyOnError "true";' }
      end
    end
  end

  context 'remove_unused' do
    context 'true' do
      it 'should work with no errors' do
        pp = <<-EOS
        include apt
        class { 'apt::unattended_upgrades':
          remove_unused => true
        }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      describe file('/etc/apt/apt.conf.d/50unattended-upgrades') do
        it { should be_file }
        it { should contain 'Unattended-Upgrade::Remove-Unused-Dependencies "true";' }
      end
    end

    context 'false' do
      it 'should work with no errors' do
        pp = <<-EOS
        include apt
        class { 'apt::unattended_upgrades':
          remove_unused => false,
        }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      describe file('/etc/apt/apt.conf.d/50unattended-upgrades') do
        it { should be_file }
        it { should contain 'Unattended-Upgrade::Remove-Unused-Dependencies "false";' }
      end
    end
  end

  context 'auto_reboot' do
    context 'true' do
      it 'should work with no errors' do
        pp = <<-EOS
        include apt
        class { 'apt::unattended_upgrades':
          auto_reboot => true
        }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      describe file('/etc/apt/apt.conf.d/50unattended-upgrades') do
        it { should be_file }
        it { should contain 'Unattended-Upgrade::Automatic-Reboot "true";' }
      end
    end

    context 'false' do
      it 'should work with no errors' do
        pp = <<-EOS
        include apt
        class { 'apt::unattended_upgrades':
          auto_reboot => false,
        }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      describe file('/etc/apt/apt.conf.d/50unattended-upgrades') do
        it { should be_file }
        it { should contain 'Unattended-Upgrade::Automatic-Reboot "false";' }
      end
    end
  end

  context 'dl_limit' do
    it 'should work with no errors' do
      pp = <<-EOS
      include apt
      class { 'apt::unattended_upgrades':
        dl_limit => '99'
      }
      EOS

      apply_manifest(pp, :catch_failures => true)
    end

    describe file('/etc/apt/apt.conf.d/50unattended-upgrades') do
      it { should be_file }
      it { should contain 'Acquire::http::Dl-Limit "99"' }
    end
  end

  context 'enable' do
    it 'should work with no errors' do
      pp = <<-EOS
      include apt
      class { 'apt::unattended_upgrades':
        enable => '2'
      }
      EOS

      apply_manifest(pp, :catch_failures => true)
    end

    describe file('/etc/apt/apt.conf.d/10periodic') do
      it { should be_file }
      it { should contain 'APT::Periodic::Enable "2"' }
    end
  end

  context 'backup_interval' do
    it 'should work with no errors' do
      pp = <<-EOS
      include apt
      class { 'apt::unattended_upgrades':
        backup_interval => '2'
      }
      EOS

      apply_manifest(pp, :catch_failures => true)
    end

    describe file('/etc/apt/apt.conf.d/10periodic') do
      it { should be_file }
      it { should contain 'APT::Periodic::BackUpArchiveInterval "2";' }
    end
  end

  context 'backup_level' do
    it 'should work with no errors' do
      pp = <<-EOS
      include apt
      class { 'apt::unattended_upgrades':
        backup_level => '2'
      }
      EOS

      apply_manifest(pp, :catch_failures => true)
    end

    describe file('/etc/apt/apt.conf.d/10periodic') do
      it { should be_file }
      it { should contain 'APT::Periodic::BackUpLevel "2";' }
    end
  end

  context 'max_age' do
    it 'should work with no errors' do
      pp = <<-EOS
      include apt
      class { 'apt::unattended_upgrades':
        max_age => '2'
      }
      EOS

      apply_manifest(pp, :catch_failures => true)
    end

    describe file('/etc/apt/apt.conf.d/10periodic') do
      it { should be_file }
      it { should contain 'APT::Periodic::MaxAge "2";' }
    end
  end

  context 'min_age' do
    it 'should work with no errors' do
      pp = <<-EOS
      include apt
      class { 'apt::unattended_upgrades':
        min_age => '2'
      }
      EOS

      apply_manifest(pp, :catch_failures => true)
    end

    describe file('/etc/apt/apt.conf.d/10periodic') do
      it { should be_file }
      it { should contain 'APT::Periodic::MinAge "2";' }
    end
  end

  context 'max_size' do
    it 'should work with no errors' do
      pp = <<-EOS
      include apt
      class { 'apt::unattended_upgrades':
        max_size => '2'
      }
      EOS

      apply_manifest(pp, :catch_failures => true)
    end

    describe file('/etc/apt/apt.conf.d/10periodic') do
      it { should be_file }
      it { should contain 'APT::Periodic::MaxSize "2";' }
    end
  end

  context 'download_delta' do
    it 'should work with no errors' do
      pp = <<-EOS
      include apt
      class { 'apt::unattended_upgrades':
        download_delta => '2'
      }
      EOS

      apply_manifest(pp, :catch_failures => true)
    end

    describe file('/etc/apt/apt.conf.d/10periodic') do
      it { should be_file }
      it { should contain 'APT::Periodic::Download-Upgradeable-Packages-Debdelta "2";' }
    end
  end

  context 'verbose' do
    it 'should work with no errors' do
      pp = <<-EOS
      include apt
      class { 'apt::unattended_upgrades':
        verbose => '2'
      }
      EOS

      apply_manifest(pp, :catch_failures => true)
    end

    describe file('/etc/apt/apt.conf.d/10periodic') do
      it { should be_file }
      it { should contain 'APT::Periodic::Verbose "2";' }
    end
  end

end
require 'spec_helper_acceptance'

describe 'unsupported distributions and OSes', :if => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
  it 'class apt fails' do
    pp = <<-EOS
      class { 'apt': }
    EOS
    expect(apply_manifest(pp, :expect_failures => true).stderr).to match(/unsupported/i)
  end
end
require 'spec_helper'
describe 'apt', :type => :class do
  let(:facts) { { :lsbdistid => 'Debian' } }
  let :default_params do
    {
      :disable_keys => :undef,
      :always_apt_update => false,
      :purge_sources_list => false,
      :purge_sources_list_d => false,
    }
  end

  [{},
    {
      :disable_keys => true,
      :always_apt_update => true,
      :proxy_host => true,
      :proxy_port => '3128',
      :purge_sources_list => true,
      :purge_sources_list_d => true,
    },
    {
      :disable_keys => false
    }
  ].each do |param_set|
    describe "when #{param_set == {} ? "using default" : "specifying"} class parameters" do
      let :param_hash do
        default_params.merge(param_set)
      end

      let :params do
        param_set
      end

      let :refresh_only_apt_update do
        if param_hash[:always_apt_update]
          false
        else
          true
        end
      end

      it { should contain_class("apt::params") }

      it {
        if param_hash[:purge_sources_list]
        should contain_file("sources.list").with({
            'path'    => "/etc/apt/sources.list",
            'ensure'  => "present",
            'owner'   => "root",
            'group'   => "root",
            'mode'    => "0644",
            "content" => "# Repos managed by puppet.\n"
          })
        else
        should contain_file("sources.list").with({
            'path'    => "/etc/apt/sources.list",
            'ensure'  => "present",
            'owner'   => "root",
            'group'   => "root",
            'mode'    => "0644",
            'content' => nil
          })
        end
      }
      it {
        if param_hash[:purge_sources_list_d]
          should create_file("sources.list.d").with({
            'path'    => "/etc/apt/sources.list.d",
            'ensure'  => "directory",
            'owner'   => "root",
            'group'   => "root",
            'purge'   => true,
            'recurse' => true,
            'notify'  => 'Exec[apt_update]'
          })
        else
          should create_file("sources.list.d").with({
            'path'    => "/etc/apt/sources.list.d",
            'ensure'  => "directory",
            'owner'   => "root",
            'group'   => "root",
            'purge'   => false,
            'recurse' => false,
            'notify'  => 'Exec[apt_update]'
          })
        end
      }

      it {
        should contain_exec("apt_update").with({
          'command'     => "/usr/bin/apt-get update",
          'refreshonly' => refresh_only_apt_update
        })
      }

      it {
        if param_hash[:disable_keys] == true
          should create_file("99unauth").with({
            'content' => "APT::Get::AllowUnauthenticated 1;\n",
            'ensure'  => "present",
            'path'    => "/etc/apt/apt.conf.d/99unauth"
          })
        elsif param_hash[:disable_keys] == false
          should create_file("99unauth").with({
            'ensure' => "absent",
            'path'   => "/etc/apt/apt.conf.d/99unauth"
          })
        elsif param_hash[:disable_keys] != :undef
          should_not create_file("99unauth").with({
            'path'   => "/etc/apt/apt.conf.d/99unauth"
          })
        end
      }
      describe 'when setting a proxy' do
        it {
          if param_hash[:proxy_host]
            should contain_file('configure-apt-proxy').with(
              'path'    => '/etc/apt/apt.conf.d/proxy',
              'content' => "Acquire::http::Proxy \"http://#{param_hash[:proxy_host]}:#{param_hash[:proxy_port]}\";",
              'notify'  => "Exec[apt_update]"
            )
          else
            should contain_file('configure-apt-proxy').with(
              'path'    => '/etc/apt/apt.conf.d/proxy',
              'notify'  => 'Exec[apt_update]',
              'ensure'  => 'absent'
            )
          end
        }
      end
    end
  end
end
require 'spec_helper'
describe 'apt::backports', :type => :class do

  describe 'when turning on backports for ubuntu karmic' do

    let :facts do
      {
        'lsbdistcodename' => 'Karmic',
        'lsbdistid'       => 'Ubuntu'
      }
    end

    it { should contain_apt__source('backports').with({
        'location'   => 'http://old-releases.ubuntu.com/ubuntu',
        'release'    => 'karmic-backports',
        'repos'      => 'main universe multiverse restricted',
        'key'        => '437D05B5',
        'key_server' => 'pgp.mit.edu',
        'pin'        => '200',
      })
    }
  end

  describe "when turning on backports for debian squeeze" do

    let :facts do
      {
        'lsbdistcodename' => 'Squeeze',
        'lsbdistid'       => 'Debian',
      }
    end

    it { should contain_apt__source('backports').with({
        'location'   => 'http://backports.debian.org/debian-backports',
        'release'    => 'squeeze-backports',
        'repos'      => 'main contrib non-free',
        'key'        => '46925553',
        'key_server' => 'pgp.mit.edu',
        'pin'        => '200',
      })
    }
  end

  describe "when turning on backports for debian squeeze but using your own mirror" do

    let :facts do
      {
        'lsbdistcodename' => 'Squeeze',
        'lsbdistid'       => 'Debian'
      }
    end

    let :location do
      'http://mirrors.example.com/debian-backports'
    end

    let :params do
      { 'location' => location }
    end

    it { should contain_apt__source('backports').with({
        'location'   => location,
        'release'    => 'squeeze-backports',
        'repos'      => 'main contrib non-free',
        'key'        => '46925553',
        'key_server' => 'pgp.mit.edu',
        'pin'        => '200',
      })
    }
  end
end
require 'spec_helper'
describe 'apt::debian::testing', :type => :class do
  let(:facts) { { :lsbdistid => 'Debian' } }
  it {
    should contain_apt__source("debian_testing").with({
      "location"            => "http://debian.mirror.iweb.ca/debian/",
      "release"             => "testing",
      "repos"               => "main contrib non-free",
      "required_packages"   => "debian-keyring debian-archive-keyring",
      "key"                 => "46925553",
      "key_server"          => "subkeys.pgp.net",
      "pin"                 => "-10"
    })
  }
end
require 'spec_helper'
describe 'apt::debian::unstable', :type => :class do
  let(:facts) { { :lsbdistid => 'Debian' } }
  it {
    should contain_apt__source("debian_unstable").with({
      "location"          => "http://debian.mirror.iweb.ca/debian/",
      "release"           => "unstable",
      "repos"             => "main contrib non-free",
      "required_packages" => "debian-keyring debian-archive-keyring",
      "key"               => "46925553",
      "key_server"        => "subkeys.pgp.net",
      "pin"               => "-10"
    })
  }
end
require 'spec_helper'
describe 'apt::params', :type => :class do
  let(:facts) { { :lsbdistid => 'Debian' } }
  let (:title) { 'my_package' }

  it { should contain_apt__params }

  # There are 4 resources in this class currently
  # there should not be any more resources because it is a params class
  # The resources are class[apt::params], class[main], class[settings], stage[main]
  it "Should not contain any resources" do
    subject.resources.size.should == 4
  end
end
require 'spec_helper'
describe 'apt::release', :type => :class do
  let(:facts) { { :lsbdistid => 'Debian' } }
  let (:title) { 'my_package' }

  let :param_set do
    { :release_id => 'precise' }
  end

  let (:params) { param_set }

  it { should contain_class("apt::params") }

  it {
    should contain_file("/etc/apt/apt.conf.d/01release").with({
      "mode"    => "0644",
      "owner"   => "root",
      "group"   => "root",
      "content" => "APT::Default-Release \"#{param_set[:release_id]}\";"
    })
  }
end

require 'spec_helper'
describe 'apt::unattended_upgrades', :type => :class do
  let(:file_unattended) { '/etc/apt/apt.conf.d/50unattended-upgrades' }
  let(:file_periodic) { '/etc/apt/apt.conf.d/10periodic' }
  let(:facts) { { :lsbdistid => 'Debian' } }

  it { should contain_package("unattended-upgrades") }

  it {
    should create_file("/etc/apt/apt.conf.d/50unattended-upgrades").with({
      "owner"   => "root",
      "group"   => "root",
      "mode"    => "0644",
      "require" => "Package[unattended-upgrades]",
    })
  }

  it {
    should create_file("/etc/apt/apt.conf.d/10periodic").with({
      "owner"   => "root",
      "group"   => "root",
      "mode"    => "0644",
      "require" => "Package[unattended-upgrades]",
    })
  }

  describe "origins" do
    describe "with param defaults" do
      let(:params) {{ }}
      it { should contain_file(file_unattended).with_content(/^Unattended-Upgrade::Allowed-Origins \{\n\t"\$\{distro_id\}:\$\{distro_codename\}-security";\n\};$/) }
    end

    describe "with origins => ['ubuntu:precise-security']" do
      let :params do
        { :origins => ['ubuntu:precise-security'] }
      end
      it { should contain_file(file_unattended).with_content(/^Unattended-Upgrade::Allowed-Origins \{\n\t"ubuntu:precise-security";\n\};$/) }
    end
  end

  describe "blacklist" do
    describe "with param defaults" do
      let(:params) {{ }}
      it { should contain_file(file_unattended).with_content(/^Unattended-Upgrade::Package-Blacklist \{\n\};$/) }
    end

    describe "with blacklist => []" do
      let :params do
        { :blacklist => ['libc6', 'libc6-dev'] }
      end
      it { should contain_file(file_unattended).with_content(/^Unattended-Upgrade::Package-Blacklist \{\n\t"libc6";\n\t"libc6-dev";\n\};$/) }
    end
  end

  describe "with update => 2" do
    let :params do
      { :update => "2" }
    end
    it { should contain_file(file_periodic).with_content(/^APT::Periodic::Update-Package-Lists "2";$/) }
  end

  describe "with download => 2" do
    let :params do
      { :download => "2" }
    end
    it { should contain_file(file_periodic).with_content(/^APT::Periodic::Download-Upgradeable-Packages "2";$/) }
  end

  describe "with upgrade => 2" do
    let :params do
      { :upgrade => "2" }
    end
    it { should contain_file(file_periodic).with_content(/^APT::Periodic::Unattended-Upgrade "2";$/) }
  end

  describe "with autoclean => 2" do
    let :params do
      { :autoclean => "2" }
    end
    it { should contain_file(file_periodic).with_content(/^APT::Periodic::AutocleanInterval "2";$/) }
  end

  describe "with auto_fix => false" do
    let :params do
      { :auto_fix => false }
    end
    it { should contain_file(file_unattended).with_content(/^Unattended-Upgrade::AutoFixInterruptedDpkg "false";$/) }
  end

  describe "with minimal_steps => true" do
    let :params do
      { :minimal_steps => true }
    end
    it { should contain_file(file_unattended).with_content(/^Unattended-Upgrade::MinimalSteps "true";$/) }
  end

  describe "with install_on_shutdown => true" do
    let :params do
      { :install_on_shutdown => true }
    end
    it { should contain_file(file_unattended).with_content(/^Unattended-Upgrade::InstallOnShutdown "true";$/) }
  end

  describe "mail_to" do
    describe "param defaults" do
      let(:params) {{ }}
      it { should_not contain_file(file_unattended).with_content(/^Unattended-Upgrade::Mail /) }
      it { should_not contain_file(file_unattended).with_content(/^Unattended-Upgrade::MailOnlyOnError /) }
    end

    describe "with mail_to => user@website, mail_only_on_error => true" do
      let :params do
        { :mail_to => "user@website",
          :mail_only_on_error => true }
      end
      it { should contain_file(file_unattended).with_content(/^Unattended-Upgrade::Mail "user@website";$/) }
      it { should contain_file(file_unattended).with_content(/^Unattended-Upgrade::MailOnlyOnError "true";$/) }
    end
  end

  describe "with remove_unused => false" do
    let :params do
      { :remove_unused => false }
    end
    it { should contain_file(file_unattended).with_content(/^Unattended-Upgrade::Remove-Unused-Dependencies "false";$/) }
  end

  describe "with auto_reboot => true" do
    let :params do
      { :auto_reboot => true }
    end
    it { should contain_file(file_unattended).with_content(/^Unattended-Upgrade::Automatic-Reboot "true";$/) }
  end

  describe "dl_limit" do
    describe "param defaults" do
      let(:params) {{ }}
      it { should_not contain_file(file_unattended).with_content(/^Acquire::http::Dl-Limit /) }
    end

    describe "with dl_limit => 70" do
      let :params do
        { :dl_limit => "70" }
      end
      it { should contain_file(file_unattended).with_content(/^Acquire::http::Dl-Limit "70";$/) }
    end
  end

  describe "with enable => 0" do
    let :params do
      { :enable => "0" }
    end
    it { should contain_file(file_periodic).with_content(/^APT::Periodic::Enable "0";$/) }
  end

  describe "with backup_interval => 1" do
    let :params do
      { :backup_interval => "1" }
    end
    it { should contain_file(file_periodic).with_content(/^APT::Periodic::BackUpArchiveInterval "1";$/) }
  end

  describe "with backup_level => 0" do
    let :params do
      { :backup_level => "0" }
    end
    it { should contain_file(file_periodic).with_content(/^APT::Periodic::BackUpLevel "0";$/) }
  end

  describe "with max_age => 1" do
    let :params do
      { :max_age => "1" }
    end
    it { should contain_file(file_periodic).with_content(/^APT::Periodic::MaxAge "1";$/) }
  end

  describe "with min_age => 1" do
    let :params do
      { :min_age => "1" }
    end
    it { should contain_file(file_periodic).with_content(/^APT::Periodic::MinAge "1";$/) }
  end

  describe "with max_size => 1" do
    let :params do
      { :max_size => "1" }
    end
    it { should contain_file(file_periodic).with_content(/^APT::Periodic::MaxSize "1";$/) }
  end

  describe "with download_delta => 2" do
    let :params do
      { :download_delta => "2" }
    end
    it { should contain_file(file_periodic).with_content(/^APT::Periodic::Download-Upgradeable-Packages-Debdelta "2";$/) }
  end

  describe "with verbose => 2" do
    let :params do
      { :verbose => "2" }
    end
    it { should contain_file(file_periodic).with_content(/^APT::Periodic::Verbose "2";$/) }
  end

end
require 'spec_helper'
describe 'apt::builddep', :type => :define do

  let(:facts) { { :lsbdistid => 'Debian' } }
  let(:title) { 'my_package' }

  describe "should require apt-get update" do
    it { should contain_exec("apt_update").with({
        'command' => "/usr/bin/apt-get update",
        'refreshonly' => true
      })
    }
    it { should contain_anchor("apt::builddep::my_package").with({
        'require' => 'Class[Apt::Update]',
      })
    }
  end

end
require 'spec_helper'
describe 'apt::conf', :type => :define do
  let(:facts) { { :lsbdistid => 'Debian' } }
  let :title do
    'norecommends'
  end

  describe "when creating an apt preference" do
    let :params do
      {
        :priority => '00',
        :content  => "Apt::Install-Recommends 0;\nApt::AutoRemove::InstallRecommends 1;\n"
      }
    end

    let :filename do
      "/etc/apt/apt.conf.d/00norecommends"
    end

    it { should contain_apt__conf('norecommends').with({
         'priority' => '00',
         'content'  => "Apt::Install-Recommends 0;\nApt::AutoRemove::InstallRecommends 1;\n"
      })
    }

    it { should contain_file(filename).with({
          'ensure'    => 'present',
          'content'   => "Apt::Install-Recommends 0;\nApt::AutoRemove::InstallRecommends 1;\n",
          'owner'     => 'root',
          'group'     => 'root',
          'mode'      => '0644',
        })
      }
  end

  describe "when removing an apt preference" do
    let :params do
      {
        :ensure   => 'absent',
        :priority => '00',
        :content  => "Apt::Install-Recommends 0;\nApt::AutoRemove::InstallRecommends 1;\n"
      }
    end

    let :filename do
      "/etc/apt/apt.conf.d/00norecommends"
    end

    it { should contain_file(filename).with({
        'ensure'    => 'absent',
        'content'   => "Apt::Install-Recommends 0;\nApt::AutoRemove::InstallRecommends 1;\n",
        'owner'     => 'root',
        'group'     => 'root',
        'mode'      => '0644',
      })
    }
  end
end
require 'spec_helper'
describe 'apt::force', :type => :define do
  let(:facts) { { :lsbdistid => 'Debian' } }
  let :pre_condition do
    'include apt::params'
  end

  let :title do
    'my_package'
  end

  let :default_params do
    {
      :release => 'testing',
      :version => false
    }
  end

  describe "when using default parameters" do
    let :params do
      default_params
    end
    it { should contain_exec("/usr/bin/apt-get -y -t #{params[:release]} install #{title}").with(
      :unless => "/usr/bin/test \$(/usr/bin/apt-cache policy -t #{params[:release]} #{title} | /bin/grep -E 'Installed|Candidate' | /usr/bin/uniq -s 14 | /usr/bin/wc -l) -eq 1",
      :timeout => '300'
    ) }
  end

  describe "when specifying false release parameter" do
    let :params do
      default_params.merge(:release => false)
    end
    it { should contain_exec("/usr/bin/apt-get -y  install #{title}").with(
      :unless  => "/usr/bin/dpkg -s #{title} | grep -q 'Status: install'"
    ) }
  end

  describe "when specifying version parameter" do
    let :params do
      default_params.merge(:version => '1')
    end
    it { should contain_exec("/usr/bin/apt-get -y -t #{params[:release]} install #{title}=#{params[:version]}").with(
      :unless => "/usr/bin/apt-cache policy -t #{params[:release]} #{title} | /bin/grep -q 'Installed: #{params[:version]}'"
    ) }
  end

  describe "when specifying false release and version parameters" do
    let :params do
      default_params.merge(
        :release => false,
        :version => '1'
      )
    end
    it { should contain_exec("/usr/bin/apt-get -y  install #{title}=1").with(
      :unless => "/usr/bin/dpkg -s #{title} | grep -q 'Version: #{params[:version]}'"
    ) }
  end
end
require 'spec_helper'
describe 'apt::key', :type => :define do
  let(:facts) { { :lsbdistid => 'Debian' } }
  let :title do
    '8347A27F'
  end

  let :default_params do
    {
      :key         => title,
      :ensure      => 'present',
      :key_server  => "keyserver.ubuntu.com",
      :key_source  => false,
      :key_content => false
    }
  end

  [{},
    {
      :ensure  => 'absent'
    },
    {
      :ensure  => 'random'
    },
    {
      :key_source => 'ftp://ftp.example.org/key',
    },
    {
      :key_content => 'deadbeef',
    }
  ].each do |param_set|

    let :param_hash do
      param_hash = default_params.merge(param_set)
      param_hash[:key].upcase! if param_hash[:key]
      param_hash
    end

    let :params do
      param_set
    end

    let :digest do
      str = String.new
      str << param_hash[:key].to_s         << '/'
      str << param_hash[:key_content].to_s << '/'
      str << param_hash[:key_source].to_s  << '/'
      str << param_hash[:key_server].to_s  << '/'
      Digest::SHA1.hexdigest(str)
    end

    describe "when #{param_set == {} ? "using default" : "specifying"} define parameters" do

      it {
        if [:present, 'present', :absent, 'absent'].include? param_hash[:ensure]
          should contain_apt__params
        end
      }

      it {
        if [:present, 'present'].include? param_hash[:ensure]
          should_not contain_exec("apt::key #{param_hash[:key]} absent")
          should contain_anchor("apt::key #{param_hash[:key]} present")
          should contain_exec(digest).with({
            "path"    => "/bin:/usr/bin",
            "unless"  => "/usr/bin/apt-key list | /bin/grep '#{param_hash[:key]}'"
          })
        elsif [:absent, 'absent'].include? param_hash[:ensure]
          should_not contain_anchor("apt::key #{param_hash[:key]} present")
          should contain_exec("apt::key #{param_hash[:key]} absent").with({
            "path"    => "/bin:/usr/bin",
            "onlyif"  => "apt-key list | grep '#{param_hash[:key]}'",
            "command" => "apt-key del '#{param_hash[:key]}'"
          })
        else
          expect { should raise_error(Puppet::Error) }
        end
      }

      it {
        if [:present, 'present'].include? param_hash[:ensure]
          if param_hash[:key_content]
            should contain_exec(digest).with({
              "command" => "echo '#{param_hash[:key_content]}' | /usr/bin/apt-key add -"
            })
          elsif param_hash[:key_source]
            should contain_exec(digest).with({
              "command" => "wget -q '#{param_hash[:key_source]}' -O- | apt-key add -"
            })
          elsif param_hash[:key_server]
            should contain_exec(digest).with({
              "command" => "apt-key adv --keyserver '#{param_hash[:key_server]}' --recv-keys '#{param_hash[:key]}'"
            })
          end
        end
      }

    end
  end

  [{ :ensure => 'present' }, { :ensure => 'absent' }].each do |param_set|
    describe "should correctly handle duplicate definitions" do

      let :pre_condition do
        "apt::key { 'duplicate': key => '#{title}'; }"
      end

      let(:params) { param_set }

      it {
        if param_set[:ensure] == 'present'
          should contain_anchor("apt::key #{title} present")
          should contain_apt__key(title)
          should contain_apt__key("duplicate")
        elsif param_set[:ensure] == 'absent'
          expect { should raise_error(Puppet::Error) }
        end
      }

    end
  end

end

require 'spec_helper'
describe 'apt::pin', :type => :define do
  let(:facts) { { :lsbdistid => 'Debian' } }
  let(:title) { 'my_pin' }

  let :default_params do
    {
      :ensure   => 'present',
      :order    => '',
      :packages => '*',
      :priority => '0',
      :release  => nil
    }
  end

  [
    { :params  => {},
      :content => "# my_pin\nExplanation: : my_pin\nPackage: *\nPin: release a=my_pin\nPin-Priority: 0\n"
    },
    {
      :params => {
        :packages => 'apache',
        :priority => '1'
      },
      :content => "# my_pin\nExplanation: : my_pin\nPackage: apache\nPin: release a=my_pin\nPin-Priority: 1\n"
    },
    {
      :params => {
        :order    => 50,
        :packages => 'apache',
        :priority => '1'
      },
      :content => "# my_pin\nExplanation: : my_pin\nPackage: apache\nPin: release a=my_pin\nPin-Priority: 1\n"
    },
    {
      :params => {
        :ensure   => 'absent',
        :packages => 'apache',
        :priority => '1'
      },
      :content => "# my_pin\nExplanation: : my_pin\nPackage: apache\nPin: release a=my_pin\nPin-Priority: 1\n"
    },
    {
      :params => {
        :packages => 'apache',
        :priority => '1',
        :release  => 'my_newpin'
      },
      :content => "# my_pin\nExplanation: : my_pin\nPackage: apache\nPin: release a=my_newpin\nPin-Priority: 1\n"
    },
    {
      :params => {
        :packages => 'apache',
        :priority => '1',
        :version  => '2.2.16*'
      },
      :content => "# my_pin\nExplanation: : my_pin\nPackage: apache\nPin: version 2.2.16*\nPin-Priority: 1\n"
    },
    {
      :params => {
        :priority => '1',
        :origin   => 'ftp.de.debian.org'
      },
      :content => "# my_pin\nExplanation: : my_pin\nPackage: *\nPin: origin ftp.de.debian.org\nPin-Priority: 1\n"
    },
    {
      :params => {
        :packages        => 'apache',
        :priority        => '1',  
        :release         => 'stable',
        :codename        => 'wheezy',
        :release_version => '3.0',
        :component       => 'main',
        :originator      => 'Debian',
        :label           => 'Debian'
      },
      :content => "# my_pin\nExplanation: : my_pin\nPackage: apache\nPin: release a=stable, n=wheezy, v=3.0, c=main, o=Debian, l=Debian\nPin-Priority: 1\n"
    },
  ].each do |param_set|
    describe "when #{param_set == {} ? "using default" : "specifying"} define parameters" do
      let :param_hash do
        default_params.merge(param_set[:params])
      end

      let :params do
        param_set[:params]
      end

      it { should contain_class("apt::params") }

      it { should contain_file("#{title}.pref").with({
          'ensure'  => param_hash[:ensure],
          'path'    => "/etc/apt/preferences.d/#{param_hash[:order] == '' ? "" : "#{param_hash[:order]}-"}#{title}.pref",
          'owner'   => 'root',
          'group'   => 'root',
          'mode'    => '0644',
          'content' => param_set[:content],
        })
      }
    end
  end
end
require 'spec_helper'
describe 'apt::ppa', :type => :define do
  [
    {
      :lsbdistrelease  => '11.04',
      :lsbdistcodename => 'natty',
      :operatingsystem => 'Ubuntu',
      :lsbdistid       => 'Ubuntu',
      :package         => 'python-software-properties'
    },
    {
      :lsbdistrelease  => '12.10',
      :lsbdistcodename => 'quantal',
      :operatingsystem => 'Ubuntu',
      :lsbdistid       => 'Ubuntu',
      :package         => 'software-properties-common'
    },
  ].each do |platform|
    context "on #{platform[:lsbdistcodename]}" do
      let :facts do
        {
          :lsbdistrelease  => platform[:lsbdistrelease],
          :lsbdistcodename => platform[:lsbdistcodename],
          :operatingsystem => platform[:operatingsystem],
          :lsbdistid       => platform[:lsbdistid],
        }
      end
      let :release do
        "#{platform[:lsbdistcodename]}"
      end
      let :package do
        "#{platform[:package]}"
      end
      let :options do
        "-y"
      end
      ['ppa:dans_ppa', 'dans_ppa','ppa:dans-daily/ubuntu'].each do |t|
        describe "with title #{t}" do
          let :pre_condition do
            'class { "apt": }'
          end
          let :title do
            t
          end
          let :filename do
            t.sub(/^ppa:/,'').gsub('/','-') << "-" << "#{release}.list"
          end

          it { should contain_package("#{package}") }

          it { should contain_exec("apt_update").with(
            'command'     => '/usr/bin/apt-get update',
            'refreshonly' => true
            )
          }

          it { should contain_exec("add-apt-repository-#{t}").with(
            'command' => "/usr/bin/add-apt-repository #{options} #{t}",
            'unless'  => "/usr/bin/test -s /etc/apt/sources.list.d/#{filename}",
            'require' => ["File[sources.list.d]", "Package[#{package}]"],
            'notify'  => "Exec[apt_update]"
            )
          }

          it { should create_file("/etc/apt/sources.list.d/#{filename}").with(
            'ensure'  => 'file',
            'require' => "Exec[add-apt-repository-#{t}]"
            )
          }
        end
      end
      describe 'without a proxy defined' do
        let :title do
          'rspec_ppa'
        end
        let :pre_condition do
          'class { "apt":
             proxy_host => false
          }'
        end
        let :filename do
          "#{title}-#{release}.list"
        end

        it { should contain_exec("add-apt-repository-#{title}").with(
          'environment' => [],
          'command'     => "/usr/bin/add-apt-repository #{options} #{title}",
          'unless'      => "/usr/bin/test -s /etc/apt/sources.list.d/#{filename}",
          'require'     => ["File[sources.list.d]", "Package[#{package}]"],
          'notify'      => "Exec[apt_update]"
          )
        }
      end

      describe 'behind a proxy' do
        let :title do
          'rspec_ppa'
        end
        let :pre_condition do
          'class { "apt":
            proxy_host => "user:pass@proxy",
          }'
        end
          let :filename do
            "#{title}-#{release}.list"
          end

        it { should contain_exec("add-apt-repository-#{title}").with(
          'environment' => [
            "http_proxy=http://user:pass@proxy:8080",
            "https_proxy=http://user:pass@proxy:8080",
          ],
          'command'     => "/usr/bin/add-apt-repository #{options} #{title}",
          'unless'      => "/usr/bin/test -s /etc/apt/sources.list.d/#{filename}",
          'require'     => ["File[sources.list.d]", "Package[#{package}]"],
          'notify'      => "Exec[apt_update]"
          )
        }
      end
    end
  end

  [ { :lsbdistcodename => 'natty',
      :package => 'python-software-properties' },
    { :lsbdistcodename => 'quantal',
      :package => 'software-properties-common'},
  ].each do |platform|
    context "on #{platform[:lsbdistcodename]}" do
      describe "it should not error if package['#{platform[:package]}'] is already defined" do
        let :pre_condition do
           'class {"apt": }' +
           'package { "#{platform[:package]}": }->Apt::Ppa["ppa"]'
        end
        let :facts do
          {:lsbdistcodename => '#{platform[:lsbdistcodename]}',
           :operatingsystem => 'Ubuntu',
           :lsbdistid => 'Ubuntu'}
        end
        let(:title) { "ppa" }
        let(:release) { "#{platform[:lsbdistcodename]}" }
        it { should contain_package('#{platform[:package]}') }
      end
    end
  end

  describe "without Class[apt] should raise a Puppet::Error" do
    let(:release) { "natty" }
    let(:title) { "ppa" }
    it { expect { should contain_apt__ppa(title) }.to raise_error(Puppet::Error) }
  end

  describe "without release should raise a Puppet::Error" do
    let(:title) { "ppa:" }
    it { expect { should contain_apt__ppa(:release) }.to raise_error(Puppet::Error) }
  end
end
require 'spec_helper'
describe 'apt::source', :type => :define do
  let(:facts) { { :lsbdistid => 'Debian' } }
  let :title do
    'my_source'
  end

  let :default_params do
    {
      :ensure             => 'present',
      :location           => '',
      :release            => 'karmic',
      :repos              => 'main',
      :include_src        => true,
      :required_packages  => false,
      :key                => false,
      :key_server         => 'keyserver.ubuntu.com',
      :key_content        => false,
      :key_source         => false,
      :pin                => false
    }
  end

  [{},
   {
      :location           => 'http://example.com',
      :release            => 'precise',
      :repos              => 'security',
      :include_src        => false,
      :required_packages  => 'apache',
      :key                => 'key_name',
      :key_server         => 'keyserver.debian.com',
      :pin                => '600',
      :key_content        => 'ABCD1234'
    },
    {
      :key                => 'key_name',
      :key_server         => 'keyserver.debian.com',
      :key_content        => false,
    },
    {
      :ensure             => 'absent',
      :location           => 'http://example.com',
      :release            => 'precise',
      :repos              => 'security',
    },
    {
      :release            => '',
    },
    {
      :release            => 'custom',
    },
    {
      :architecture       => 'amd64',
    }
  ].each do |param_set|
    describe "when #{param_set == {} ? "using default" : "specifying"} class parameters" do
      let :param_hash do
        default_params.merge(param_set)
      end

      let :facts do
        {:lsbdistcodename => 'karmic', :lsbdistid => 'Ubuntu'}
      end

      let :params do
        param_set
      end

      let :filename do
        "/etc/apt/sources.list.d/#{title}.list"
      end

      let :content do
        content = "# #{title}"
        if param_hash[:architecture]
          arch = "[arch=#{param_hash[:architecture]}] "
        end
        content << "\ndeb #{arch}#{param_hash[:location]} #{param_hash[:release]} #{param_hash[:repos]}\n"

        if param_hash[:include_src]
          content << "deb-src #{arch}#{param_hash[:location]} #{param_hash[:release]} #{param_hash[:repos]}\n"
        end
        content
      end

      it { should contain_apt__params }

      it { should contain_file("#{title}.list").with({
          'ensure'    => param_hash[:ensure],
          'path'      => filename,
          'owner'     => 'root',
          'group'     => 'root',
          'mode'      => '0644',
          'content'   => content,
        })
      }

      it {
        if param_hash[:pin]
          should contain_apt__pin(title).with({
            "priority"  => param_hash[:pin],
            "before"    => "File[#{title}.list]"
          })
        else
          should_not contain_apt__pin(title).with({
            "priority"  => param_hash[:pin],
            "before"    => "File[#{title}.list]"
          })
        end
      }

      it {
        should contain_exec("apt_update").with({
          "command"     => "/usr/bin/apt-get update",
          "refreshonly" => true
        })
      }

      it {
        if param_hash[:required_packages]
          should contain_exec("Required packages: '#{param_hash[:required_packages]}' for #{title}").with({
            "command" => "/usr/bin/apt-get -y install #{param_hash[:required_packages]}",
            "subscribe"   => "File[#{title}.list]",
            "refreshonly" => true,
            "before"      => 'Exec[apt_update]',
          })
        else
          should_not contain_exec("Required packages: '#{param_hash[:required_packages]}' for #{title}").with({
            "command"     => "/usr/bin/apt-get -y install #{param_hash[:required_packages]}",
            "subscribe"   => "File[#{title}.list]",
            "refreshonly" => true
          })
        end
      }

      it {
        if param_hash[:key]
          should contain_apt__key("Add key: #{param_hash[:key]} from Apt::Source #{title}").with({
            "key"         => param_hash[:key],
            "ensure"      => :present,
            "key_server"  => param_hash[:key_server],
            "key_content" => param_hash[:key_content],
            "key_source"  => param_hash[:key_source],
            "before"      => "File[#{title}.list]"
          })
        else
          should_not contain_apt__key("Add key: #{param_hash[:key]} from Apt::Source #{title}").with({
            "key"         => param_hash[:key],
            "ensure"      => :present,
            "key_server"  => param_hash[:key_server],
            "key_content" => param_hash[:key_content],
            "key_source"  => param_hash[:key_source],
            "before"      => "File[#{title}.list]"
          })
        end
      }
    end
  end
  describe "without release should raise a Puppet::Error" do
    let(:default_params) { Hash.new }
    let(:facts) { Hash.new }
    it { expect { should raise_error(Puppet::Error) } }
    let(:facts) { { :lsbdistcodename => 'lucid', :lsbdistid => 'Ubuntu' } }
    it { should contain_apt__source(title) }
  end
end
require 'puppetlabs_spec_helper/module_spec_helper'
require 'beaker-rspec'

# Install Puppet
unless ENV['RS_PROVISION'] == 'no'
  hosts.each do |host|
    if host.is_pe?
      install_pe
    else
      install_puppet
      on host, "mkdir -p #{host['distmoduledir']}"
    end
  end
end

UNSUPPORTED_PLATFORMS = ['RedHat','Suse','windows','AIX','Solaris']

RSpec.configure do |c|
  # Project root
  proj_root = File.expand_path(File.join(File.dirname(__FILE__), '..'))

  # Readable test descriptions
  c.formatter = :documentation

  # Configure all nodes in nodeset
  c.before :suite do
    # Install module and dependencies
    puppet_module_install(:source => proj_root, :module_name => 'apt')
    hosts.each do |host|
      shell('/bin/touch /etc/puppet/hiera.yaml')
      shell('puppet module install puppetlabs-stdlib --version 2.2.1', { :acceptable_exit_codes => [0,1] })
    end
  end
end
APT::Periodic::Enable "<%= @enable %>";
APT::Periodic::BackUpArchiveInterval "<%= @backup_interval %>";
APT::Periodic::BackUpLevel "<%= @backup_level %>";
APT::Periodic::MaxAge "<%= @max_age %>";
APT::Periodic::MinAge "<%= @min_age %>";
APT::Periodic::MaxSize "<%= @max_size %>";
APT::Periodic::Update-Package-Lists "<%= @update %>";
APT::Periodic::Download-Upgradeable-Packages "<%= @download %>";
APT::Periodic::Download-Upgradeable-Packages-Debdelta "<%= @download_delta %>";
APT::Periodic::Unattended-Upgrade "<%= @upgrade %>";
APT::Periodic::AutocleanInterval "<%= @autoclean %>";
APT::Periodic::Verbose "<%= @verbose %>";
// Automatically upgrade packages from these (origin:archive) pairs
Unattended-Upgrade::Allowed-Origins {
<% @origins.each do |origin| -%>
	"<%= origin %>";
<% end -%>
};

// List of packages to not update
Unattended-Upgrade::Package-Blacklist {
<% @blacklist.each do |package| -%>
	"<%= package %>";
<% end -%>
};

// This option allows you to control if on a unclean dpkg exit
// unattended-upgrades will automatically run 
//   dpkg --force-confold --configure -a
// The default is true, to ensure updates keep getting installed
Unattended-Upgrade::AutoFixInterruptedDpkg "<%= @auto_fix %>";

// Split the upgrade into the smallest possible chunks so that
// they can be interrupted with SIGUSR1. This makes the upgrade
// a bit slower but it has the benefit that shutdown while a upgrade
// is running is possible (with a small delay)
Unattended-Upgrade::MinimalSteps "<%= @minimal_steps %>";

// Install all unattended-upgrades when the machine is shuting down
// instead of doing it in the background while the machine is running
// This will (obviously) make shutdown slower
Unattended-Upgrade::InstallOnShutdown "<%= @install_on_shutdown %>";

// Send email to this address for problems or packages upgrades
// If empty or unset then no email is sent, make sure that you
// have a working mail setup on your system. A package that provides
// 'mailx' must be installed.
<% if @mail_to != "NONE" %>Unattended-Upgrade::Mail "<%= @mail_to %>";<% end %>

// Set this value to "true" to get emails only on errors. Default
// is to always send a mail if Unattended-Upgrade::Mail is set
<% if @mail_to != "NONE" %>Unattended-Upgrade::MailOnlyOnError "<%= @mail_only_on_error %>";<% end %>

// Do automatic removal of new unused dependencies after the upgrade
// (equivalent to apt-get autoremove)
Unattended-Upgrade::Remove-Unused-Dependencies "<%= @remove_unused %>";

// Automatically reboot *WITHOUT CONFIRMATION* if a 
// the file /var/run/reboot-required is found after the upgrade 
Unattended-Upgrade::Automatic-Reboot "<%= @auto_reboot %>";


// Use apt bandwidth limit feature, this example limits the download
// speed to 70kb/sec
<% if @dl_limit != "NONE" %>Acquire::http::Dl-Limit "<%= @dl_limit %>";<% end %>
<%-
@pin = "release a=#{@name}" # default value
if @pin_release.length > 0
  options = []
  options.push("a=#{@release}") if @release.length > 0
  options.push("n=#{@codename}") if @codename.length > 0
  options.push("v=#{@release_version}") if @release_version.length > 0
  options.push("c=#{@component}") if @component.length > 0
  options.push("o=#{@originator}") if @originator.length > 0
  options.push("l=#{@label}") if @label.length > 0
  @pin = "release #{options.join(', ')}"
elsif @version.length > 0
  @pin = "version #{@version}"
elsif @origin.length > 0
  @pin = "origin #{@origin}"
end
-%>
# <%= @name %>
Explanation: <%= @explanation %>
Package: <%= @packages %>
Pin: <%= @pin %>
Pin-Priority: <%= @priority %>
# <%= @name %>
deb <% if @architecture %>[arch=<%= @architecture %>] <% end %><%= @location %> <%= @release_real %> <%= @repos %>
<%- if @include_src then -%>
deb-src <% if @architecture %>[arch=<%= @architecture %>] <% end %><%= @location %> <%= @release_real %> <%= @repos %>
<%- end -%>
class { 'apt': }
apt::builddep{ 'glusterfs-server': }
class { 'apt': }
class { 'apt::debian::testing': }
class { 'apt': }
class { 'apt::debian::unstable': }
# force.pp

# force a package from a specific release
apt::force { 'package1':
  release => 'backports',
}

# force a package to be a specific version
apt::force { 'package2':
  version => '1.0.0-1',
}

# force a package from a specific release to be a specific version
apt::force { 'package3':
  release => 'sid',
  version => '2.0.0-1',
}
class { 'apt': }
# Declare Apt key for apt.puppetlabs.com source
apt::key { 'puppetlabs':
  key         => '4BD6EC30',
  key_server  => 'pgp.mit.edu',
  key_options => 'http-proxy="http://proxyuser:proxypass@example.org:3128"',
}
include apt::params
# pin a release in apt, useful for unstable repositories
apt::pin { 'foo':
  packages => '*',
  priority => 0,
}
class { 'apt': }

# Example declaration of an Apt PPA
apt::ppa{ 'ppa:openstack-ppa/bleeding-edge': }
class { 'apt': }
class { 'apt::release':
  release_id => 'karmic'
}
# Declare the apt class to manage /etc/apt/sources.list and /etc/sources.list.d
class { 'apt': }

# Install the puppetlabs apt source
# Release is automatically obtained from lsbdistcodename fact if available.
apt::source { 'puppetlabs':
  location   => 'http://apt.puppetlabs.com',
  repos      => 'main',
  key        => '4BD6EC30',
  key_server => 'pgp.mit.edu',
}

# test two sources with the same key
apt::source { 'debian_testing':
  location   => 'http://debian.mirror.iweb.ca/debian/',
  release    => 'testing',
  repos      => 'main contrib non-free',
  key        => '46925553',
  key_server => 'subkeys.pgp.net',
  pin        => '-10',
}
apt::source { 'debian_unstable':
  location   => 'http://debian.mirror.iweb.ca/debian/',
  release    => 'unstable',
  repos      => 'main contrib non-free',
  key        => '46925553',
  key_server => 'subkeys.pgp.net',
  pin        => '-10',
}
include apt::unattended_upgrades
language: ruby
rvm:
  - "1.8.7"
# life with later versions of ruby gets interesting with 2.6..so lets
# ignore them for now
#  - "1.9.2"
#  - "1.9.3"
#  - ruby-head ..that doesnt work. would be nice to do "current"

env:
#find versions here https://rubygems.org/gems/puppet/versions
# spec_helper pretty much fails on these earlier versions.
#  - PUPPET_VERSION=0.24.5
#  - PUPPET_VERSION=0.25.5 
  - PUPPET_VERSION=2.6.18
  - PUPPET_VERSION=2.7.21
  - PUPPET_VERSION=3.1.1
 

before_script: 
 - cd beanstalkd
 - bundle install
 - bundle show

script: 
 - bundle exec rake
source 'https://rubygems.org'

puppetversion = ENV.key?('PUPPET_VERSION') ? "= #{ENV['PUPPET_VERSION']}" : ['>= 2.7']


gem 'rake'
gem 'rspec-expectations'
gem 'rspec'
gem 'facter'
gem 'puppet', puppetversion
gem 'rspec-puppet'
gem 'puppetlabs_spec_helper'
puppet-beanstalkd
=================
[![Build Status](https://travis-ci.org/keen99/puppet-beanstalkd.png?branch=master)](https://travis-ci.org/keen99/puppet-beanstalkd)

puppet module for managing beanstalkd, a simple and fast work queue - https://github.com/kr/beanstalkd


## Supported OSes

redhat/centos and debian/ubuntu currently.  Please PR updates for others!  

Requires packages (rpm, etc) with traditional init scripts supported by service{} for your OS.


## Basic Usage

Drop the beanstalkd directory into your modules tree and realize the define:

	beanstalkd::config{"my beanstalk install": }

## Optional parameters
	
	listenaddress => '0.0.0.0',
	listenport => '13000',
	maxjobsize => '65535',
	maxconnections => '1024',
	binlogdir => '/var/lib/beanstalkd/binlog',	# set empty ( '' ) to disable binlog
	binlogfsync => undef,							
	binlogsize => '10485760',
	ensure => 'running',		# running, stopped, absent
	packageversion => 'latest',	# latest, present, or specific version
	packagename => undef,		# override package name						
	servicename => undef		# override service name





## Tests

To run unit tests, cd into beanstalkd and execute "run-tests.sh"

Requires ruby and bundler, everything else should get installed by the test.

```
$$ puppet-beanstalkd/beanstalkd# ./run-tests.sh 
Using rake (10.0.4) 
Using diff-lcs (1.2.4) 
Using facter (1.7.0) 
Using json_pure (1.7.7) 
Using hiera (1.2.1) 
Using metaclass (0.0.1) 
Using mocha (0.13.3) 
Using puppet (3.1.1) 
Using rspec-core (2.13.1) 
Using rspec-expectations (2.13.0) 
Using rspec-mocks (2.13.1) 
Using rspec (2.13.0) 
Using rspec-puppet (0.1.6) 
Using puppetlabs_spec_helper (0.4.1) 
Using bundler (1.1.4) 
Your bundle is complete! Use `bundle show [gemname]` to see where a bundled gem is installed.
/usr/bin/ruby1.9.1 -S rspec spec/defines/config_spec.rb
...................

Finished in 0.84772 seconds
19 examples, 0 failures
```
require 'rake'

require 'rspec/core/rake_task'

task :default => [:spec]


RSpec::Core::RakeTask.new(:spec) do |t|
  t.pattern = 'spec/*/*_spec.rb'
end

# usage:
#
#  beanstalkd::config { name:
#    listenaddress => '0.0.0.0',
#    listenport => '13000',
#    maxjobsize => '65535',
#    maxconnections => '1024',
#    binlogdir => '/var/lib/beanstalkd/binlog',
#    binlogfsync => undef,              
#    binlogsize => '10485760',
#    ensure => 'running',         # running, stopped, absent
#    packageversion => 'latest',  # latest, present, or specific version
#    packagename => undef,        # override package name
#    servicename => undef         # override service name
#  }


define beanstalkd::config ( # name
  $listenaddress  = '0.0.0.0',
  $listenport     = '13000',
  $maxjobsize     = '65535',
  $maxconnections = '1024',                       # results in open file limit
  $binlogdir      = '/var/lib/beanstalkd/binlog', # set empty ( '' ) to disable binlog
  $binlogfsync    = undef,                        # unset = no explicit fsync
  $binlogsize     = '10485760',
  #
  $ensure         = 'running',  # running, stopped, absent
  $packageversion = 'latest',   # latest, present, or specific version
  $packagename    = undef,      # got your own custom package?  override the default name/service here.
  $servicename    = undef
) {

  case $::operatingsystem {
    ubuntu, debian: {
      $defaultpackagename = 'beanstalkd'
      $defaultservicename = 'beanstalkd'
      $user               = 'beanstalkd'
      $configfile         = '/etc/default/beanstalkd'
      $configtemplate     = "${module_name}/debian/beanstalkd_default.erb"  # please create me!
      $hasstatus          = 'true'
      $restart            = '/etc/init.d/beanstalkd restart'
    }
    centos, redhat: {
      $defaultpackagename = 'beanstalkd'
      $defaultservicename = 'beanstalkd'
      $user               = 'beanstalkd'
      $configfile         = '/etc/sysconfig/beanstalkd'
      $configtemplate     = "${module_name}/redhat/beanstalkd_sysconfig.erb"
      $hasstatus          = 'true'
      $restart            = '/etc/init.d/beanstalkd restart'
    }
    # TODO: add more OS support!
    default: {   
      fail("ERROR [${module_name}]: I don't know how to manage this OS: ${::operatingsystem}")
    }
  }

  # simply the users experience for running/stopped/absent, and use ensure to cover those bases
  case $ensure {
    absent: {
      $ourpackageversion  = 'absent'
      $serviceenable      = 'false'
      $serviceensure      = 'stopped'
      $fileensure         = 'absent'
    }
    running: {
      $serviceenable  = 'true'
      $serviceensure  = 'running'
      $fileensure     = 'present'
    }
    stopped: {
      $serviceenable  = 'false'
      $serviceensure  = 'stopped'
      $fileensure     = 'present'
    }
    default: {
      fail("ERROR [${module_name}]: enable must be one of: running stopped absent")
    }
  }
  
  # for packageversion, use what's configured unless we're set (which should only be in the absent case..)
  if ! $ourpackageversion { 
    $ourpackageversion = $packageversion
  }
  
  # for service and package name - if we've specified one, use it. else use the default
  if $packagename == undef {
    $ourpackagename = $defaultpackagename
  } else {
    $ourpackagename = $packagename
  }

  if $servicename == undef {
    $ourservicename = $defaultservicename
  } else {
    $ourservicename = $servicename
  }

  package { $ourpackagename:
    ensure => $ourpackageversion
  }

  service { $ourservicename:
    enable    => $serviceenable,
    ensure    => $serviceensure,
    hasstatus => $hasstatus,
    restart   => $restart,
    subscribe => [
      Package[$ourpackagename],
      File[$configfile]
    ],
  }

  file { $configfile:
    content => template($configtemplate),
    owner   => 'root',
    group   => 'root',
    mode    => 0644,
    ensure  => $fileensure,
    require => Package[$ourpackagename],
  } 

}
#!/usr/bin/env sh

bundle="bundle"
gotbundle=0
for i in $(echo "$PATH" | tr ":" " ")
 do
        if [ -e $i/$bundle ]
         then
                gotbundle=1
                break
        fi
done
if [ $gotbundle = 0 ]
 then
        echo "ERROR: please install 'bundler' for ruby from http://gembundler.com/ and make sure '$bundle' is in your path"
        exit 1
fi

$bundle install || exit $?
$bundle exec rake || exit $?
require 'spec_helper'


describe 'beanstalkd::config' do
  let (:title) {'a title is required'}

  #basic OS support testing
  context "on Debian" do
    let (:facts) { { :operatingsystem => 'debian' } }
    it { should contain_package('beanstalkd').with_ensure('latest') }
    it { should contain_service('beanstalkd').with_ensure('running') }
  end  
  context "on redhat" do
    let (:facts) { { :operatingsystem => 'debian' } }
    it { should contain_package('beanstalkd').with_ensure('latest') }
    it { should contain_service('beanstalkd').with_ensure('running') }
  end  
  context "on ubuntu" do
    let (:facts) { { :operatingsystem => 'ubuntu' } }
    it { should contain_package('beanstalkd').with_ensure('latest') }
    it { should contain_service('beanstalkd').with_ensure('running') }
  end  
  context "on centos" do
    let (:facts) { { :operatingsystem => 'centos' } }
    it { should contain_package('beanstalkd').with_ensure('latest') }
    it { should contain_service('beanstalkd').with_ensure('running') }
  end  
  context "on unsupported OS" do
    let (:facts) { { :operatingsystem => 'unsupported' } }
    it { expect { raise_error(Puppet::Error) } }
  end  

  #now lets test our various parameters - for the most part this shouldn't care what OS it is
  #if your OS support needs more specific testing, do it!

  #ensure testing - remember this does both service and packages, so test both
  context "on redhat, ensure absent" do
    let (:facts) { { :operatingsystem => 'redhat' } }
    let(:params) { { :ensure => 'absent' } }
    it { should contain_package('beanstalkd').with_ensure('absent') }
    it { should contain_service('beanstalkd').with_ensure('stopped') }
  end  
  context "on redhat, ensure running" do
    let (:facts) { { :operatingsystem => 'redhat' } }
    let(:params) { { :ensure => 'running' } }
    it { should contain_package('beanstalkd').with_ensure('latest') }
    it { should contain_service('beanstalkd').with_ensure('running') }
  end  
  context "on redhat, ensure stopped" do
    let (:facts) { { :operatingsystem => 'redhat' } }
    let(:params) { { :ensure => 'stopped' } }
    it { should contain_package('beanstalkd').with_ensure('latest') }
    it { should contain_service('beanstalkd').with_ensure('stopped') }
  end  
  context "on redhat, ensure broken" do
    let (:facts) { { :operatingsystem => 'redhat' } }
    let(:params) { { :ensure => 'broken' } }
    it { expect { raise_error(Puppet::Error) } }
  end  

  #custom package/service names
  context "on redhat, servicename testbeans" do
    let (:facts) { { :operatingsystem => 'redhat' } }
    let(:params) { { :servicename => 'testbeans' } }
    it { should contain_service('testbeans').with_ensure('running') }
  end  
  context "on redhat, packagename testbeans" do
    let (:facts) { { :operatingsystem => 'redhat' } }
    let(:params) { { :packagename => 'testbeans' } }
    it { should contain_package('testbeans').with_ensure('latest') }
  end  
  #and custom version
  context "on redhat, package version" do
    let (:facts) { { :operatingsystem => 'redhat' } }
    let(:params) { { :packageversion => 'testversion' } }
    it { should contain_package('beanstalkd').with_ensure('testversion') }
  end  

   
end

# usage:
#
#  beanstalkd::config { name:
#    listenaddress => '0.0.0.0',
#    listenport => '13000',
#    maxjobsize => '65535',
#    maxconnections => '1024',
#    binlogdir => '/var/lib/beanstalkd/binlog',
#    binlogfsync => undef,              
#    binlogsize => '10485760',
#    ensure => 'running',         # running, stopped, absent
#    packageversion => 'latest',  # latest, present, or specific version
#    packagename => undef,        # override package name
#    servicename => undef         # override service name
#  }


define beanstalkd::config ( # name
  $listenaddress  = '0.0.0.0',
  $listenport     = '13000',
  $maxjobsize     = '65535',
  $maxconnections = '1024',                       # results in open file limit
  $binlogdir      = '/var/lib/beanstalkd/binlog', # set empty ( '' ) to disable binlog
  $binlogfsync    = undef,                        # unset = no explicit fsync
  $binlogsize     = '10485760',
  #
  $ensure         = 'running',  # running, stopped, absent
  $packageversion = 'latest',   # latest, present, or specific version
  $packagename    = undef,      # got your own custom package?  override the default name/service here.
  $servicename    = undef
) {

  case $::operatingsystem {
    ubuntu, debian: {
      $defaultpackagename = 'beanstalkd'
      $defaultservicename = 'beanstalkd'
      $user               = 'beanstalkd'
      $configfile         = '/etc/default/beanstalkd'
      $configtemplate     = "${module_name}/debian/beanstalkd_default.erb"  # please create me!
      $hasstatus          = 'true'
      $restart            = '/etc/init.d/beanstalkd restart'
    }
    centos, redhat: {
      $defaultpackagename = 'beanstalkd'
      $defaultservicename = 'beanstalkd'
      $user               = 'beanstalkd'
      $configfile         = '/etc/sysconfig/beanstalkd'
      $configtemplate     = "${module_name}/redhat/beanstalkd_sysconfig.erb"
      $hasstatus          = 'true'
      $restart            = '/etc/init.d/beanstalkd restart'
    }
    # TODO: add more OS support!
    default: {   
      fail("ERROR [${module_name}]: I don't know how to manage this OS: ${::operatingsystem}")
    }
  }

  # simply the users experience for running/stopped/absent, and use ensure to cover those bases
  case $ensure {
    absent: {
      $ourpackageversion  = 'absent'
      $serviceenable      = 'false'
      $serviceensure      = 'stopped'
      $fileensure         = 'absent'
    }
    running: {
      $serviceenable  = 'true'
      $serviceensure  = 'running'
      $fileensure     = 'present'
    }
    stopped: {
      $serviceenable  = 'false'
      $serviceensure  = 'stopped'
      $fileensure     = 'present'
    }
    default: {
      fail("ERROR [${module_name}]: enable must be one of: running stopped absent")
    }
  }
  
  # for packageversion, use what's configured unless we're set (which should only be in the absent case..)
  if ! $ourpackageversion { 
    $ourpackageversion = $packageversion
  }
  
  # for service and package name - if we've specified one, use it. else use the default
  if $packagename == undef {
    $ourpackagename = $defaultpackagename
  } else {
    $ourpackagename = $packagename
  }

  if $servicename == undef {
    $ourservicename = $defaultservicename
  } else {
    $ourservicename = $servicename
  }

  package { $ourpackagename:
    ensure => $ourpackageversion
  }

  service { $ourservicename:
    enable    => $serviceenable,
    ensure    => $serviceensure,
    hasstatus => $hasstatus,
    restart   => $restart,
    subscribe => [
      Package[$ourpackagename],
      File[$configfile]
    ],
  }

  file { $configfile:
    content => template($configtemplate),
    owner   => 'root',
    group   => 'root',
    mode    => 0644,
    ensure  => $fileensure,
    require => Package[$ourpackagename],
  } 

}
#!/bin/sh
##based loosely on my sysconfig and initd scripts from centos, but tweaked to work without having to
##hack up the debian init script.  -keen99 4/2013

<% if @maxconnections -%>
BEANSTALKD_MAXCONNECTIONS=<%= @maxconnections %>
<% else -%>
#use default ulimit
#BEANSTALKD_MAXCONNECTIONS=1024
<% end -%>


BEANSTALKD_ADDR=<%= @listenaddress %>
BEANSTALKD_PORT=<%= @listenport %>
BEANSTALKD_USER=<%= @user %>

# Job size is left to the default. Uncomment and set it
# to a value to have it take affect.
<% if @maxjobsize -%>
BEANSTALKD_MAX_JOB_SIZE=<%= @maxjobsize %>
<% else -%>
#use default
#BEANSTALKD_MAX_JOB_SIZE=65535
<% end -%>

# Using the binlog is off by default.
#
# The direcory to house the binlog.
<% if @binlogdir -%>
BEANSTALKD_BINLOG_DIR=<%= @binlogdir %>
<% else -%>
#use default
#BEANSTALKD_BINLOG_DIR=/var/lib/beanstalkd/binlog
<% end -%>

# fsync the binlog at most once every N milliseconds.
# setting this to 0 means 'always fsync'. If this is unset,
# and the binlog is used, then no explicit fsync is ever
# performed.  That is, the -F option is used.
<% if @binlogfsync -%>
BEANSTALKD_BINLOG_FSYNC_PERIOD=<%= @bbinlogfsync %>
<% else -%>
#use default
#BEANSTALKD_BINLOG_FSYNC_PERIOD=
<% end -%>

# The size of each binlog file.  This is rounded
# up to the nearest 512 byte boundary.
<% if @binlogsize -%>
BEANSTALKD_BINLOG_SIZE=<%= @binlogsize %>
<% else -%>
#use default
#BEANSTALKD_BINLOG_SIZE=10485760
<% end -%>


options=""

##the debian init script leaves everything to be desired.  so lets put our setup logic here.

case "$1" in
	start|restart|force-reload|reload)
		exec=$DAEMON
		[ -x $exec ] || exit 5
		
		# if not running, start it up here, usually something like "daemon $exec"
		options="-l ${BEANSTALKD_ADDR} -p ${BEANSTALKD_PORT} -u ${BEANSTALKD_USER}"
		if [ "${BEANSTALKD_MAX_JOB_SIZE}" != ""  ]; then
			options="${options} -z ${BEANSTALKD_MAX_JOB_SIZE}"
		fi
		
		if [ "${BEANSTALKD_BINLOG_DIR}" != "" ]; then
			if [ ! -d "${BEANSTALKD_BINLOG_DIR}" ]; then
				echo "Creating binlog directory (${BEANSTALKD_BINLOG_DIR})"
				mkdir -p ${BEANSTALKD_BINLOG_DIR} && chown ${BEANSTALKD_USER}:${BEANSTALKD_USER} ${BEANSTALKD_BINLOG_DIR}
			fi
			options="${options} -b ${BEANSTALKD_BINLOG_DIR}"
			if [ "${BEANSTALKD_BINLOG_FSYNC_PERIOD}" != "" ]; then
				options="${options} -f ${BEANSTALKD_BINLOG_FSYNC_PERIOD}"
			else
				options="${options} -F"
			fi
			if [ "${BEANSTALKD_BINLOG_SIZE}" != "" ]; then
				options="${options} -s ${BEANSTALKD_BINLOG_SIZE}"
			fi
		
			##1.4.6 at least is prone to leave a lock file around after shutting down
			##this breaks startup after upgrade to 1.5, so work around this
			##unknown if this happens w/o binlog enabled...
			#check for stale lock file in binlog
			if [ -e "${BEANSTALKD_BINLOG_DIR}/lock" ]
			 then
				if ! ps xa| grep -v grep | grep -q $exec
				 then
					echo "found old lock file and beanstalk isn't running - deleting it"
					rm -f ${BEANSTALKD_BINLOG_DIR}/lock
				fi
			fi
		fi
	
		if [ -n "${BEANSTALKD_MAXCONNECTIONS}" ]; then
			#increase open files ulimit to support higher concurrent connections
			echo "increasing open file limit to $BEANSTALKD_MAXCONNECTIONS"
			ulimit -n $BEANSTALKD_MAXCONNECTIONS
		fi
	;;
	*)
		#nothing, please keep moving
	;;
esac


DAEMON_OPTS="$options"
DAEMONUSER=$BEANSTALKD_USER


## Uncomment to enable startup during boot.
START=yes

# System configuration for the beanstalkd daemon

# Available options correspond to the options to the
# beanstalkd commandline.

<% if @maxconnections -%>
BEANSTALKD_MAXCONNECTIONS=<%= @maxconnections %>
<% else -%>
#use default ulimit
#BEANSTALKD_MAXCONNECTIONS=1024
<% end -%>


BEANSTALKD_ADDR=<%= @listenaddress %>
BEANSTALKD_PORT=<%= @listenport %>
BEANSTALKD_USER=<%= @user %>

# Job size is left to the default. Uncomment and set it
# to a value to have it take affect.
<% if @maxjobsize -%>
BEANSTALKD_MAX_JOB_SIZE=<%= @maxjobsize %>
<% else -%>
#use default
#BEANSTALKD_MAX_JOB_SIZE=65535
<% end -%>

# Using the binlog is off by default.
#
# The direcory to house the binlog.
<% if @binlogdir -%>
BEANSTALKD_BINLOG_DIR=<%= @binlogdir %>
<% else -%>
#use default
#BEANSTALKD_BINLOG_DIR=/var/lib/beanstalkd/binlog
<% end -%>

# fsync the binlog at most once every N milliseconds.
# setting this to 0 means 'always fsync'. If this is unset,
# and the binlog is used, then no explicit fsync is ever
# performed.  That is, the -F option is used.
<% if @binlogfsync -%>
BEANSTALKD_BINLOG_FSYNC_PERIOD=<%= @bbinlogfsync %>
<% else -%>
#use default
#BEANSTALKD_BINLOG_FSYNC_PERIOD=
<% end -%>

# The size of each binlog file.  This is rounded
# up to the nearest 512 byte boundary.
<% if @binlogsize -%>
BEANSTALKD_BINLOG_SIZE=<%= @binlogsize %>
<% else -%>
#use default
#BEANSTALKD_BINLOG_SIZE=10485760
<% end -%>

require 'rspec-puppet'

fixture_path = File.expand_path(File.join(__FILE__, '..', 'fixtures'))

RSpec.configure do |c|
  c.module_path = File.join(fixture_path, 'modules')
  c.manifest_dir = File.join(fixture_path, 'manifests')
end
#!/bin/sh
##based loosely on my sysconfig and initd scripts from centos, but tweaked to work without having to
##hack up the debian init script.  -keen99 4/2013

<% if @maxconnections -%>
BEANSTALKD_MAXCONNECTIONS=<%= @maxconnections %>
<% else -%>
#use default ulimit
#BEANSTALKD_MAXCONNECTIONS=1024
<% end -%>


BEANSTALKD_ADDR=<%= @listenaddress %>
BEANSTALKD_PORT=<%= @listenport %>
BEANSTALKD_USER=<%= @user %>

# Job size is left to the default. Uncomment and set it
# to a value to have it take affect.
<% if @maxjobsize -%>
BEANSTALKD_MAX_JOB_SIZE=<%= @maxjobsize %>
<% else -%>
#use default
#BEANSTALKD_MAX_JOB_SIZE=65535
<% end -%>

# Using the binlog is off by default.
#
# The direcory to house the binlog.
<% if @binlogdir -%>
BEANSTALKD_BINLOG_DIR=<%= @binlogdir %>
<% else -%>
#use default
#BEANSTALKD_BINLOG_DIR=/var/lib/beanstalkd/binlog
<% end -%>

# fsync the binlog at most once every N milliseconds.
# setting this to 0 means 'always fsync'. If this is unset,
# and the binlog is used, then no explicit fsync is ever
# performed.  That is, the -F option is used.
<% if @binlogfsync -%>
BEANSTALKD_BINLOG_FSYNC_PERIOD=<%= @bbinlogfsync %>
<% else -%>
#use default
#BEANSTALKD_BINLOG_FSYNC_PERIOD=
<% end -%>

# The size of each binlog file.  This is rounded
# up to the nearest 512 byte boundary.
<% if @binlogsize -%>
BEANSTALKD_BINLOG_SIZE=<%= @binlogsize %>
<% else -%>
#use default
#BEANSTALKD_BINLOG_SIZE=10485760
<% end -%>


options=""

##the debian init script leaves everything to be desired.  so lets put our setup logic here.

case "$1" in
	start|restart|force-reload|reload)
		exec=$DAEMON
		[ -x $exec ] || exit 5
		
		# if not running, start it up here, usually something like "daemon $exec"
		options="-l ${BEANSTALKD_ADDR} -p ${BEANSTALKD_PORT} -u ${BEANSTALKD_USER}"
		if [ "${BEANSTALKD_MAX_JOB_SIZE}" != ""  ]; then
			options="${options} -z ${BEANSTALKD_MAX_JOB_SIZE}"
		fi
		
		if [ "${BEANSTALKD_BINLOG_DIR}" != "" ]; then
			if [ ! -d "${BEANSTALKD_BINLOG_DIR}" ]; then
				echo "Creating binlog directory (${BEANSTALKD_BINLOG_DIR})"
				mkdir -p ${BEANSTALKD_BINLOG_DIR} && chown ${BEANSTALKD_USER}:${BEANSTALKD_USER} ${BEANSTALKD_BINLOG_DIR}
			fi
			options="${options} -b ${BEANSTALKD_BINLOG_DIR}"
			if [ "${BEANSTALKD_BINLOG_FSYNC_PERIOD}" != "" ]; then
				options="${options} -f ${BEANSTALKD_BINLOG_FSYNC_PERIOD}"
			else
				options="${options} -F"
			fi
			if [ "${BEANSTALKD_BINLOG_SIZE}" != "" ]; then
				options="${options} -s ${BEANSTALKD_BINLOG_SIZE}"
			fi
		
			##1.4.6 at least is prone to leave a lock file around after shutting down
			##this breaks startup after upgrade to 1.5, so work around this
			##unknown if this happens w/o binlog enabled...
			#check for stale lock file in binlog
			if [ -e "${BEANSTALKD_BINLOG_DIR}/lock" ]
			 then
				if ! ps xa| grep -v grep | grep -q $exec
				 then
					echo "found old lock file and beanstalk isn't running - deleting it"
					rm -f ${BEANSTALKD_BINLOG_DIR}/lock
				fi
			fi
		fi
	
		if [ -n "${BEANSTALKD_MAXCONNECTIONS}" ]; then
			#increase open files ulimit to support higher concurrent connections
			echo "increasing open file limit to $BEANSTALKD_MAXCONNECTIONS"
			ulimit -n $BEANSTALKD_MAXCONNECTIONS
		fi
	;;
	*)
		#nothing, please keep moving
	;;
esac


DAEMON_OPTS="$options"
DAEMONUSER=$BEANSTALKD_USER


## Uncomment to enable startup during boot.
START=yes

# System configuration for the beanstalkd daemon

# Available options correspond to the options to the
# beanstalkd commandline.

<% if @maxconnections -%>
BEANSTALKD_MAXCONNECTIONS=<%= @maxconnections %>
<% else -%>
#use default ulimit
#BEANSTALKD_MAXCONNECTIONS=1024
<% end -%>


BEANSTALKD_ADDR=<%= @listenaddress %>
BEANSTALKD_PORT=<%= @listenport %>
BEANSTALKD_USER=<%= @user %>

# Job size is left to the default. Uncomment and set it
# to a value to have it take affect.
<% if @maxjobsize -%>
BEANSTALKD_MAX_JOB_SIZE=<%= @maxjobsize %>
<% else -%>
#use default
#BEANSTALKD_MAX_JOB_SIZE=65535
<% end -%>

# Using the binlog is off by default.
#
# The direcory to house the binlog.
<% if @binlogdir -%>
BEANSTALKD_BINLOG_DIR=<%= @binlogdir %>
<% else -%>
#use default
#BEANSTALKD_BINLOG_DIR=/var/lib/beanstalkd/binlog
<% end -%>

# fsync the binlog at most once every N milliseconds.
# setting this to 0 means 'always fsync'. If this is unset,
# and the binlog is used, then no explicit fsync is ever
# performed.  That is, the -F option is used.
<% if @binlogfsync -%>
BEANSTALKD_BINLOG_FSYNC_PERIOD=<%= @bbinlogfsync %>
<% else -%>
#use default
#BEANSTALKD_BINLOG_FSYNC_PERIOD=
<% end -%>

# The size of each binlog file.  This is rounded
# up to the nearest 512 byte boundary.
<% if @binlogsize -%>
BEANSTALKD_BINLOG_SIZE=<%= @binlogsize %>
<% else -%>
#use default
#BEANSTALKD_BINLOG_SIZE=10485760
<% end -%>

fixtures:
  repositories:
    git: "git://github.com/puppetlabs/puppetlabs-git"
  symlinks:
    composer: "#{source_dir}"
language: ruby
rvm:
  - 1.9.3
before_script:
after_script:
script: "bundle exec rake spec"
env:
  - PUPPET_VERSION=2.7.23
  - PUPPET_VERSION=3.0.2
  - PUPPET_VERSION=3.2.4
  - PUPPET_VERSION=3.3.0
notifications:
  email: false
v1.2.1
======
f44b7e5 Now also supports Amazon Linux (RedHat)

9341805 Now `suhosin_enabled` parameter is correctly documented.

v1.2.0
======
66b071a (HEAD, tag: 1.2.0, master) Bumping version to 1.2.0

166ec87 Updated README.md

626ee43 (origin/master, origin/HEAD) Updated CHANGELOG format

1364058 Moved CHANGELOG to markdown format

6f21dcb Updated LICENSE file

6209eb8 Added CHANGELOG file

6307d5a Add parameter 'php_bin' to override name or path of php binary

9e484e9 (origin/rspec_head_fixes, rspec_head_fixes) just match on errorname, not specific exception

db4176e update specs for latest rspec-puppet 1.0.1+

v1.1.1
======
17b2309 (tag: 1.1.1) Update Modulefile

d848038 Used puppetlabs/git >= 0.0.2

0d75cff doc updates for 1.1.0 release

v1.1.0
======
3b46e4d (tag: 1.1.0) bumping version to 1.1.0 for refreshonly and user features

5290e8e support setting exec user for project and exec

6af1e25 ignore puppet module package folder

c2106ec Add refreshonly parameter to exec

v1.0.1
======
fb1fd04 (tag: 1.0.1) Bumped version to 1.0.1

bf43913 (origin/deprecated_erb_variables) fix deprecated variables in the exec erb template

342b898 (origin/documentation_refactor) document refactor, add spec test information

3677acc adding tests for new suhosin_enable param and Debian family

de86c0d Only run augeas commands if suhosin is enabled

v1.0.0
======
f5d214a (tag: 1.0.0) Bumping version to 1.0.0

12589bf fixes for travis-ci building

5279b92 spec testing using rspec-puppet

3069608 documentation updates for composer_home and previous PRs

b5faa45 add a composer_home fact and use it to set up environment

v0.1.1
======
dbc0c74 Bumping version to 0.1.1

b4833d6 no-custom-installers is deprecated in favor of no-plugins

acdc73c dry up the composer binary download code

41f3a7b CentOS isn't actually an $::osfamily value

d54c0db PHP binary is provided by php-cli on RHEL systems

v0.1.0
======
1e8f9f1 (tag: 0.1.0) Adding License file.

523c28f (igalic/option-names, igalic-option-names) update readme with the new options

3d2ddda double-negating option names is confusing

be518cf (igalic/style, igalic-style) Fix puppet lint complaints

4050077 There's no need for these files to be executable

522e93c Updated temp path.

bf0f9e7 Support centos/redhat

f45e9de Support redhat/centos

920d1ca Support redhat/centos

v0.0.6
======
78643ef (tag: 0.0.6) Bumping version to 0.0.6

0fbfb53 Fixing bug where global path is overwritten by local scope.

v0.0.5
======
ee4e49b (tag: 0.0.5) Bumping version to 0.0.5

17ca5ee Added varaible composer path to exec calls.

v0.0.4
======
e94be5e (tag: 0.0.4) Bumping version to 0.0.4

a27e45f Fixed dry_run parameter

28cfee8 Adding version parameter to project task README

v0.0.3
======
4787b24 Bumping version to 0.0.3

4ee9547 (tag: 0.0.3) Fixing type in exec manifest.

v0.0.2
======
974d2ad (tag: 0.0.2) Bumping version to 0.0.2

667eb18 Fixed README

925aa97 Fixed Modulefile.
#ruby=1.9.3@puppet-composer

if ENV.key?('PUPPET_VERSION')
  puppetversion = "= #{ENV['PUPPET_VERSION']}"
else
  puppetversion = ['>= 2.7']
end

source 'https://rubygems.org'

ruby '1.9.3'

gem 'puppet', puppetversion
gem 'puppetlabs_spec_helper'
gem 'rspec-puppet', :github => 'rodjek/rspec-puppet', :ref => '03e94422fb9bbdd950d5a0bec6ead5d76e06616b'
gem 'mocha'
gem 'puppet-lint'
The MIT License (MIT)

Copyright (c) 2013 - 2014 Thomas Ploch

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
name 'tPl0ch-composer'
version '1.2.1'
dependency 'puppetlabs/git', '>= 0.0.2'
summary "This module provides the 'Composer' PHP dependency manager."
description "This module installs the 'Composer' PHP dependency manager and provides some custom types to create, update
    and install projects. Until now the Debian and Redhat OS families are supported."
project_page "https://github.com/tPl0ch/puppet-composer"
author "tPl0ch - Thomas Ploch <profiploch@gmail.com>"
# Composer Puppet Module

[![Build Status](https://travis-ci.org/tPl0ch/puppet-composer.png?branch=master)](https://travis-ci.org/tPl0ch/puppet-composer)

## Description

The `puppet-composer` module installs the latest version of Composer from http://getcomposer.org. Composer is a dependency manager for PHP.

## Supported Platforms

* `Debian`
* `Redhat`
* `Centos`
* `Amazon Linux`

## Installation

#### Puppet Forge
We recommend installing using the Puppet Forge as it automatically satisfies dependencies.

    puppet module install --target-dir=/your/path/to/modules tPl0ch-composer

#### Installation via git submodule
You can also install as a git submodule and handle the dependencies manually. See the [Dependencies](#dependencies) section below.

    git submodule add git://github.com/tPl0ch/puppet-composer.git modules/composer

## Dependencies

This module requires the following Puppet modules:

* [`puppetlabs-git`](https://github.com/puppetlabs/puppetlabs-git/)

And additional (for puppet version lower than 3.0.0) you need:

* [`libaugeas`](http://augeas.net/) (For automatically updating php.ini settings for suhosin patch)

## Usage
To install the `composer` binary globally in `/usr/local/bin` you only need to declare the `composer` class. We try to set some sane defaults. There are also a number of parameters you can tweak should the defaults not be sufficient.

### Simple Include
To install the binary with the defaults you just need to include the following in your manifests:

    include composer

### Full Include
Alternatively, you can set a number of options by declaring the class with parameters:

```puppet
class { 'composer':
    target_dir      => '/usr/local/bin',
    composer_file   => 'composer', # could also be 'composer.phar'
    download_method => 'curl',     # or 'wget'
    logoutput       => false,
    tmp_path        => '/tmp',
    php_package     => 'php5-cli',
    curl_package    => 'curl',
    wget_package    => 'wget',
    composer_home   => '/root',
    php_bin         => 'php', # could also i.e. be 'php -d "apc.enable_cli=0"' for more fine grained control
    suhosin_enabled => true,
}
```

### Creating Projects

The `composer::project` definition provides a way to create projects in a target directory.

```puppet
composer::project { 'silex':
    project_name   => 'fabpot/silex-skeleton',  # REQUIRED
    target_dir     => '/vagrant/silex', # REQUIRED
    version        => '2.1.x-dev', # Some valid version string
    prefer_source  => true,
    stability      => 'dev', # Minimum stability setting
    keep_vcs       => false, # Keep the VCS information
    dev            => true, # Install dev dependencies
    repository_url => 'http://repo.example.com', # Custom repository URL
    user           => undef, # Set the user to run as
}
```

#### Updating Packages

The `composer::exec` definition provides a more generic wrapper arround composer `update` and `install` commands. The following example will update the `silex/silex` and `symfony/browser-kit` packages in the `/vagrant/silex` directory. You can omit `packages` to update the entire project.

```puppet
composer::exec { 'silex-update':
    cmd                  => 'update',  # REQUIRED
    cwd                  => '/vagrant/silex', # REQUIRED
    packages             => ['silex/silex', 'symfony/browser-kit'], # leave empty or omit to update whole project
    prefer_source        => false, # Only one of prefer_source or prefer_dist can be true
    prefer_dist          => false, # Only one of prefer_source or prefer_dist can be true
    dry_run              => false, # Just simulate actions
    custom_installers    => false, # No custom installers
    scripts              => false, # No script execution
    interaction          => false, # No interactive questions
    optimize             => false, # Optimize autoloader
    dev                  => false, # Install dev dependencies
    user                 => undef, # Set the user to run as
    refreshonly          => false, # Only run on refresh
}
```

#### Installing Packages

We support the `install` command in addition to `update`. The install command will ignore the `packages` parameter and the following example is the equivalent to running `composer install` in the `/vagrant/silex` directory.

```puppet
composer::exec { 'silex-install':
    cmd                  => 'install',  # REQUIRED
    cwd                  => '/vagrant/silex', # REQUIRED
    prefer_source        => false,
    prefer_dist          => false,
    dry_run              => false, # Just simulate actions
    custom_installers    => false, # No custom installers
    scripts              => false, # No script execution
    interaction          => false, # No interactive questions
    optimize             => false, # Optimize autoloader
    dev                  => false, # Install dev dependencies
}
```

## Development

We have `rspec-puppet` and Travis CI setup for the project. To run the spec tests locally you need `bundler` installed:

```
gem install bundler
```

Then you can install the required gems:

```
bundle install
```

Finally, the tests can be run:

```
rake spec
```

## Contributing

We welcome everyone to help develop this module. To contribute:

* Fork this repository
* Add features and spec tests for them
* Commit to feature named branch
* Open a pull request outlining your changes and the reasoning for them

## Todo

* Add a `composer::require` type
require 'puppet-lint/tasks/puppet-lint'
require 'puppetlabs_spec_helper/rake_tasks'
Facter.add(:composer_home) do
  setcode do
    ENV['HOME']
  end
end
# == Type: composer::exec
#
# Either installs from composer.json or updates project or specific packages
#
# === Authors
#
# Thomas Ploch <profiploch@gmail.com>
#
# === Copyright
#
# Copyright 2013 Thomas Ploch
#
define composer::exec (
  $cmd,
  $cwd,
  $packages          = [],
  $prefer_source     = false,
  $prefer_dist       = false,
  $dry_run           = false,
  $custom_installers = false,
  $scripts           = false,
  $optimize          = false,
  $interaction       = false,
  $dev               = false,
  $logoutput         = false,
  $verbose           = false,
  $refreshonly       = false,
  $user              = undef,
) {
  require composer
  require git

  Exec {
    path        => "/bin:/usr/bin/:/sbin:/usr/sbin:${composer::target_dir}",
    environment => "COMPOSER_HOME=${composer::composer_home}",
    user        => $user,
  }

  if $cmd != 'install' and $cmd != 'update' {
    fail("Only types 'install' and 'update' are allowed, ${cmd} given")
  }

  if $prefer_source and $prefer_dist {
    fail('Only one of \$prefer_source or \$prefer_dist can be true.')
  }

  $command = "${composer::php_bin} ${composer::target_dir}/${composer::composer_file} ${cmd}"

  exec { "composer_update_${title}":
    command     => template('composer/exec.erb'),
    cwd         => $cwd,
    logoutput   => $logoutput,
    refreshonly => $refreshonly
  }
}
# == Class: composer
#
# The parameters for the composer class and corresponding definitions
#
# === Parameters
#
# Document parameters here.
#
# [*target_dir*]
#   The target dir that composer should be installed to.
#   Defaults to ```/usr/local/bin```.
#
# [*composer_file*]
#   The name of the composer binary, which will reside in ```target_dir```.
#
# [*download_method*]
#   Either ```curl``` or ```wget```.
#
# [*logoutput*]
#   If the output should be logged. Defaults to FALSE.
#
# [*tmp_path*]
#   Where the composer.phar file should be temporarily put.
#
# [*php_package*]
#   The Package name of tht PHP CLI package.
#
# [*curl_package*]
#   The name of the curl package to override the default set in the
#   composer::params class.
#
# [*wget_package*]
#   The name of the wget package to override the default set in the
#   composer::params class.
#
# [*composer_home*]
#   Folder to use as the COMPOSER_HOME environment variable. Default comes
#   from our composer::params class which derives from our own $composer_home
#   fact. The fact returns the current users $HOME environment variable.
#
# [*php_bin*]
#   The name or path of the php binary to override the default set in the
#   composer::params class.
#
# === Authors
#
# Thomas Ploch <profiploch@gmail.com>
#
class composer(
  $target_dir      = $composer::params::target_dir,
  $composer_file   = $composer::params::composer_file,
  $download_method = $composer::params::download_method,
  $logoutput       = $composer::params::logoutput,
  $tmp_path        = $composer::params::tmp_path,
  $php_package     = $composer::params::php_package,
  $curl_package    = $composer::params::curl_package,
  $wget_package    = $composer::params::wget_package,
  $composer_home   = $composer::params::composer_home,
  $php_bin         = $composer::params::php_bin,
  $suhosin_enabled = $composer::params::suhosin_enabled
) inherits composer::params {

  Exec { path => "/bin:/usr/bin/:/sbin:/usr/sbin:${target_dir}" }

  if defined(Package[$php_package]) == false {
    package { $php_package: ensure => present, }
  }

  # download composer
  case $download_method {
    'curl': {
      $download_command = "curl -s http://getcomposer.org/installer | ${composer::php_bin}"
      $download_require = $suhosin_enabled ? {
        true  => [ Package['curl', $php_package], Augeas['allow_url_fopen', 'whitelist_phar'] ],
        false => [ Package['curl', $php_package] ]
      }
      $method_package = $curl_package
    }
    'wget': {
      $download_command = 'wget http://getcomposer.org/composer.phar -O composer.phar'
      $download_require = $suhosin_enabled ? {
        true  => [ Package['wget', $php_package], Augeas['allow_url_fopen', 'whitelist_phar'] ],
        false => [ Package['wget', $php_package] ]
      }
      $method_package = $wget_package
    }
    default: {
      fail("The param download_method ${download_method} is not valid. Please set download_method to curl or wget.")
    }
  }

  if defined(Package[$method_package]) == false {
    package { $method_package: ensure => present, }
  }

  exec { 'download_composer':
    command   => $download_command,
    cwd       => $tmp_path,
    require   => $download_require,
    creates   => "${tmp_path}/composer.phar",
    logoutput => $logoutput,
  }

  # check if directory exists
  file { $target_dir:
    ensure => directory,
  }

  # move file to target_dir
  file { "${target_dir}/${composer_file}":
    ensure  => present,
    source  => "${tmp_path}/composer.phar",
    require => [ Exec['download_composer'], File[$target_dir] ],
    mode    => 0755,
  }

  if $suhosin_enabled {
    case $family {

      'Redhat','Centos': {

        # set /etc/php5/cli/php.ini/suhosin.executor.include.whitelist = phar
        augeas { 'whitelist_phar':
          context     => '/files/etc/suhosin.ini/suhosin',
          changes     => 'set suhosin.executor.include.whitelist phar',
          require     => Package[$php_package],
        }

        # set /etc/cli/php.ini/PHP/allow_url_fopen = On
        augeas{ 'allow_url_fopen':
          context     => '/files/etc/php.ini/PHP',
          changes     => 'set allow_url_fopen On',
          require     => Package[$php_package],
        }

      }
     'Debian': {

        # set /etc/php5/cli/php.ini/suhosin.executor.include.whitelist = phar
        augeas { 'whitelist_phar':
          context     => '/files/etc/php5/conf.d/suhosin.ini/suhosin',
          changes     => 'set suhosin.executor.include.whitelist phar',
          require     => Package[$php_package],
        }

        # set /etc/php5/cli/php.ini/PHP/allow_url_fopen = On
        augeas{ 'allow_url_fopen':
          context     => '/files/etc/php5/cli/php.ini/PHP',
          changes     => 'set allow_url_fopen On',
          require     => Package[$php_package],
        }

      }
    }
  }
}
# == Class: composer::params
#
# The parameters for the composer class and corresponding definitions
#
# === Authors
#
# Thomas Ploch <profiploch@gmail.com>
# Andrew Johnstone <andrew@ajohnstone.com>
#
# === Copyright
#
# Copyright 2013 Thomas Ploch
#
class composer::params {
  $composer_home = $::composer_home

  # Support Amazon Linux which is supported by RedHat family
  if $::osfamily == 'Linux' and $::operatingsystem == 'Amazon' {
    $family = 'RedHat'
  } else {
    $family = $::osfamily
  }

  case $family {
    'Debian': {
      $target_dir      = '/usr/local/bin'
      $composer_file   = 'composer'
      $download_method = 'curl'
      $logoutput       = false
      $tmp_path        = '/tmp'
      $php_package     = 'php5-cli'
      $curl_package    = 'curl'
      $wget_package    = 'wget'
      $php_bin         = 'php'
      $suhosin_enabled = true
    }
    'RedHat', 'Centos': {
      $target_dir      = '/usr/local/bin'
      $composer_file   = 'composer'
      $download_method = 'curl'
      $logoutput       = false
      $tmp_path        = '/tmp'
      $php_package     = 'php-cli'
      $curl_package    = 'curl'
      $wget_package    = 'wget'
      $php_bin         = 'php'
      $suhosin_enabled = true
    }
    default: {
      fail("Unsupported platform: ${family}")
    }
  }
}
# == Type: composer::project
#
# Installs a given project with composer create-project
#
# === Parameters
#
# Document parameters here.
#
# [*target_dir*]
#   The target dir that composer should be installed to.
#   Defaults to ```/usr/local/bin```.
#
# [*composer_file*]
#   The name of the composer binary, which will reside in ```target_dir```.
#
# [*download_method*]
#   Either ```curl``` or ```wget```.
#
# [*logoutput*]
#   If the output should be logged. Defaults to FALSE.
#
# [*tmp_path*]
#   Where the composer.phar file should be temporarily put.
#
# [*php_package*]
#   The Package name of the PHP CLI package.
#
# [*user*]
#   The user name to exec the composer commands as. Default is undefined.
#
# === Authors
#
# Thomas Ploch <profiploch@gmail.com>
#
# === Copyright
#
# Copyright 2013 Thomas Ploch
#
define composer::project(
  $project_name,
  $target_dir,
  $version        = undef,
  $dev            = false,
  $prefer_source  = false,
  $stability      = 'dev',
  $repository_url = undef,
  $keep_vcs       = false,
  $tries          = 3,
  $timeout        = 1200,
  $user           = undef,
) {
  require git
  require composer

  Exec {
    path        => "/bin:/usr/bin/:/sbin:/usr/sbin:${composer::target_dir}",
    environment => "COMPOSER_HOME=${composer::composer_home}",
    user        => $user,
  }

  $exec_name    = "composer_create_project_${title}"
  $base_command = "${composer::php_bin} ${composer::target_dir}/${composer::composer_file} --stability=${stability}"
  $end_command  = "${project_name} ${target_dir}"

  $dev_arg = $dev ? {
    true    => ' --dev',
    default => '',
  }

  $vcs = $keep_vcs? {
    true    => ' --keep-vcs',
    default => '',
  }

  $repo = $repository_url? {
    undef   => '',
    default => " --repository-url=${repository_url}",
  }

  $pref_src = $prefer_source? {
    true  => ' --prefer-source',
    false => ''
  }

  $v = $version? {
    undef   => '',
    default => " ${version}",
  }

  exec { $exec_name:
    command => "${base_command}${dev_arg}${repo}${pref_src}${vcs} create-project ${end_command}${v}",
    tries   => $tries,
    timeout => $timeout,
    creates => $target_dir,
  }
}
require 'spec_helper'

describe 'composer::params' do
  ['RedHat', 'Debian', 'Linux'].each do |osfamily|
    context "on #{osfamily} operating system family" do
      let(:facts) { {
        :osfamily        => osfamily,
        :operatingsystem => 'Amazon',
      } }

      it { should compile }
    end
  end
end
require 'spec_helper'

describe 'composer' do
  ['RedHat', 'Debian', 'Linux'].each do |osfamily|
    case osfamily
    when 'RedHat'
      php_package = 'php-cli'
      php_context = '/files/etc/php.ini/PHP'
      suhosin_context = '/files/etc/suhosin.ini/suhosin'
    when 'Linux'
      php_package = 'php-cli'
      php_context = '/files/etc/php.ini/PHP'
      suhosin_context = '/files/etc/suhosin.ini/suhosin'
    when 'Debian'
      php_package = 'php5-cli'
      php_context = '/files/etc/php5/cli/php.ini/PHP'
      suhosin_context = '/files/etc/php5/conf.d/suhosin.ini/suhosin'
    else
      php_package = 'php-cli'
      php_context = '/files/etc/php.ini/PHP'
      suhosin_context = '/files/etc/suhosin.ini/suhosin'
    end

    context "on #{osfamily} operating system family" do
      let(:facts) { {
          :osfamily        => osfamily,
          :operatingsystem => 'Amazon'
      } }

      it { should contain_class('composer::params') }

      it {
        should contain_exec('download_composer').with({
          :command     => 'curl -s http://getcomposer.org/installer | php',
          :cwd         => '/tmp',
          :creates     => '/tmp/composer.phar',
          :logoutput   => false,
        })
      }

      it {
        should contain_augeas('whitelist_phar').with({
          :context     => suhosin_context,
          :changes     => 'set suhosin.executor.include.whitelist phar',
        })
      }

      it {
        should contain_augeas('allow_url_fopen').with({
          :context    => php_context,
          :changes    => 'set allow_url_fopen On',
        })
      }

      context 'with default parameters' do
        it 'should compile' do
          compile
        end

        it { should contain_package(php_package).with_ensure('present') }
        it { should contain_package('curl').with_ensure('present') }
        it { should contain_file('/usr/local/bin').with_ensure('directory') }

        it {
          should contain_file('/usr/local/bin/composer').with({
            :source => 'present',
            :source => '/tmp/composer.phar',
            :mode   => '0755',
          })
        }
      end

      context "on invalid operating system family" do
        let(:facts) { {
          :osfamily        => 'Invalid',
          :operatingsystem => 'Amazon'
        } }

        it 'should not compile' do
          expect { should compile }.to raise_error(/Unsupported platform: Invalid/)
        end
      end

      context 'with custom parameters' do
        let(:params) { {
          :target_dir      => '/you_sir/lowcal/been',
          :php_package     => 'php8-cli',
          :composer_file   => 'compozah',
          :curl_package    => 'kerl',
          :php_bin         => 'pehpe',
          :suhosin_enabled => false,
        } }

        it 'should compile' do
          compile
        end

        it { should contain_package('php8-cli').with_ensure('present') }
        it { should contain_package('kerl').with_ensure('present') }
        it { should contain_file('/you_sir/lowcal/been').with_ensure('directory') }

        it {
          should contain_file('/you_sir/lowcal/been/compozah').with({
            :source => 'present',
            :source => '/tmp/composer.phar',
            :mode   => '0755',
          })
        }

        it { should_not contain_augeas('whitelist_phar') }
        it { should_not contain_augeas('allow_url_fopen') }

      end
    end
  end
end
require 'spec_helper'

describe 'composer::exec' do
  ['RedHat', 'Debian'].each do |osfamily|
    context "on #{osfamily} operating system family" do
      let(:facts) { {
          :osfamily => osfamily,
      } }

      context 'using install command' do
        it { should contain_class('git') }
        it { should contain_class('composer') }

        let(:title) { 'myproject' }
        let(:params) { {
          :cmd  => 'install',
          :cwd  => '/my/awesome/project',
          :user => 'linus',
        } }

        it {
          should contain_exec('composer_update_myproject').with({
            :command       => %r{php /usr/local/bin/composer install --no-plugins --no-scripts --no-interaction},
            :cwd       => '/my/awesome/project',
            :user      => 'linus',
            :logoutput => false,
          })
        }
      end

      context 'using update command' do
        it { should contain_class('git') }
        it { should contain_class('composer') }

        let(:title) { 'yourpr0ject' }
        let(:params) { {
          :cmd       => 'update',
          :cwd       => '/just/in/time',
          :packages  => ['package1', 'packageinf'],
          :logoutput => true,
        } }

        it {
          should contain_exec('composer_update_yourpr0ject').without_user.with({
            :command   => %r{php /usr/local/bin/composer update --no-plugins --no-scripts --no-interaction             package1             packageinf},
            :cwd       => '/just/in/time',
            :logoutput => true,
          })
        }
      end
    end
  end

  context 'on unsupported operating system family' do
    let(:facts) { {
      :osfamily => 'Darwin',
    } }

    let(:title) { 'someproject' }

    it 'should not compile' do
      expect { should compile }.to raise_error(/Unsupported platform: Darwin/)
    end
  end
end
require 'spec_helper'

describe 'composer::project' do
  ['RedHat', 'Debian'].each do |osfamily|
    context "on #{osfamily} operating system family" do
      let(:facts) { {
            :osfamily => osfamily,
        } }

      context 'with default params' do
        let(:title) { 'myproject' }
        let(:params) { {
          :project_name => 'projectzzz',
          :target_dir   => '/my/subpar/project',
        } }

        it { should contain_class('git') }
        it { should contain_class('composer') }

        it {
          should contain_exec('composer_create_project_myproject').without_user.with({
            :command => "php /usr/local/bin/composer --stability=dev create-project projectzzz /my/subpar/project",
            :tries   => 3,
            :timeout => 1200,
            :creates => '/my/subpar/project',
          })
        }
      end

      context 'with all custom params' do
        let(:title) { 'whoadawg' }
        let(:params) { {
          :project_name   => 'whoadawg99',
          :target_dir     => '/my/mediocre/project',
          :version        => '0.0.8',
          :dev            => true,
          :prefer_source  => true,
          :stability      => 'dev',
          :repository_url => 'git@github.com:trollface/whoadawg.git',
          :keep_vcs       => true,
          :tries          => 2,
          :timeout        => 600,
          :user           => 'mrploch',
        } }

        it { should contain_class('git') }
        it { should contain_class('composer') }

        it {
          should contain_exec('composer_create_project_whoadawg').with({
            :command => %r{php /usr/local/bin/composer --stability=dev --dev --repository-url=git@github.com:trollface/whoadawg.git --prefer-source --keep-vcs create-project whoadawg99 /my/mediocre/project 0.0.8},
            :tries   => 2,
            :timeout => 600,
            :creates => '/my/mediocre/project',
            :user    => 'mrploch',
          })
        }
      end
    end
  end
end
node default {
  include composer

  composer::exec {'ohai':
    cmd => 'install',
    cwd => '/some/cool/dir',
  }
}
s
mtime
require 'puppetlabs_spec_helper/module_spec_helper'
<%= @command -%>
<% if @prefer_source %> --prefer-source<% end -%>
<% if @prefer_dist %> --prefer-dist<% end -%>
<% unless @custom_installers %> --no-plugins<% end -%>
<% unless @scripts %> --no-scripts<% end -%>
<% unless @interaction %> --no-interaction<% end -%>
<% if @dev %> --dev<% end -%>
<% if @verbose %> -v<% end -%>
<% if @dry_run %> --dry-run<% end -%>
<% if @cmd == 'update' -%>
    <%- if @packages -%>
        <%- @packages.each do |package| -%>
            <%= ' ' + package -%>
        <%- end -%>
    <%- end -%>
<% end -%>

# The baseline for module testing used by Puppet Labs is that each manifest
# should have a corresponding test manifest that declares that class or defined
# type.
#
# Tests are then run by using puppet apply --noop (to check for compilation errors
# and view a log of events) or by fully applying the test in a virtual environment
# (to compare the resulting system state to the desired state).
#
# Learn more about module testing here: http://docs.puppetlabs.com/guides/tests_smoke.html
#
include composer
# The baseline for module testing used by Puppet Labs is that each manifest
# should have a corresponding test manifest that declares that class or defined
# type.
#
# Tests are then run by using puppet apply --noop (to check for compilation errors
# and view a log of events) or by fully applying the test in a virtual environment
# (to compare the resulting system state to the desired state).
#
# Learn more about module testing here: http://docs.puppetlabs.com/guides/tests_smoke.html
#

composer::project { 'my_first_test':
  project_name => 'fabpot/silex-skeleton',
  target_dir   => '/tmp/first_test',
}

composer::project { 'my_second_test':
  project_name  => 'fabpot/silex-skeleton',
  target_dir    => '/tmp/second_test',
  prefer_source => true,
  stability     => 'dev',
}

fixtures:
  repositories:
    'stdlib':
      repo: 'git://github.com/puppetlabs/puppetlabs-stdlib.git'
      ref: '4.0.0'
  symlinks:
    'concat': '#{source_dir}'
*.sh  eol=lf
branches:
  only:
    - master
language: ruby
bundler_args: --without development
script: bundle exec rake spec SPEC_OPTS='--format documentation'
# work around RubyGems 2.2.0 breaking ruby 1.8.7
# https://github.com/rubygems/rubygems/pull/763
# https://github.com/freerange/mocha/commit/66bab2a8f4e7cd8734bf88e6f32157c0d5153125
before_install:
  - gem update --system 2.1.11
  - gem --version
rvm:
  - 1.8.7
  - 1.9.3
  - 2.0.0
env:
  matrix:
    - PUPPET_GEM_VERSION="2.7.3" FACTER_GEM_VERSION="1.6.0"
    - PUPPET_GEM_VERSION="~> 2.7.0" FACTER_GEM_VERSION="~> 1.6.0"
    - PUPPET_GEM_VERSION="~> 2.7.0" FACTER_GEM_VERSION="~> 1.7.0"
    - PUPPET_GEM_VERSION="~> 3.0"
matrix:
  fast_finish: true
  exclude:
    - rvm: 1.9.3
      env: PUPPET_GEM_VERSION="2.7.3" FACTER_GEM_VERSION="1.6.0"
    - rvm: 1.9.3
      env: PUPPET_GEM_VERSION="~> 2.7.0" FACTER_GEM_VERSION="~> 1.6.0"
    - rvm: 1.9.3
      env: PUPPET_GEM_VERSION="~> 2.7.0" FACTER_GEM_VERSION="~> 1.7.0"
    - rvm: 2.0.0
      env: PUPPET_GEM_VERSION="2.7.3" FACTER_GEM_VERSION="1.6.0"
    - rvm: 2.0.0
      env: PUPPET_GEM_VERSION="~> 2.7.0" FACTER_GEM_VERSION="~> 1.6.0"
    - rvm: 2.0.0
      env: PUPPET_GEM_VERSION="~> 2.7.0" FACTER_GEM_VERSION="~> 1.7.0"
notifications:
  email: false
2014-05-14 1.1.0

Summary

This release is primarily a bugfix release since 1.1.0-rc1.

Features:
- Improved testing, with tests moved to beaker

Bugfixes:
- No longer attempts to set fragment owner and mode on Windows
- Fix numeric sorting
- Fix incorrect quoting
- Fix newlines

2014-01-03 1.1.0-rc1

Summary:

This release of concat was 90% written by Joshua Hoblitt, and the module team
would like to thank him for the huge amount of work he put into this release.

This module deprecates a bunch of old parameters and usage patterns, modernizes
much of the manifest code, simplifies a whole bunch of logic and makes
improvements to almost all parts of the module.

The other major feature is windows support, courtesy of luisfdez, with an
alternative version of the concat bash script in ruby.  We've attempted to
ensure that there are no backwards incompatible changes, all users of 1.0.0
should be able to use 1.1.0 without any failures, but you may find deprecation
warnings and we'll be aggressively moving for a 2.0 to remove those too.

For further information on deprecations, please read:
https://github.com/puppetlabs/puppetlabs-concat/blob/master/README.md#api-deprecations

Removed:
- Puppet 0.24 support.
- Filebucket backup of all file resources except the target concatenated file.
- Default owner/user/group values.
- Purging of long unused /usr/local/bin/concatfragments.sh

Features:
- Windows support via a ruby version of the concat bash script.
- Huge amount of acceptance testing work added.
- Documentation (README) completely rewritten.
- New parameters in concat:
 - `ensure`: Controls if the file should be present/absent at all.
- Remove requirement to include concat::setup in manifests.
- Made `gnu` parameter deprecated.
- Added parameter validation.

Bugfixes:
- Ensure concat::setup runs before concat::fragment in all cases.
- Pluginsync references updated for modern Puppet.
- Fix incorrect group parameter.
- Use $owner instead of $id to avoid confusion with $::id
- Compatibility fixes for Puppet 2.7/ruby 1.8.7
- Use LC_ALL=C instead of LANG=C
- Always exec the concatfragments script as root when running as root.
- Syntax and other cleanup changes.

2013-08-09 1.0.0

Summary:

Many new features and bugfixes in this release, and if you're a heavy concat
user you should test carefully before upgrading.  The features should all be
backwards compatible but only light testing has been done from our side before
this release.

Features:
- New parameters in concat:
 - `replace`: specify if concat should replace existing files.
 - `ensure_newline`: controls if fragments should contain a newline at the end.
- Improved README documentation.
- Add rspec:system tests (rake spec:system to test concat)

Bugfixes
- Gracefully handle \n in a fragment resource name.
- Adding more helpful message for 'pluginsync = true'
- Allow passing `source` and `content` directly to file resource, rather than
defining resource defaults.
- Added -r flag to read so that filenames with \ will be read correctly.
- sort always uses LANG=C.
- Allow WARNMSG to contain/start with '#'.
- Replace while-read pattern with for-do in order to support Solaris.

CHANGELOG:
- 2010/02/19 - initial release
- 2010/03/12 - add support for 0.24.8 and newer
             - make the location of sort configurable
             - add the ability to add shell comment based warnings to
               top of files
             - add the ablity to create empty files
- 2010/04/05 - fix parsing of WARN and change code style to match rest
               of the code
             - Better and safer boolean handling for warn and force
             - Don't use hard coded paths in the shell script, set PATH
               top of the script
             - Use file{} to copy the result and make all fragments owned
               by root.  This means we can chnage the ownership/group of the
               resulting file at any time.
             - You can specify ensure => "/some/other/file" in concat::fragment
               to include the contents of a symlink into the final file.
- 2010/04/16 - Add more cleaning of the fragment name - removing / from the $name
- 2010/05/22 - Improve documentation and show the use of ensure =>
- 2010/07/14 - Add support for setting the filebucket behavior of files
- 2010/10/04 - Make the warning message configurable
- 2010/12/03 - Add flags to make concat work better on Solaris - thanks Jonathan Boyett
- 2011/02/03 - Make the shell script more portable and add a config option for root group
- 2011/06/21 - Make base dir root readable only for security
- 2011/06/23 - Set base directory using a fact instead of hardcoding it
- 2011/06/23 - Support operating as non privileged user
- 2011/06/23 - Support dash instead of bash or sh
- 2011/07/11 - Better solaris support
- 2011/12/05 - Use fully qualified variables
- 2011/12/13 - Improve Nexenta support
- 2012/04/11 - Do not use any GNU specific extensions in the shell script
- 2012/03/24 - Comply to community style guides
- 2012/05/23 - Better errors when basedir isnt set
- 2012/05/31 - Add spec tests
- 2012/07/11 - Include concat::setup in concat improving UX
- 2012/08/14 - Puppet Lint improvements
- 2012/08/30 - The target path can be different from the $name
- 2012/08/30 - More Puppet Lint cleanup
- 2012/09/04 - RELEASE 0.2.0
- 2012/12/12 - Added (file) $replace parameter to concat
source ENV['GEM_SOURCE'] || "https://rubygems.org"

group :development, :test do
  gem 'rake',                    :require => false
  gem 'rspec-puppet',            :require => false
  gem 'puppetlabs_spec_helper',  :require => false
  gem 'beaker',                  :require => false
  gem 'beaker-rspec',            :require => false
  gem 'puppet-lint',             :require => false
  gem 'serverspec',              :require => false
  gem 'pry',                     :require => false
end

if puppetversion = ENV['PUPPET_GEM_VERSION']
  gem 'puppet', puppetversion, :require => false
else
  gem 'puppet', :require => false
end

# vim:ft=ruby
   Copyright 2012 R.I.Pienaar

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

name 'puppetlabs-concat'
version '1.1.0'
source 'git://github.com/puppetlabs/puppetlabs-concat.git'
author 'Puppetlabs'
license 'Apache 2.0'
summary 'Concat module'
description 'Concat module'
project_page 'http://github.com/puppetlabs/puppetlabs-concat'
dependency 'puppetlabs/stdlib', '>= 4.0.0'
#Concat

[![Build Status](https://travis-ci.org/puppetlabs/puppetlabs-concat.png?branch=master)](https://travis-ci.org/puppetlabs/puppetlabs-concat)

####Table of Contents

1. [Overview](#overview)
2. [Module Description - What the module does and why it is useful](#module-description)
3. [Setup - The basics of getting started with concat](#setup)
    * [What concat affects](#what-concat-affects)
    * [Setup requirements](#setup-requirements)
    * [Beginning with concat](#beginning-with-concat)
4. [Usage - Configuration options and additional functionality](#usage)
    * [API _deprecations_](#api-deprecations)
5. [Reference - An under-the-hood peek at what the module is doing and how](#reference)
5. [Limitations - OS compatibility, etc.](#limitations)
6. [Development - Guide for contributing to the module](#development)

##Overview

This module constructs files from multiple fragments in an ordered way.

##Module Description

This module lets you use many concat::fragment{} resources throughout
your modules to construct a single file at the end.  It does this through
a shell (or ruby) script and a temporary holding space for the fragments.

##Setup

###What concat affects

* Installs concatfragments.[sh|rb] based on platform.
* Adds a concat/ directory into Puppets `vardir`.

###Beginning with concat

To start using concat you need to create:

* A concat{} resource for the final file.
* One or more concat::fragment{}'s. 

A minimal example might be:

```puppet
concat { '/tmp/file':
  ensure => present,
}

concat::fragment { 'tmpfile':
  target  => '/tmp/file'
  content => 'test contents',
  order   => '01'
}
```

##Usage

Please be aware that there have been a number of [API
_deprecations_](#api-deprecations).

If you wanted a /etc/motd file that listed all the major modules
on the machine.  And that would be maintained automatically even
if you just remove the include lines for other modules you could
use code like below, a sample /etc/motd would be:

<pre>
Puppet modules on this server:

    -- Apache
    -- MySQL
</pre>

Local sysadmins can also append to the file by just editing /etc/motd.local
their changes will be incorporated into the puppet managed motd.

```puppet
class motd {
  $motd = '/etc/motd'

  concat { $motd:
    owner => 'root',
    group => 'root',
    mode  => '0644'
  }

  concat::fragment{ 'motd_header':
    target  => $motd,
    content => "\nPuppet modules on this server:\n\n",
    order   => '01'
  }

  # local users on the machine can append to motd by just creating
  # /etc/motd.local
  concat::fragment{ 'motd_local':
    target => $motd,
    source => '/etc/motd.local',
    order  => '15'
  }
}

# used by other modules to register themselves in the motd
define motd::register($content="", $order=10) {
  if $content == "" {
    $body = $name
  } else {
    $body = $content
  }

  concat::fragment{ "motd_fragment_$name":
    target  => '/etc/motd',
    order   => $order,
    content => "    -- $body\n"
  }
}
```

To use this you'd then do something like:

```puppet
class apache {
  include apache::install, apache::config, apache::service

  motd::register{ 'Apache': }
}
```

##Reference

###Classes

####Public classes

####Private classes
* `concat::setup`: Sets up the concat script/directories.

###Parameters

###Defines

####concat

#####`ensure`
Controls if the combined file is present or absent.

######Example
- ensure => present
- ensure => absent

#####`path`
Controls the destination of the file to create.

######Example
- path => '/tmp/filename'

#####`owner`
Set the owner of the combined file.

######Example
- owner => 'root'

#####`group`
Set the group of the combined file.

######Example
- group => 'root'

#####`mode`
Set the mode of the combined file.

######Example
- mode => '0644'

#####`warn`
Determine if a warning message should be added at the top of the file to let
users know it was autogenerated by Puppet.

######Example
- warn => true
- warn => false

#####`warn_message`
Set the contents of the warning message.

######Example
- warn_message => 'This file is autogenerated!'

#####`force`
Determine if empty files are allowed when no fragments were added.

######Example
- force => true
- force => false

#####`backup`
Controls the filebucket behavior used for the file.

######Example
- backup => 'puppet'

#####`replace`
Controls if Puppet should replace the destination file if it already exists.

######Example
- replace => true
- replace => false

#####`order`
Controls the way in which the shell script chooses to sort the files.  It's
rare you'll need to adjust this.

######Allowed Values
- order => 'alpha'
- order => 'numeric'

#####`ensure_newline`
Ensure there's a newline at the end of the fragments.

######Example
- ensure_newline => true
- ensure_newline => false

####concat::fragment

#####`target`
Choose the destination file of the fragment.

######Example
- target => '/tmp/testfile'

#####`content`
Create the content of the fragment.

######Example
- content => 'test file contents'

#####`source`
Find the sources within Puppet of the fragment.

######Example
- source => 'puppet:///modules/test/testfile'
- source => ['puppet:///modules/test/1', 'puppet:///modules/test/2']

#####`order`
Order the fragments.

######Example
- order => '01'

#####`ensure`
Control the file of fragment created.

######Example
- ensure => 'present'
- ensure => 'absent'
- ensure => 'file'
- ensure => 'directory'

#####`mode`
Set the mode of the fragment.

######Example
- mode => '0644'

#####`owner`
Set the owner of the fragment.

######Example
- owner => 'root'

#####`group`
Set the group of the fragment.

######Example
- group => 'root'

#####`backup`
Control the filebucket behavior for the fragment.

######Example
- backup => 'puppet'

### API _deprecations_

#### Since version `1.0.0`

##### `concat{}` `warn` parameter

```puppet
concat { '/tmp/file':
  ensure => present,
  warn   => 'true',  # generates stringified boolean value warning
}
```

Using stringified Boolean values as the `warn` parameter to `concat` is
deprecated, generates a catalog compile time warning, and will be silently
treated as the concatenated file header/warning message in a future release.

The following strings are considered a stringified Boolean value:

 * `'true'`
 * `'yes'`
 * `'on'`
 * `'false'`
 * `'no'`
 * `'off'`

Please migrate to using the Puppet DSL's native [Boolean data
type](http://docs.puppetlabs.com/puppet/3/reference/lang_datatypes.html#booleans).

##### `concat{}` `gnu` parameter

```puppet
concat { '/tmp/file':
  ensure => present,
  gnu    => $foo,    # generates deprecation warning
}
```

The `gnu` parameter to `concat` is deprecated, generates a catalog compile time
warning, and has no effect.  This parameter will be removed in a future
release.

Note that this parameter was silently ignored in the `1.0.0` release.

##### `concat::fragment{}` `ensure` parameter

```puppet
concat::fragment { 'cpuinfo':
  ensure => '/proc/cpuinfo', # generates deprecation warning
  target => '/tmp/file',
}
```

Passing a value other than `'present'` or `'absent'` as the `ensure` parameter
to `concat::fragment` is deprecated and generates a catalog compile time
warning.  The warning will become a catalog compilation failure in a future
release.

This type emulates the Puppet core `file` type's disfavored [`ensure`
semantics](http://docs.puppetlabs.com/references/latest/type.html#file-attribute-ensure)
of treating a file path as a directive to create a symlink.  This feature is
problematic in several ways.  It copies an API semantic of another type that is
both frowned upon and not generally well known.  It's behavior may be
surprising in that the target concatenated file will not be a symlink nor is
there any common file system that has a concept of a section of a plain file
being symbolically linked to another file.  Additionally, the behavior is
generally inconsistent with most Puppet types in that a missing source file
will be silently ignored.

If you want to use the content of a file as a fragment please use the `source`
parameter.

##### `concat::fragment{}` `mode/owner/group` parameters

```puppet
concat::fragment { 'foo':
  target  => '/tmp/file',
  content => 'foo',
  mode    => $mode,       # generates deprecation warning
  owner   => $owner,      # generates deprecation warning
  group   => $group,      # generates deprecation warning
}
```

The `mode` parameter to `concat::fragment` is deprecated, generates a catalog compile time warning, and has no effect.

The `owner` parameter to `concat::fragment` is deprecated, generates a catalog
compile time warning, and has no effect.

The `group` parameter to `concat::fragment` is deprecated, generates a catalog
compile time warning, and has no effect.

These parameters had no user visible effect in version `1.0.0` and will be
removed in a future release.

##### `concat::fragment{}` `backup` parameter

```puppet
concat::fragment { 'foo':
  target  => '/tmp/file',
  content => 'foo',
  backup  => 'bar',       # generates deprecation warning
}
```

The `backup` parameter to `concat::fragment` is deprecated, generates a catalog
compile time warning, and has no effect.  It will be removed in a future
release.

In the `1.0.0` release this parameter controlled file bucketing of the file
fragment.  Bucketting the fragment(s) is redundant with bucketting the final
concatenated file and this feature has been removed.

##### `class { 'concat::setup': }`

```puppet
include concat::setup     # generates deprecation warning

class { 'concat::setup: } # generates deprecation warning
```

The `concat::setup` class is deprecated as a public API of this module and
should no longer be directly included in the manifest.  This class may be
removed in a future release.

##### Parameter validation

While not an API depreciation, users should be aware that all public parameters
in this module are now validated for at least variable type.  This may cause
validation errors in a manifest that was previously silently misbehaving.

##Limitations

This module has been tested on:

* RedHat Enterprise Linux (and Centos) 5/6
* Debian 6/7
* Ubuntu 12.04

Testing on other platforms has been light and cannot be guaranteed.

#Development

Puppet Labs modules on the Puppet Forge are open projects, and community
contributions are essential for keeping them great. We can’t access the
huge number of platforms and myriad of hardware, software, and deployment
configurations that Puppet is intended to serve.

We want to keep it as easy as possible to contribute changes so that our
modules work in your environment. There are a few guidelines that we need
contributors to follow so that we can have a chance of keeping on top of things.

You can read the complete module contribution guide [on the Puppet Labs wiki.](http://projects.puppetlabs.com/projects/module-site/wiki/Module_contributing)

###Contributors

The list of contributors can be found at:

https://github.com/puppetlabs/puppetlabs-concat/graphs/contributors
require 'puppetlabs_spec_helper/rake_tasks'
require 'puppet-lint/tasks/puppet-lint'

PuppetLint.configuration.send('disable_80chars')
PuppetLint.configuration.send('disable_quoted_booleans')
# Script to concat files to a config file.
#
# Given a directory like this:
# /path/to/conf.d
# |-- fragments
# |   |-- 00_named.conf
# |   |-- 10_domain.net
# |   `-- zz_footer
#
# The script supports a test option that will build the concat file to a temp location and
# use /usr/bin/cmp to verify if it should be run or not.  This would result in the concat happening
# twice on each run but gives you the option to have an unless option in your execs to inhibit rebuilds.
#
# Without the test option and the unless combo your services that depend on the final file would end up
# restarting on each run, or in other manifest models some changes might get missed.
#
# OPTIONS:
#  -o	The file to create from the sources
#  -d	The directory where the fragments are kept
#  -t	Test to find out if a build is needed, basically concats the files to a temp
#       location and compare with what's in the final location, return codes are designed
#       for use with unless on an exec resource
#  -w   Add a shell style comment at the top of the created file to warn users that it
#       is generated by puppet
#  -f   Enables the creation of empty output files when no fragments are found
#  -n	Sort the output numerically rather than the default alpha sort
#
# the command:
#
#   concatfragments.rb -o /path/to/conffile.cfg -d /path/to/conf.d
#
# creates /path/to/conf.d/fragments.concat and copies the resulting
# file to /path/to/conffile.cfg.  The files will be sorted alphabetically
# pass the -n switch to sort numerically.
#
# The script does error checking on the various dirs and files to make
# sure things don't fail.
require 'optparse'
require 'fileutils'

settings = {
  :outfile => "",
  :workdir => "",
  :test    => false,
  :force   => false,
  :warn    => "",
  :sortarg => ""
}

OptionParser.new do |opts|
  opts.banner = "Usage: #{$0} [options]"
  opts.separator "Specific options:"

  opts.on("-o", "--outfile OUTFILE", String, "The file to create from the sources") do |o|
    settings[:outfile] = o
  end

  opts.on("-d", "--workdir WORKDIR", String, "The directory where the fragments are kept") do |d|
    settings[:workdir] = d
  end

  opts.on("-t", "--test", "Test to find out if a build is needed") do
    settings[:test] = true
  end

  opts.separator "Other options:"
  opts.on("-w", "--warn WARNMSG", String,
          "Add a shell style comment at the top of the created file to warn users that it is generated by puppet") do |w|
    settings[:warn] = w
  end

  opts.on("-f", "--force", "Enables the creation of empty output files when no fragments are found") do
    settings[:force] = true
  end

  opts.on("-n", "--sort", "Sort the output numerically rather than the default alpha sort") do
    settings[:sortarg] = "-n"
  end
end.parse!

# do we have -o?
raise 'Please specify an output file with -o' unless !settings[:outfile].empty?

# do we have -d?
raise 'Please specify fragments directory with -d' unless !settings[:workdir].empty?

# can we write to -o?
if File.file?(settings[:outfile])
  if !File.writable?(settings[:outfile])
    raise "Cannot write to #{settings[:outfile]}"
  end
else
  if !File.writable?(File.dirname(settings[:outfile]))
    raise "Cannot write to dirname #{File.dirname(settings[:outfile])} to create #{settings[:outfile]}"
  end
end

# do we have a fragments subdir inside the work dir?
if !File.directory?(File.join(settings[:workdir], "fragments")) && !File.executable?(File.join(settings[:workdir], "fragments"))
  raise "Cannot access the fragments directory"
end

# are there actually any fragments?
if (Dir.entries(File.join(settings[:workdir], "fragments")) - %w{ . .. }).empty?
  if !settings[:force]
    raise "The fragments directory is empty, cowardly refusing to make empty config files"
  end
end

Dir.chdir(settings[:workdir])

if settings[:warn].empty?
  File.open("fragments.concat", 'w') {|f| f.write("") }
else
  File.open("fragments.concat", 'w') {|f| f.write("#{settings[:warn]}\n") }
end

# find all the files in the fragments directory, sort them numerically and concat to fragments.concat in the working dir
open('fragments.concat', 'a') do |f|
  Dir.entries("fragments").sort.each{ |entry|
    if File.file?(File.join("fragments", entry))
	  f << File.read(File.join("fragments", entry))
    end
  }
end

if !settings[:test]
  # This is a real run, copy the file to outfile
  FileUtils.cp 'fragments.concat', settings[:outfile]
else
  # Just compare the result to outfile to help the exec decide
  if FileUtils.cmp 'fragments.concat', settings[:outfile]
    exit 0
  else
    exit 1
  end
end
#!/bin/sh

# Script to concat files to a config file.
#
# Given a directory like this:
# /path/to/conf.d
# |-- fragments
# |   |-- 00_named.conf
# |   |-- 10_domain.net
# |   `-- zz_footer
#
# The script supports a test option that will build the concat file to a temp location and 
# use /usr/bin/cmp to verify if it should be run or not.  This would result in the concat happening
# twice on each run but gives you the option to have an unless option in your execs to inhibit rebuilds.
# 
# Without the test option and the unless combo your services that depend on the final file would end up 
# restarting on each run, or in other manifest models some changes might get missed.
#
# OPTIONS:
#  -o	The file to create from the sources
#  -d	The directory where the fragments are kept
#  -t	Test to find out if a build is needed, basically concats the files to a temp
#       location and compare with what's in the final location, return codes are designed
#       for use with unless on an exec resource
#  -w   Add a shell style comment at the top of the created file to warn users that it 
#       is generated by puppet
#  -f   Enables the creation of empty output files when no fragments are found
#  -n	Sort the output numerically rather than the default alpha sort
#
# the command: 
#
#   concatfragments.sh -o /path/to/conffile.cfg -d /path/to/conf.d
#
# creates /path/to/conf.d/fragments.concat and copies the resulting 
# file to /path/to/conffile.cfg.  The files will be sorted alphabetically
# pass the -n switch to sort numerically.
# 
# The script does error checking on the various dirs and files to make
# sure things don't fail.

OUTFILE=""
WORKDIR=""
TEST=""
FORCE=""
WARN=""
SORTARG=""
ENSURE_NEWLINE=""

PATH=/sbin:/usr/sbin:/bin:/usr/bin

## Well, if there's ever a bad way to do things, Nexenta has it.
## http://nexenta.org/projects/site/wiki/Personalities
unset SUN_PERSONALITY

while getopts "o:s:d:tnw:fl" options; do
	case $options in
		o ) OUTFILE=$OPTARG;;
		d ) WORKDIR=$OPTARG;;
		n ) SORTARG="-n";;
		w ) WARNMSG="$OPTARG";;
		f ) FORCE="true";;
		t ) TEST="true";;
		l ) ENSURE_NEWLINE="true";;
		* ) echo "Specify output file with -o and fragments directory with -d"
		    exit 1;;
	esac
done

# do we have -o?
if [ "x${OUTFILE}" = "x" ]; then
	echo "Please specify an output file with -o"
	exit 1
fi

# do we have -d?
if [ "x${WORKDIR}" = "x" ]; then
	echo "Please fragments directory with -d"
	exit 1
fi

# can we write to -o?
if [ -f "${OUTFILE}" ]; then
	if [ ! -w "${OUTFILE}" ]; then
		echo "Cannot write to ${OUTFILE}"
		exit 1
	fi
else
	if [ ! -w `dirname "${OUTFILE}"` ]; then
		echo "Cannot write to `dirname \"${OUTFILE}\"` to create ${OUTFILE}"
		exit 1
	fi
fi

# do we have a fragments subdir inside the work dir?
if [ ! -d "${WORKDIR}/fragments" ]  && [ ! -x "${WORKDIR}/fragments" ]; then
	echo "Cannot access the fragments directory"
	exit 1
fi

# are there actually any fragments?
if [ ! "$(ls -A """${WORKDIR}/fragments""")" ]; then
	if [ "x${FORCE}" = "x" ]; then
		echo "The fragments directory is empty, cowardly refusing to make empty config files"
		exit 1
	fi
fi

cd "${WORKDIR}"

if [ "x${WARNMSG}" = "x" ]; then
	: > "fragments.concat"
else
	printf '%s\n' "$WARNMSG" > "fragments.concat"
fi

# find all the files in the fragments directory, sort them numerically and concat to fragments.concat in the working dir
IFS_BACKUP=$IFS
IFS='
'
for fragfile in `find fragments/ -type f -follow -print0 | xargs -0 -n1 basename | LC_ALL=C sort ${SORTARG}`
do
    cat "fragments/$fragfile" >> "fragments.concat"
    # Handle newlines.
    if [ "x${ENSURE_NEWLINE}" != "x" ]; then
      echo >> "fragments.concat"
    fi
done
IFS=$IFS_BACKUP

if [ "x${TEST}" = "x" ]; then
	# This is a real run, copy the file to outfile
	cp fragments.concat "${OUTFILE}"
	RETVAL=$?
else
	# Just compare the result to outfile to help the exec decide
	cmp "${OUTFILE}" fragments.concat
	RETVAL=$?
fi

exit $RETVAL
# == Fact: concat_basedir
#
# A custom fact that sets the default location for fragments
#
# "${::vardir}/concat/"
#
Facter.add("concat_basedir") do
  setcode do
    File.join(Puppet[:vardir],"concat")
  end
end
# == Define: concat::fragment
#
# Puts a file fragment into a directory previous setup using concat
#
# === Options:
#
# [*target*]
#   The file that these fragments belong to
# [*content*]
#   If present puts the content into the file
# [*source*]
#   If content was not specified, use the source
# [*order*]
#   By default all files gets a 10_ prefix in the directory you can set it to
#   anything else using this to influence the order of the content in the file
# [*ensure*]
#   Present/Absent or destination to a file to include another file
# [*mode*]
#   Deprecated
# [*owner*]
#   Deprecated
# [*group*]
#   Deprecated
# [*backup*]
#   Deprecated
#
define concat::fragment(
    $target,
    $content = undef,
    $source  = undef,
    $order   = 10,
    $ensure  = undef,
    $mode    = undef,
    $owner   = undef,
    $group   = undef,
    $backup  = undef
) {
  validate_string($target)
  validate_string($content)
  if !(is_string($source) or is_array($source)) {
    fail('$source is not a string or an Array.')
  }
  validate_string($order)
  if $mode {
    warning('The $mode parameter to concat::fragment is deprecated and has no effect')
  }
  if $owner {
    warning('The $owner parameter to concat::fragment is deprecated and has no effect')
  }
  if $group {
    warning('The $group parameter to concat::fragment is deprecated and has no effect')
  }
  if $backup {
    warning('The $backup parameter to concat::fragment is deprecated and has no effect')
  }
  if $ensure == undef {
    $_ensure = getparam(Concat[$target], 'ensure')
  } else {
    if ! ($ensure in [ 'present', 'absent' ]) {
      warning('Passing a value other than \'present\' or \'absent\' as the $ensure parameter to concat::fragment is deprecated.  If you want to use the content of a file as a fragment please use the $source parameter.')
    }
    $_ensure = $ensure
  }

  include concat::setup

  $safe_name        = regsubst($name, '[/:\n]', '_', 'GM')
  $safe_target_name = regsubst($target, '[/:\n]', '_', 'GM')
  $concatdir        = $concat::setup::concatdir
  $fragdir          = "${concatdir}/${safe_target_name}"
  $fragowner            = $concat::setup::fragment_owner
  $fragmode             = $concat::setup::fragment_mode

  # The file type's semantics are problematic in that ensure => present will
  # not over write a pre-existing symlink.  We are attempting to provide
  # backwards compatiblity with previous concat::fragment versions that
  # supported the file type's ensure => /target syntax

  # be paranoid and only allow the fragment's file resource's ensure param to
  # be file, absent, or a file target
  $safe_ensure = $_ensure ? {
    ''        => 'file',
    undef     => 'file',
    'file'    => 'file',
    'present' => 'file',
    'absent'  => 'absent',
    default   => $_ensure,
  }

  # if it looks line ensure => /target syntax was used, fish that out
  if ! ($_ensure in ['', 'present', 'absent', 'file' ]) {
    $ensure_target = $_ensure
  } else {
    $ensure_target = undef
  }

  # the file type's semantics only allows one of: ensure => /target, content,
  # or source
  if ($ensure_target and $source) or
    ($ensure_target and $content) or
    ($source and $content) {
    fail('You cannot specify more than one of $content, $source, $ensure => /target')
  }

  if ! ($content or $source or $ensure_target) {
    crit('No content, source or symlink specified')
  }

  # punt on group ownership until some point in the distant future when $::gid
  # can be relied on to be present
  file { "${fragdir}/fragments/${order}_${safe_name}":
    ensure  => $safe_ensure,
    owner   => $fragowner,
    mode    => $fragmode,
    source  => $source,
    content => $content,
    backup  => false,
    alias   => "concat_fragment_${name}",
    notify  => Exec["concat_${target}"]
  }
}
# == Define: concat
#
# Sets up so that you can use fragments to build a final config file,
#
# === Options:
#
# [*ensure*]
#   Present/Absent
# [*path*]
#   The path to the final file. Use this in case you want to differentiate
#   between the name of a resource and the file path.  Note: Use the name you
#   provided in the target of your fragments.
# [*owner*]
#   Who will own the file
# [*group*]
#   Who will own the file
# [*mode*]
#   The mode of the final file
# [*force*]
#   Enables creating empty files if no fragments are present
# [*warn*]
#   Adds a normal shell style comment top of the file indicating that it is
#   built by puppet
# [*force*]
# [*backup*]
#   Controls the filebucketing behavior of the final file and see File type
#   reference for its use.  Defaults to 'puppet'
# [*replace*]
#   Whether to replace a file that already exists on the local system
# [*order*]
# [*ensure_newline*]
# [*gnu*]
#   Deprecated
#
# === Actions:
# * Creates fragment directories if it didn't exist already
# * Executes the concatfragments.sh script to build the final file, this
#   script will create directory/fragments.concat.   Execution happens only
#   when:
#   * The directory changes
#   * fragments.concat != final destination, this means rebuilds will happen
#     whenever someone changes or deletes the final file.  Checking is done
#     using /usr/bin/cmp.
#   * The Exec gets notified by something else - like the concat::fragment
#     define
# * Copies the file over to the final destination using a file resource
#
# === Aliases:
#
# * The exec can notified using Exec["concat_/path/to/file"] or
#   Exec["concat_/path/to/directory"]
# * The final file can be referenced as File["/path/to/file"] or
#   File["concat_/path/to/file"]
#
define concat(
  $ensure         = 'present',
  $path           = $name,
  $owner          = undef,
  $group          = undef,
  $mode           = '0644',
  $warn           = false,
  $force          = false,
  $backup         = 'puppet',
  $replace        = true,
  $order          = 'alpha',
  $ensure_newline = false,
  $gnu            = undef
) {
  validate_re($ensure, '^present$|^absent$')
  validate_absolute_path($path)
  validate_string($owner)
  validate_string($group)
  validate_string($mode)
  if ! (is_string($warn) or $warn == true or $warn == false) {
    fail('$warn is not a string or boolean')
  }
  validate_bool($force)
  validate_string($backup)
  validate_bool($replace)
  validate_re($order, '^alpha$|^numeric$')
  validate_bool($ensure_newline)
  if $gnu {
    warning('The $gnu parameter to concat is deprecated and has no effect')
  }

  include concat::setup

  $safe_name            = regsubst($name, '[/:]', '_', 'G')
  $concatdir            = $concat::setup::concatdir
  $fragdir              = "${concatdir}/${safe_name}"
  $concat_name          = 'fragments.concat.out'
  $script_command       = $concat::setup::script_command
  $default_warn_message = '# This file is managed by Puppet. DO NOT EDIT.'
  $bool_warn_message    = 'Using stringified boolean values (\'true\', \'yes\', \'on\', \'false\', \'no\', \'off\') to represent boolean true/false as the $warn parameter to concat is deprecated and will be treated as the warning message in a future release'

  case $warn {
    true: {
      $warn_message = $default_warn_message
    }
    'true', 'yes', 'on': {
      warning($bool_warn_message)
      $warn_message = $default_warn_message
    }
    false: {
      $warn_message = ''
    }
    'false', 'no', 'off': {
      warning($bool_warn_message)
      $warn_message = ''
    }
    default: {
      $warn_message = $warn
    }
  }

  $warnmsg_escaped = regsubst($warn_message, '\'', '\'\\\'\'', 'G')
  $warnflag = $warnmsg_escaped ? {
    ''      => '',
    default => "-w '${warnmsg_escaped}'"
  }

  $forceflag = $force ? {
    true  => '-f',
    false => '',
  }

  $orderflag = $order ? {
    'numeric' => '-n',
    'alpha'   => '',
  }

  $newlineflag = $ensure_newline ? {
    true  => '-l',
    false => '',
  }

  File {
    backup  => false,
  }

  if $ensure == 'present' {
    file { $fragdir:
      ensure => directory,
      mode   => '0750',
    }

    file { "${fragdir}/fragments":
      ensure  => directory,
      mode    => '0750',
      force   => true,
      ignore  => ['.svn', '.git', '.gitignore'],
      notify  => Exec["concat_${name}"],
      purge   => true,
      recurse => true,
    }

    file { "${fragdir}/fragments.concat":
      ensure => present,
      mode   => '0640',
    }

    file { "${fragdir}/${concat_name}":
      ensure => present,
      mode   => '0640',
    }

    file { $name:
      ensure  => present,
      owner   => $owner,
      group   => $group,
      mode    => $mode,
      replace => $replace,
      path    => $path,
      alias   => "concat_${name}",
      source  => "${fragdir}/${concat_name}",
      backup  => $backup,
    }

    # remove extra whitespace from string interpolation to make testing easier
    $command = strip(regsubst("${script_command} -o \"${fragdir}/${concat_name}\" -d \"${fragdir}\" ${warnflag} ${forceflag} ${orderflag} ${newlineflag}", '\s+', ' ', 'G'))

    # if puppet is running as root, this exec should also run as root to allow
    # the concatfragments.sh script to potentially be installed in path that
    # may not be accessible by a target non-root owner.
    exec { "concat_${name}":
      alias     => "concat_${fragdir}",
      command   => $command,
      notify    => File[$name],
      subscribe => File[$fragdir],
      unless    => "${command} -t",
      path      => $::path,
      require   => [
        File[$fragdir],
        File["${fragdir}/fragments"],
        File["${fragdir}/fragments.concat"],
      ],
    }
  } else {
    file { [
      $fragdir,
      "${fragdir}/fragments",
      "${fragdir}/fragments.concat",
      "${fragdir}/${concat_name}"
    ]:
      ensure => absent,
      force  => true,
    }

    file { $path:
      ensure => absent,
      backup => $backup,
    }

    $absent_exec_command = $::kernel ? {
      'windows' => 'cmd.exe /c exit 0',
      default   => 'true',
    }

    $absent_exec_path = $::kernel ? {
      'windows' => $::path,
      default   => '/bin:/usr/bin',
    }

    exec { "concat_${name}":
      alias   => "concat_${fragdir}",
      command => $absent_exec_command,
      path    => $absent_exec_path
    }
  }
}

# vim:sw=2:ts=2:expandtab:textwidth=79
# === Class: concat::setup
#
# Sets up the concat system. This is a private class.
#
# [$concatdir]
#   is where the fragments live and is set on the fact concat_basedir.
#   Since puppet should always manage files in $concatdir and they should
#   not be deleted ever, /tmp is not an option.
#
# It also copies out the concatfragments.sh file to ${concatdir}/bin
#
class concat::setup {
  if $caller_module_name != $module_name {
    warning("${name} is deprecated as a public API of the ${module_name} module and should no longer be directly included in the manifest.")
  }

  if $::concat_basedir {
    $concatdir = $::concat_basedir
  } else {
    fail ('$concat_basedir not defined. Try running again with pluginsync=true on the [master] and/or [main] section of your node\'s \'/etc/puppet/puppet.conf\'.')
  }
  
  # owner and mode of fragment files (on windows owner and access rights should be inherited from concatdir and not explicitly set to avoid problems)
  $fragment_owner = $osfamily ? { 'windows' => undef, default => $::id }
  $fragment_mode  = $osfamily ? { 'windows' => undef, default => '0640' }

  $script_name = $::kernel ? {
    'windows' => 'concatfragments.rb',
    default   => 'concatfragments.sh'
  }

  $script_path = "${concatdir}/bin/${script_name}"

  $script_owner = $osfamily ? { 'windows' => undef, default => $::id }

  $script_mode = $osfamily ? { 'windows' => undef, default => '0755' }

  $script_command   = $::kernel ? {
    'windows' => "ruby.exe ${script_path}",
    default   => $script_path
  }

  File {
    backup => false,
  }

  file { $script_path:
    ensure => file,
    owner  => $script_owner,
    mode   => $script_mode,
    source => "puppet:///modules/concat/${script_name}",
  }

  file { [ $concatdir, "${concatdir}/bin" ]:
    ensure => directory,
    mode   => '0755',
  }
}
require 'spec_helper_acceptance'

describe 'concat backup parameter' do
  context '=> puppet' do
    before :all do
      shell('rm -rf /tmp/concat')
      shell('mkdir -p /tmp/concat')
      shell("/bin/echo 'old contents' > /tmp/concat/file")
    end

    pp = <<-EOS
      concat { '/tmp/concat/file':
        backup => 'puppet',
      }
      concat::fragment { 'new file':
        target  => '/tmp/concat/file',
        content => 'new contents',
      }
    EOS

    it 'applies the manifest twice with "Filebucketed" stdout and no stderr' do
      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stderr).to eq("")
        expect(r.stdout).to match(/Filebucketed \/tmp\/concat\/file to puppet with sum 0140c31db86293a1a1e080ce9b91305f/) # sum is for file contents of 'old contents'
      end
      expect(apply_manifest(pp, :catch_changes => true).stderr).to eq("")
    end

    describe file('/tmp/concat/file') do
      it { should be_file }
      it { should contain 'new contents' }
    end
  end

  context '=> .backup' do
    before :all do
      shell('rm -rf /tmp/concat')
      shell('mkdir -p /tmp/concat')
      shell("/bin/echo 'old contents' > /tmp/concat/file")
    end

    pp = <<-EOS
      concat { '/tmp/concat/file':
        backup => '.backup',
      }
      concat::fragment { 'new file':
        target  => '/tmp/concat/file',
        content => 'new contents',
      }
    EOS

    # XXX Puppet doesn't mention anything about filebucketing with a given
    # extension like .backup
    it 'applies the manifest twice  no stderr' do
      expect(apply_manifest(pp, :catch_failures => true).stderr).to eq("")
      expect(apply_manifest(pp, :catch_changes => true).stderr).to eq("")
    end

    describe file('/tmp/concat/file') do
      it { should be_file }
      it { should contain 'new contents' }
    end
    describe file('/tmp/concat/file.backup') do
      it { should be_file }
      it { should contain 'old contents' }
    end
  end

  # XXX The backup parameter uses validate_string() and thus can't be the
  # boolean false value, but the string 'false' has the same effect in Puppet 3
  context "=> 'false'" do
    before :all do
      shell('rm -rf /tmp/concat')
      shell('mkdir -p /tmp/concat')
      shell("/bin/echo 'old contents' > /tmp/concat/file")
    end

    pp = <<-EOS
      concat { '/tmp/concat/file':
        backup => '.backup',
      }
      concat::fragment { 'new file':
        target  => '/tmp/concat/file',
        content => 'new contents',
      }
    EOS

    it 'applies the manifest twice with no "Filebucketed" stdout and no stderr' do
      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stderr).to eq("")
        expect(r.stdout).to_not match(/Filebucketed/)
      end
      expect(apply_manifest(pp, :catch_changes => true).stderr).to eq("")
    end

    describe file('/tmp/concat/file') do
      it { should be_file }
      it { should contain 'new contents' }
    end
  end
end
require 'spec_helper_acceptance'

describe 'basic concat test' do

  shared_examples 'successfully_applied' do |pp|
    it 'applies the manifest twice with no stderr' do
      expect(apply_manifest(pp, :catch_failures => true).stderr).to eq("")
      expect(apply_manifest(pp, :catch_changes => true).stderr).to eq("")
    end

    describe file("#{default['puppetvardir']}/concat") do
      it { should be_directory }
      it { should be_owned_by 'root' }
      it { should be_grouped_into 'root' }
      it { should be_mode 755 }
    end
    describe file("#{default['puppetvardir']}/concat/bin") do
      it { should be_directory }
      it { should be_owned_by 'root' }
      it { should be_grouped_into 'root' }
      it { should be_mode 755 }
    end
    describe file("#{default['puppetvardir']}/concat/bin/concatfragments.sh") do
      it { should be_file }
      it { should be_owned_by 'root' }
      #it { should be_grouped_into 'root' }
      it { should be_mode 755 }
    end
    describe file("#{default['puppetvardir']}/concat/_tmp_concat_file") do
      it { should be_directory }
      it { should be_owned_by 'root' }
      it { should be_grouped_into 'root' }
      it { should be_mode 750 }
    end
    describe file("#{default['puppetvardir']}/concat/_tmp_concat_file/fragments") do
      it { should be_directory }
      it { should be_owned_by 'root' }
      it { should be_grouped_into 'root' }
      it { should be_mode 750 }
    end
    describe file("#{default['puppetvardir']}/concat/_tmp_concat_file/fragments.concat") do
      it { should be_file }
      it { should be_owned_by 'root' }
      it { should be_grouped_into 'root' }
      it { should be_mode 640 }
    end
    describe file("#{default['puppetvardir']}/concat/_tmp_concat_file/fragments.concat.out") do
      it { should be_file }
      it { should be_owned_by 'root' }
      it { should be_grouped_into 'root' }
      it { should be_mode 640 }
    end
  end

  context 'owner/group root' do
    pp = <<-EOS
      concat { '/tmp/concat/file':
        owner => 'root',
        group => 'root',
        mode  => '0644',
      }

      concat::fragment { '1':
        target  => '/tmp/concat/file',
        content => '1',
        order   => '01',
      }

      concat::fragment { '2':
        target  => '/tmp/concat/file',
        content => '2',
        order   => '02',
      }
    EOS

    it_behaves_like 'successfully_applied', pp

    describe file('/tmp/concat/file') do
      it { should be_file }
      it { should be_owned_by 'root' }
      it { should be_grouped_into 'root' }
      it { should be_mode 644 }
      it { should contain '1' }
      it { should contain '2' }
    end
    describe file("#{default['puppetvardir']}/concat/_tmp_concat_file/fragments/01_1") do
      it { should be_file }
      it { should be_owned_by 'root' }
      it { should be_grouped_into 'root' }
      it { should be_mode 640 }
    end
    describe file("#{default['puppetvardir']}/concat/_tmp_concat_file/fragments/02_2") do
      it { should be_file }
      it { should be_owned_by 'root' }
      it { should be_grouped_into 'root' }
      it { should be_mode 640 }
    end
  end

  context 'owner/group non-root' do
    before(:all) do
      shell "groupadd -g 64444 bob"
      shell "useradd -u 42 -g 64444 bob"
    end
    after(:all) do
      shell "userdel bob"
    end

    pp="
      concat { '/tmp/concat/file':
        owner => 'bob',
        group => 'bob',
        mode  => '0644',
      }

      concat::fragment { '1':
        target  => '/tmp/concat/file',
        content => '1',
        order   => '01',
      }

      concat::fragment { '2':
        target  => '/tmp/concat/file',
        content => '2',
        order   => '02',
      }
    "

    it_behaves_like 'successfully_applied', pp

    describe file('/tmp/concat/file') do
      it { should be_file }
      it { should be_owned_by 'bob' }
      it { should be_grouped_into 'bob' }
      it { should be_mode 644 }
      it { should contain '1' }
      it { should contain '2' }
    end
    describe file("#{default['puppetvardir']}/concat/_tmp_concat_file/fragments/01_1") do
      it { should be_file }
      it { should be_owned_by 'root' }
      it { should be_grouped_into 'root' }
      it { should be_mode 640 }
      it { should contain '1' }
    end
    describe file("#{default['puppetvardir']}/concat/_tmp_concat_file/fragments/02_2") do
      it { should be_file }
      it { should be_owned_by 'root' }
      it { should be_grouped_into 'root' }
      it { should be_mode 640 }
      it { should contain '2' }
    end
  end

  context 'ensure' do
    context 'works when set to present with path set' do
      pp="
        concat { 'file':
          ensure => present,
          path   => '/tmp/concat/file',
          mode   => '0644',
        }
        concat::fragment { '1':
          target  => 'file',
          content => '1',
          order   => '01',
        }
      "

      it_behaves_like 'successfully_applied', pp

      describe file('/tmp/concat/file') do
        it { should be_file }
        it { should be_mode 644 }
        it { should contain '1' }
      end
    end
    context 'works when set to absent with path set' do
      pp="
        concat { 'file':
          ensure => absent,
          path   => '/tmp/concat/file',
          mode   => '0644',
        }
        concat::fragment { '1':
          target  => 'file',
          content => '1',
          order   => '01',
        }
      "

      # Can't used shared examples as this will always trigger the exec when
      # absent is set.
      it 'applies the manifest twice with no stderr' do
        expect(apply_manifest(pp, :catch_failures => true).stderr).to eq("")
        expect(apply_manifest(pp, :catch_failures => true).stderr).to eq("")
      end

      describe file('/tmp/concat/file') do
        it { should_not be_file }
      end
    end
  end
end
require 'spec_helper_acceptance'

describe 'deprecation warnings' do

  shared_examples 'has_warning'do |pp, w|
    it 'applies the manifest twice with a stderr regex' do
      expect(apply_manifest(pp, :catch_failures => true).stderr).to match(/#{Regexp.escape(w)}/m)
      expect(apply_manifest(pp, :catch_changes => true).stderr).to match(/#{Regexp.escape(w)}/m)
    end
  end

  context 'concat gnu parameter' do
    pp = <<-EOS
      concat { '/tmp/concat/file':
        gnu => 'foo',
      }
      concat::fragment { 'foo':
        target  => '/tmp/concat/file',
        content => 'bar',
      }
    EOS
    w = 'The $gnu parameter to concat is deprecated and has no effect'

    it_behaves_like 'has_warning', pp, w
  end

  context 'concat warn parameter =>' do
    ['true', 'yes', 'on'].each do |warn|
      context warn do
        pp = <<-EOS
          concat { '/tmp/concat/file':
            warn => '#{warn}',
          }
          concat::fragment { 'foo':
            target  => '/tmp/concat/file',
            content => 'bar',
          }
        EOS
        w = 'Using stringified boolean values (\'true\', \'yes\', \'on\', \'false\', \'no\', \'off\') to represent boolean true/false as the $warn parameter to concat is deprecated and will be treated as the warning message in a future release'

        it_behaves_like 'has_warning', pp, w

        describe file('/tmp/concat/file') do
          it { should be_file }
          it { should contain '# This file is managed by Puppet. DO NOT EDIT.' }
          it { should contain 'bar' }
        end
      end
    end

    ['false', 'no', 'off'].each do |warn|
      context warn do
        pp = <<-EOS
          concat { '/tmp/concat/file':
            warn => '#{warn}',
          }
          concat::fragment { 'foo':
            target  => '/tmp/concat/file',
            content => 'bar',
          }
        EOS
        w = 'Using stringified boolean values (\'true\', \'yes\', \'on\', \'false\', \'no\', \'off\') to represent boolean true/false as the $warn parameter to concat is deprecated and will be treated as the warning message in a future release'

        it_behaves_like 'has_warning', pp, w

        describe file('/tmp/concat/file') do
          it { should be_file }
          it { should_not contain '# This file is managed by Puppet. DO NOT EDIT.' }
          it { should contain 'bar' }
        end
      end
    end
  end

  context 'concat::fragment ensure parameter' do
    context 'target file exists' do
      before(:all) do
        shell("/bin/echo 'file1 contents' > /tmp/concat/file1")
      end
      after(:all) do
        # XXX this test may leave behind a symlink in the fragment directory
        # which could cause warnings and/or breakage from the subsequent tests
        # unless we clean it up. 
        shell('rm -rf /tmp/concat /var/lib/puppet/concat')
        shell('mkdir -p /tmp/concat')
      end

      pp = <<-EOS
        concat { '/tmp/concat/file': }
        concat::fragment { 'foo':
          target => '/tmp/concat/file',
          ensure => '/tmp/concat/file1',
        }
      EOS
      w = 'Passing a value other than \'present\' or \'absent\' as the $ensure parameter to concat::fragment is deprecated.  If you want to use the content of a file as a fragment please use the $source parameter.'

      it_behaves_like 'has_warning', pp, w

      describe file('/tmp/concat/file') do
        it { should be_file }
        it { should contain 'file1 contents' }
      end

      describe 'the fragment can be changed from a symlink to a plain file' do
        pp = <<-EOS
          concat { '/tmp/concat/file': }
          concat::fragment { 'foo':
            target  => '/tmp/concat/file',
            content => 'new content',
          }
        EOS

        it 'applies the manifest twice with no stderr' do
          expect(apply_manifest(pp, :catch_failures => true).stderr).to eq("")
          expect(apply_manifest(pp, :catch_changes => true).stderr).to eq("")
        end

        describe file('/tmp/concat/file') do
          it { should be_file }
          it { should contain 'new content' }
          it { should_not contain 'file1 contents' }
        end
      end
    end # target file exists

    context 'target does not exist' do
      pp = <<-EOS
        concat { '/tmp/concat/file': }
        concat::fragment { 'foo':
          target => '/tmp/concat/file',
          ensure => '/tmp/concat/file1',
        }
      EOS
      w = 'Passing a value other than \'present\' or \'absent\' as the $ensure parameter to concat::fragment is deprecated.  If you want to use the content of a file as a fragment please use the $source parameter.'

      it_behaves_like 'has_warning', pp, w

      describe file('/tmp/concat/file') do
        it { should be_file }
      end

      describe 'the fragment can be changed from a symlink to a plain file' do
        pp = <<-EOS
          concat { '/tmp/concat/file': }
          concat::fragment { 'foo':
            target  => '/tmp/concat/file',
            content => 'new content',
          }
        EOS

        it 'applies the manifest twice with no stderr' do
          expect(apply_manifest(pp, :catch_failures => true).stderr).to eq("")
          expect(apply_manifest(pp, :catch_changes => true).stderr).to eq("")
        end

        describe file('/tmp/concat/file') do
          it { should be_file }
          it { should contain 'new content' }
        end
      end
    end # target file exists

  end # concat::fragment ensure parameter

  context 'concat::fragment mode parameter' do
    pp = <<-EOS
      concat { '/tmp/concat/file': }
      concat::fragment { 'foo':
        target  => '/tmp/concat/file',
        content => 'bar',
        mode    => 'bar',
      }
    EOS
    w = 'The $mode parameter to concat::fragment is deprecated and has no effect'

    it_behaves_like 'has_warning', pp, w
  end

  context 'concat::fragment owner parameter' do
    pp = <<-EOS
      concat { '/tmp/concat/file': }
      concat::fragment { 'foo':
        target  => '/tmp/concat/file',
        content => 'bar',
        owner   => 'bar',
      }
    EOS
    w = 'The $owner parameter to concat::fragment is deprecated and has no effect'

    it_behaves_like 'has_warning', pp, w
  end

  context 'concat::fragment group parameter' do
    pp = <<-EOS
      concat { '/tmp/concat/file': }
      concat::fragment { 'foo':
        target  => '/tmp/concat/file',
        content => 'bar',
        group   => 'bar',
      }
    EOS
    w = 'The $group parameter to concat::fragment is deprecated and has no effect'

    it_behaves_like 'has_warning', pp, w
  end

  context 'concat::fragment backup parameter' do
    pp = <<-EOS
      concat { '/tmp/concat/file': }
      concat::fragment { 'foo':
        target  => '/tmp/concat/file',
        content => 'bar',
        backup  => 'bar',
      }
    EOS
    w = 'The $backup parameter to concat::fragment is deprecated and has no effect'

    it_behaves_like 'has_warning', pp, w
  end

  context 'include concat::setup' do
    pp = <<-EOS
      include concat::setup
    EOS
    w = 'concat::setup is deprecated as a public API of the concat module and should no longer be directly included in the manifest.'

    it_behaves_like 'has_warning', pp, w
  end

end
require 'spec_helper_acceptance'

describe 'concat force empty parameter' do
  context 'should run successfully' do
    pp = <<-EOS
      concat { '/tmp/concat/file':
        owner => root,
        group => root,
        mode  => '0644',
        force => true,
      }
    EOS

    it 'applies the manifest twice with no stderr' do
      expect(apply_manifest(pp, :catch_failures => true).stderr).to eq("")
      expect(apply_manifest(pp, :catch_changes => true).stderr).to eq("")
    end

    describe file('/tmp/concat/file') do
      it { should be_file }
      it { should_not contain '1\n2' }
    end
  end
end
require 'spec_helper_acceptance'

describe 'concat::fragment source' do
  context 'should read file fragments from local system' do
    before(:all) do
      shell("/bin/echo 'file1 contents' > /tmp/concat/file1")
      shell("/bin/echo 'file2 contents' > /tmp/concat/file2")
    end

    pp = <<-EOS
      concat { '/tmp/concat/foo': }

      concat::fragment { '1':
        target  => '/tmp/concat/foo',
        source  => '/tmp/concat/file1',
      }
      concat::fragment { '2':
        target  => '/tmp/concat/foo',
        content => 'string1 contents',
      }
      concat::fragment { '3':
        target  => '/tmp/concat/foo',
        source  => '/tmp/concat/file2',
      }
    EOS

    it 'applies the manifest twice with no stderr' do
      expect(apply_manifest(pp, :catch_failures => true).stderr).to eq("")
      expect(apply_manifest(pp, :catch_changes => true).stderr).to eq("")
    end

    describe file('/tmp/concat/foo') do
      it { should be_file }
      it { should contain 'file1 contents' }
      it { should contain 'string1 contents' }
      it { should contain 'file2 contents' }
    end
  end # should read file fragments from local system

  context 'should create files containing first match only.' do
    before(:all) do
      shell('rm -rf /tmp/concat /var/lib/puppet/concat')
      shell('mkdir -p /tmp/concat')
      shell("/bin/echo 'file1 contents' > /tmp/concat/file1")
      shell("/bin/echo 'file2 contents' > /tmp/concat/file2")
    end

    pp = <<-EOS
      concat { '/tmp/concat/result_file1':
        owner   => root,
        group   => root,
        mode    => '0644',
      }
      concat { '/tmp/concat/result_file2':
        owner   => root,
        group   => root,
        mode    => '0644',
      }
      concat { '/tmp/concat/result_file3':
        owner   => root,
        group   => root,
        mode    => '0644',
      }

      concat::fragment { '1':
        target  => '/tmp/concat/result_file1',
        source => [ '/tmp/concat/file1', '/tmp/concat/file2' ],
        order   => '01',
      }
      concat::fragment { '2':
        target  => '/tmp/concat/result_file2',
        source => [ '/tmp/concat/file2', '/tmp/concat/file1' ],
        order   => '01',
      }
      concat::fragment { '3':
        target  => '/tmp/concat/result_file3',
        source => [ '/tmp/concat/file1', '/tmp/concat/file2' ],
        order   => '01',
      }
    EOS

    it 'applies the manifest twice with no stderr' do
      expect(apply_manifest(pp, :catch_failures => true).stderr).to eq("")
      expect(apply_manifest(pp, :catch_changes => true).stderr).to eq("")
    end
    describe file('/tmp/concat/result_file1') do
      it { should be_file }
      it { should contain 'file1 contents' }
      it { should_not contain 'file2 contents' }
    end
    describe file('/tmp/concat/result_file2') do
      it { should be_file }
      it { should contain 'file2 contents' }
      it { should_not contain 'file1 contents' }
    end
    describe file('/tmp/concat/result_file3') do
      it { should be_file }
      it { should contain 'file1 contents' }
      it { should_not contain 'file2 contents' }
    end
  end

  context 'should fail if no match on source.' do
    before(:all) do
      shell('rm -rf /tmp/concat /var/lib/puppet/concat')
      shell('mkdir -p /tmp/concat')
      shell('/bin/rm -rf /tmp/concat/fail_no_source /tmp/concat/nofilehere /tmp/concat/nothereeither')
    end

    pp = <<-EOS
      concat { '/tmp/concat/fail_no_source':
        owner   => root,
        group   => root,
        mode    => '0644',
      }

      concat::fragment { '1':
        target  => '/tmp/concat/fail_no_source',
        source => [ '/tmp/concat/nofilehere', '/tmp/concat/nothereeither' ],
        order   => '01',
      }
    EOS

    it 'applies the manifest with resource failures' do
      apply_manifest(pp, :expect_failures => true)
    end
    describe file('/tmp/concat/fail_no_source') do
      #FIXME: Serverspec::Type::File doesn't support exists? for some reason. so... hack.
      it { should_not be_file }
      it { should_not be_directory }
    end
  end
end

require 'spec_helper_acceptance'

describe 'concat ensure_newline parameter' do
  context '=> false' do
    pp = <<-EOS
      concat { '/tmp/concat/file':
        ensure_newline => false,
      }
      concat::fragment { '1':
        target  => '/tmp/concat/file',
        content => '1',
      }
      concat::fragment { '2':
        target  => '/tmp/concat/file',
        content => '2',
      }
    EOS

    it 'applies the manifest twice with no stderr' do
      expect(apply_manifest(pp, :catch_failures => true).stderr).to eq("")
      expect(apply_manifest(pp, :catch_changes => true).stderr).to eq("")
    end

    describe file('/tmp/concat/file') do
      it { should be_file }
      it { should contain '12' }
    end
  end

  context '=> true' do
    pp = <<-EOS
      concat { '/tmp/concat/file':
        ensure_newline => true,
      }
      concat::fragment { '1':
        target  => '/tmp/concat/file',
        content => '1',
      }
      concat::fragment { '2':
        target  => '/tmp/concat/file',
        content => '2',
      }
    EOS

    it 'applies the manifest twice with no stderr' do
      expect(apply_manifest(pp, :catch_failures => true).stderr).to eq("")
      expect(apply_manifest(pp, :catch_changes  => true).stderr).to eq("")
      #XXX ensure_newline => true causes changes on every run because the files
      #are modified in place.
    end

    describe file('/tmp/concat/file') do
      it { should be_file }
      it { should contain "1\n2\n" }
    end
  end
end
HOSTS:
  pe-aix-71-acceptance:
    roles:
      - master
      - dashboard
      - database
      - agent
      - default
    platform: aix-7.1-power
    hypervisor: aix
    ip: pe-aix-71-acceptance.delivery.puppetlabs.net
CONFIG:
  type: pe
  nfs_server: NONE
  consoleport: 443
  datastore: instance0
  folder: Delivery/Quality Assurance/Enterprise/Dynamic
  resourcepool: delivery/Quality Assurance/Enterprise/Dynamic
  pooling_api: http://vcloud.delivery.puppetlabs.net/
HOSTS:
  centos-59-x64:
    roles:
      - master
    platform: el-5-x86_64
    box : centos-59-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-59-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: git
HOSTS:
  centos-64-x64:
    roles:
      - master
      - database
      - dashboard
    platform: el-6-x86_64
    box : centos-64-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: pe
HOSTS:
  centos-64-x64:
    roles:
      - master
    platform: el-6-x86_64
    box : centos-64-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: foss
HOSTS:
  debian-607-x64:
    roles:
      - master
    platform: debian-6-amd64
    box : debian-607-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/debian-607-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: git
HOSTS:
  debian-70rc1-x64:
    roles:
      - master
    platform: debian-7-amd64
    box : debian-70rc1-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/debian-70rc1-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: git
HOSTS:
  debian-73-x64.localhost:
    roles:
      - master
    platform: debian-7-amd64
    box : debian-73-x64-virtualbox-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/debian-73-x64-virtualbox-nocm.box
    hypervisor : vagrant
CONFIG:
  log_level: debug
  type: foss
HOSTS:
  centos-64-x64.localdomain:
    roles:
      - master
    platform: el-6-x86_64
    box : centos-65-x64-virtualbox-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-65-x64-virtualbox-nocm.box
    hypervisor : vagrant
CONFIG:
  type: foss
HOSTS:
  fedora-18-x64:
    roles:
      - master
    platform: fedora-18-x86_64
    box : fedora-18-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/fedora-18-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: foss
HOSTS:
  sles-11-x64.local:
    roles:
      - master
    platform: sles-11-x64
    box : sles-11sp1-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/sles-11sp1-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
    type: foss
HOSTS:
  sles-11sp1-x64:
    roles:
      - master
    platform: sles-11-x86_64
    box : sles-11sp1-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/sles-11sp1-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: git
HOSTS:
  ubuntu-server-10044-x64:
    roles:
      - master
    platform: ubuntu-10.04-amd64
    box : ubuntu-server-10044-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/ubuntu-server-10044-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: foss
HOSTS:
  ubuntu-server-12042-x64:
    roles:
      - master
    platform: ubuntu-12.04-amd64
    box : ubuntu-server-12042-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/ubuntu-server-12042-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: foss
HOSTS:
  ubuntu-server-1404-x64:
    roles:
      - master
    platform: ubuntu-14.04-amd64
    box : puppetlabs/ubuntu-14.04-64-nocm
    box_url : https://vagrantcloud.com/puppetlabs/ubuntu-14.04-64-nocm
    hypervisor : vagrant
CONFIG:
  log_level   : debug
  type: git
require 'spec_helper_acceptance'

describe 'concat order' do
  before(:all) do
    shell('rm -rf /tmp/concat /var/lib/puppet/concat')
    shell('mkdir -p /tmp/concat')
  end

  context '=> alpha' do
    pp = <<-EOS
      concat { '/tmp/concat/foo':
        order => 'alpha'
      }
      concat::fragment { '1':
        target  => '/tmp/concat/foo',
        content => 'string1',
      }
      concat::fragment { '2':
        target  => '/tmp/concat/foo',
        content => 'string2',
      }
      concat::fragment { '10':
        target  => '/tmp/concat/foo',
        content => 'string10',
      }
    EOS

    it 'applies the manifest twice with no stderr' do
      expect(apply_manifest(pp, :catch_failures => true).stderr).to eq("")
      expect(apply_manifest(pp, :catch_changes => true).stderr).to eq("")
    end

    describe file('/tmp/concat/foo') do
      it { should be_file }
      it { should contain "string10\nstring1\nsring2" }
    end
  end

  context '=> numeric' do
    pp = <<-EOS
      concat { '/tmp/concat/foo':
        order => 'numeric'
      }
      concat::fragment { '1':
        target  => '/tmp/concat/foo',
        content => 'string1',
      }
      concat::fragment { '2':
        target  => '/tmp/concat/foo',
        content => 'string2',
      }
      concat::fragment { '10':
        target  => '/tmp/concat/foo',
        content => 'string10',
      }
    EOS

    it 'applies the manifest twice with no stderr' do
      expect(apply_manifest(pp, :catch_failures => true).stderr).to eq("")
      expect(apply_manifest(pp, :catch_changes => true).stderr).to eq("")
    end

    describe file('/tmp/concat/foo') do
      it { should be_file }
      it { should contain "string1\nstring2\nsring10" }
    end
  end
end # concat order

describe 'concat::fragment order' do
  before(:all) do
    shell('rm -rf /tmp/concat /var/lib/puppet/concat')
    shell('mkdir -p /tmp/concat')
  end

  context '=> reverse order' do
    pp = <<-EOS
      concat { '/tmp/concat/foo': }
      concat::fragment { '1':
        target  => '/tmp/concat/foo',
        content => 'string1',
        order   => '15',
      }
      concat::fragment { '2':
        target  => '/tmp/concat/foo',
        content => 'string2',
        # default order 10
      }
      concat::fragment { '3':
        target  => '/tmp/concat/foo',
        content => 'string3',
        order   => '1',
      }
    EOS

    it 'applies the manifest twice with no stderr' do
      expect(apply_manifest(pp, :catch_failures => true).stderr).to eq("")
      expect(apply_manifest(pp, :catch_changes => true).stderr).to eq("")
    end

    describe file('/tmp/concat/foo') do
      it { should be_file }
      it { should contain "string3\nstring2\nsring1" }
    end
  end

  context '=> normal order' do
    pp = <<-EOS
      concat { '/tmp/concat/foo': }
      concat::fragment { '1':
        target  => '/tmp/concat/foo',
        content => 'string1',
        order   => '01',
      }
      concat::fragment { '2':
        target  => '/tmp/concat/foo',
        content => 'string2',
        order   => '02'
      }
      concat::fragment { '3':
        target  => '/tmp/concat/foo',
        content => 'string3',
        order   => '03',
      }
    EOS

    it 'applies the manifest twice with no stderr' do
      expect(apply_manifest(pp, :catch_failures => true).stderr).to eq("")
      expect(apply_manifest(pp, :catch_changes => true).stderr).to eq("")
    end

    describe file('/tmp/concat/foo') do
      it { should be_file }
      it { should contain "string1\nstring2\nsring3" }
    end
  end
end # concat::fragment order
require 'spec_helper_acceptance'

describe 'quoted paths' do
  before(:all) do
    shell('rm -rf "/tmp/concat test" /var/lib/puppet/concat')
    shell('mkdir -p "/tmp/concat test"')
  end

  context 'path with blanks' do
    pp = <<-EOS
      concat { '/tmp/concat test/foo':
      }
      concat::fragment { '1':
        target  => '/tmp/concat test/foo',
        content => 'string1',
      }
      concat::fragment { '2':
        target  => '/tmp/concat test/foo',
        content => 'string2',
      }
    EOS

    it 'applies the manifest twice with no stderr' do
      expect(apply_manifest(pp, :catch_failures => true).stderr).to eq("")
      expect(apply_manifest(pp, :catch_changes => true).stderr).to eq("")
    end

    describe file('/tmp/concat test/foo') do
      it { should be_file }
      it { should contain "string1\nsring2" }
    end
  end
end
require 'spec_helper_acceptance'

describe 'replacement of' do
  context 'file' do
    context 'should not succeed' do
      before(:all) do
        shell('mkdir -p /tmp/concat')
        shell('echo "file exists" > /tmp/concat/file')
      end
      after(:all) do
        shell('rm -rf /tmp/concat /var/lib/puppet/concat')
      end

      pp = <<-EOS
        concat { '/tmp/concat/file':
          replace => false,
        }

        concat::fragment { '1':
          target  => '/tmp/concat/file',
          content => '1',
        }

        concat::fragment { '2':
          target  => '/tmp/concat/file',
          content => '2',
        }
      EOS

      it 'applies the manifest twice with no stderr' do
        expect(apply_manifest(pp, :catch_failures => true).stderr).to eq("")
        expect(apply_manifest(pp, :catch_changes => true).stderr).to eq("")
      end

      describe file('/tmp/concat/file') do
        it { should be_file }
        it { should contain 'file exists' }
        it { should_not contain '1' }
        it { should_not contain '2' }
      end
    end

    context 'should succeed' do
      before(:all) do
        shell('mkdir -p /tmp/concat')
        shell('echo "file exists" > /tmp/concat/file')
      end
      after(:all) do
        shell('rm -rf /tmp/concat /var/lib/puppet/concat')
      end

      pp = <<-EOS
        concat { '/tmp/concat/file':
          replace => true,
        }

        concat::fragment { '1':
          target  => '/tmp/concat/file',
          content => '1',
        }

        concat::fragment { '2':
          target  => '/tmp/concat/file',
          content => '2',
        }
      EOS

      it 'applies the manifest twice with no stderr' do
        expect(apply_manifest(pp, :catch_failures => true).stderr).to eq("")
        expect(apply_manifest(pp, :catch_changes => true).stderr).to eq("")
      end

      describe file('/tmp/concat/file') do
        it { should be_file }
        it { should_not contain 'file exists' }
        it { should contain '1' }
        it { should contain '2' }
      end
    end
  end # file

  context 'symlink' do
    context 'should not succeed' do
      # XXX the core puppet file type will replace a symlink with a plain file
      # when using ensure => present and source => ... but it will not when using
      # ensure => present and content => ...; this is somewhat confusing behavior
      before(:all) do
        shell('mkdir -p /tmp/concat')
        shell('ln -s /tmp/concat/dangling /tmp/concat/file')
      end
      after(:all) do
        shell('rm -rf /tmp/concat /var/lib/puppet/concat')
      end

      pp = <<-EOS
        concat { '/tmp/concat/file':
          replace => false,
        }

        concat::fragment { '1':
          target  => '/tmp/concat/file',
          content => '1',
        }

        concat::fragment { '2':
          target  => '/tmp/concat/file',
          content => '2',
        }
      EOS

      it 'applies the manifest twice with no stderr' do
        expect(apply_manifest(pp, :catch_failures => true).stderr).to eq("")
        expect(apply_manifest(pp, :catch_changes => true).stderr).to eq("")
      end

      describe file('/tmp/concat/file') do
        it { should be_linked_to '/tmp/concat/dangling' }
      end

      describe file('/tmp/concat/dangling') do
        # XXX serverspec does not have a matcher for 'exists'
        it { should_not be_file }
        it { should_not be_directory }
      end
    end

    context 'should succeed' do
      # XXX the core puppet file type will replace a symlink with a plain file
      # when using ensure => present and source => ... but it will not when using
      # ensure => present and content => ...; this is somewhat confusing behavior
      before(:all) do
        shell('mkdir -p /tmp/concat')
        shell('ln -s /tmp/concat/dangling /tmp/concat/file')
      end
      after(:all) do
        shell('rm -rf /tmp/concat /var/lib/puppet/concat')
      end

      pp = <<-EOS
        concat { '/tmp/concat/file':
          replace => true,
        }

        concat::fragment { '1':
          target  => '/tmp/concat/file',
          content => '1',
        }

        concat::fragment { '2':
          target  => '/tmp/concat/file',
          content => '2',
        }
      EOS

      it 'applies the manifest twice with no stderr' do
        expect(apply_manifest(pp, :catch_failures => true).stderr).to eq("")
        expect(apply_manifest(pp, :catch_changes => true).stderr).to eq("")
      end

      describe file('/tmp/concat/file') do
        it { should be_file }
        it { should contain '1' }
        it { should contain '2' }
      end
    end
  end # symlink

  context 'directory' do
    context 'should not succeed' do
      before(:all) do
        shell('mkdir -p /tmp/concat/file')
      end
      after(:all) do
        shell('rm -rf /tmp/concat /var/lib/puppet/concat')
      end

      pp = <<-EOS
        concat { '/tmp/concat/file': }

        concat::fragment { '1':
          target  => '/tmp/concat/file',
          content => '1',
        }

        concat::fragment { '2':
          target  => '/tmp/concat/file',
          content => '2',
        }
      EOS

      it 'applies the manifest twice with stderr for changing to file' do
        expect(apply_manifest(pp, :expect_failures => true).stderr).to match(/change from directory to file failed/)
        expect(apply_manifest(pp, :expect_failures => true).stderr).to match(/change from directory to file failed/)
      end

      describe file('/tmp/concat/file') do
        it { should be_directory }
      end
    end

    # XXX concat's force param currently enables the creation of empty files
    # when there are no fragments, and the replace param will only replace
    # files and symlinks, not directories.  The semantics either need to be
    # changed, extended, or a new param introduced to control directory
    # replacement.
    context 'should succeed', :pending => 'not yet implemented' do
      before(:all) do
        shell('mkdir -p /tmp/concat/file')
      end
      after(:all) do
        shell('rm -rf /tmp/concat /var/lib/puppet/concat')
      end

      pp = <<-EOS
        concat { '/tmp/concat/file':
          force => true,
        }

        concat::fragment { '1':
          target  => '/tmp/concat/file',
          content => '1',
        }

        concat::fragment { '2':
          target  => '/tmp/concat/file',
          content => '2',
        }
      EOS

      it 'applies the manifest twice with no stderr' do
        expect(apply_manifest(pp, :catch_failures => true).stderr).to eq("")
        expect(apply_manifest(pp, :catch_changes => true).stderr).to eq("")
      end

      describe file('/tmp/concat/file') do
        it { should be_file }
        it { should contain '1' }
      end
    end
  end # directory
end
require 'spec_helper_acceptance'

describe 'symbolic name' do
  pp = <<-EOS
    concat { 'not_abs_path':
      path => '/tmp/concat/file',
    }

    concat::fragment { '1':
      target  => 'not_abs_path',
      content => '1',
      order   => '01',
    }

    concat::fragment { '2':
      target  => 'not_abs_path',
      content => '2',
      order   => '02',
    }
  EOS

  it 'applies the manifest twice with no stderr' do
    expect(apply_manifest(pp, :catch_failures => true).stderr).to eq("")
    expect(apply_manifest(pp, :catch_changes => true).stderr).to eq("")
  end

  describe file('/tmp/concat/file') do
    it { should be_file }
    it { should contain '1' }
    it { should contain '2' }
  end
end
require 'spec_helper_acceptance'

describe 'concat warn =>' do
  context 'true should enable default warning message' do
    pp = <<-EOS
      concat { '/tmp/concat/file':
        warn  => true,
      }

      concat::fragment { '1':
        target  => '/tmp/concat/file',
        content => '1',
        order   => '01',
      }

      concat::fragment { '2':
        target  => '/tmp/concat/file',
        content => '2',
        order   => '02',
      }
    EOS

    it 'applies the manifest twice with no stderr' do
      expect(apply_manifest(pp, :catch_failures => true).stderr).to eq("")
      expect(apply_manifest(pp, :catch_changes => true).stderr).to eq("")
    end

    describe file('/tmp/concat/file') do
      it { should be_file }
      it { should contain '# This file is managed by Puppet. DO NOT EDIT.' }
      it { should contain '1' }
      it { should contain '2' }
    end
  end
  context 'false should not enable default warning message' do
    pp = <<-EOS
      concat { '/tmp/concat/file':
        warn  => false,
      }

      concat::fragment { '1':
        target  => '/tmp/concat/file',
        content => '1',
        order   => '01',
      }

      concat::fragment { '2':
        target  => '/tmp/concat/file',
        content => '2',
        order   => '02',
      }
    EOS

    it 'applies the manifest twice with no stderr' do
      expect(apply_manifest(pp, :catch_failures => true).stderr).to eq("")
      expect(apply_manifest(pp, :catch_changes => true).stderr).to eq("")
    end

    describe file('/tmp/concat/file') do
      it { should be_file }
      it { should_not contain '# This file is managed by Puppet. DO NOT EDIT.' }
      it { should contain '1' }
      it { should contain '2' }
    end
  end
  context '# foo should overide default warning message' do
    pp = <<-EOS
      concat { '/tmp/concat/file':
        warn  => '# foo',
      }

      concat::fragment { '1':
        target  => '/tmp/concat/file',
        content => '1',
        order   => '01',
      }

      concat::fragment { '2':
        target  => '/tmp/concat/file',
        content => '2',
        order   => '02',
      }
    EOS

    it 'applies the manifest twice with no stderr' do
      expect(apply_manifest(pp, :catch_failures => true).stderr).to eq("")
      expect(apply_manifest(pp, :catch_changes => true).stderr).to eq("")
    end

    describe file('/tmp/concat/file') do
      it { should be_file }
      it { should contain '# foo' }
      it { should contain '1' }
      it { should contain '2' }
    end
  end
end
require 'puppetlabs_spec_helper/module_spec_helper'
require 'beaker-rspec/spec_helper'
require 'beaker-rspec/helpers/serverspec'

unless ENV['RS_PROVISION'] == 'no' or ENV['BEAKER_provision'] == 'no'
  if hosts.first.is_pe?
    install_pe
  else
    install_puppet
  end
  hosts.each do |host|
    on hosts, "mkdir -p #{host['distmoduledir']}"
  end
end

RSpec.configure do |c|
  # Project root
  proj_root = File.expand_path(File.join(File.dirname(__FILE__), '..'))

  # Readable test descriptions
  c.formatter = :documentation

  # Configure all nodes in nodeset
  c.before :suite do
    # Install module and dependencies
    puppet_module_install(:source => proj_root, :module_name => 'concat')
    hosts.each do |host|
      on host, puppet('module','install','puppetlabs-stdlib'), { :acceptable_exit_codes => [0,1] }
    end
  end

  c.before(:all) do
    shell('mkdir -p /tmp/concat')
  end
  c.after(:all) do
    shell('rm -rf /tmp/concat /var/lib/puppet/concat')
  end

  c.treat_symbols_as_metadata_keys_with_true_values = true
end
require 'spec_helper'

describe 'concat::setup', :type => :class do

  shared_examples 'setup' do |concatdir|
    concatdir = '/foo' if concatdir.nil?

    let(:facts) {{ :concat_basedir => concatdir }}

    it do
      should contain_file("#{concatdir}/bin/concatfragments.sh").with({
        :mode   => '0755',
        :source => 'puppet:///modules/concat/concatfragments.sh',
        :backup => false,
      })
    end

    [concatdir, "#{concatdir}/bin"].each do |file|
      it do
        should contain_file(file).with({
          :ensure => 'directory',
          :mode   => '0755',
          :backup => false,
        })
      end
    end
  end

  context 'facts' do
    context 'concat_basedir =>' do
      context '/foo' do
        it_behaves_like 'setup', '/foo'
      end
    end
  end # facts

  context 'deprecated as a public class' do
    it 'should create a warning' do
      pending('rspec-puppet support for testing warning()')
    end
  end
end
require 'spec_helper'

describe 'concat::fragment', :type => :define do

  shared_examples 'fragment' do |title, params|
    params = {} if params.nil?

    p = {
      :content => nil,
      :source  => nil,
      :order   => 10,
      :ensure  => 'present',
    }.merge(params)

    safe_name        = title.gsub(/[\/\n]/, '_')
    safe_target_name = p[:target].gsub(/[\/\n]/, '_')
    concatdir        = '/var/lib/puppet/concat'
    fragdir          = "#{concatdir}/#{safe_target_name}"
    id               = 'root'
    if p[:ensure] == 'absent'
      safe_ensure = p[:ensure] 
    else
      safe_ensure = 'file'
    end

    let(:title) { title }
    let(:facts) {{ :concat_basedir => concatdir, :id => id }}
    let(:params) { params }
    let(:pre_condition) do
      "concat{ '#{p[:target]}': }"
    end

    it do
      should contain_class('concat::setup')
      should contain_concat(p[:target])
      should contain_file("#{fragdir}/fragments/#{p[:order]}_#{safe_name}").with({
        :ensure  => safe_ensure,
        :owner   => id,
        :mode    => '0640',
        :source  => p[:source],
        :content => p[:content],
        :alias   => "concat_fragment_#{title}",
        :backup  => false,
      })
    end
  end

  context 'title' do
    ['0', '1', 'a', 'z'].each do |title|
      it_behaves_like 'fragment', title, {
        :target  => '/etc/motd',
      }
    end
  end # title

  context 'target =>' do
    ['./etc/motd', 'etc/motd', 'motd_header'].each do |target|
      context target do
        it_behaves_like 'fragment', target, {
          :target  => '/etc/motd',
        }
      end
    end

    context 'false' do
      let(:title) { 'motd_header' }
      let(:facts) {{ :concat_basedir => '/tmp' }}
      let(:params) {{ :target => false }}

      it 'should fail' do
        expect { should }.to raise_error(Puppet::Error, /is not a string/)
      end
    end
  end # target =>

  context 'ensure =>' do
    ['present', 'absent'].each do |ens|
      context ens do
        it_behaves_like 'fragment', 'motd_header', {
          :ensure => ens,
          :target => '/etc/motd',
        }
      end
    end

    context 'any value other than \'present\' or \'absent\'' do
      let(:title) { 'motd_header' }
      let(:facts) {{ :concat_basedir => '/tmp' }}
      let(:params) {{ :ensure => 'invalid', :target => '/etc/motd' }}

      it 'should create a warning' do
        pending('rspec-puppet support for testing warning()')
      end
    end
  end # ensure =>

  context 'content =>' do
    ['', 'ashp is our hero'].each do |content|
      context content do
        it_behaves_like 'fragment', 'motd_header', {
          :content => content,
          :target  => '/etc/motd',
        }
      end
    end

    context 'false' do
      let(:title) { 'motd_header' }
      let(:facts) {{ :concat_basedir => '/tmp' }}
      let(:params) {{ :content => false, :target => '/etc/motd' }}

      it 'should fail' do
        expect { should }.to raise_error(Puppet::Error, /is not a string/)
      end
    end
  end # content =>

  context 'source =>' do
    ['', '/foo/bar', ['/foo/bar', '/foo/baz']].each do |source|
      context source do
        it_behaves_like 'fragment', 'motd_header', {
          :source => source,
          :target => '/etc/motd',
        }
      end
    end

    context 'false' do
      let(:title) { 'motd_header' }
      let(:facts) {{ :concat_basedir => '/tmp' }}
      let(:params) {{ :source => false, :target => '/etc/motd' }}

      it 'should fail' do
        expect { should }.to raise_error(Puppet::Error, /is not a string or an Array/)
      end
    end
  end # source =>

  context 'order =>' do
    ['', '42', 'a', 'z'].each do |order|
      context '\'\'' do
        it_behaves_like 'fragment', 'motd_header', {
          :order  => order,
          :target => '/etc/motd',
        }
      end
    end

    context 'false' do
      let(:title) { 'motd_header' }
      let(:facts) {{ :concat_basedir => '/tmp' }}
      let(:params) {{ :order => false, :target => '/etc/motd' }}

      it 'should fail' do
        expect { should }.to raise_error(Puppet::Error, /is not a string/)
      end
    end
  end # order =>

  context 'more than one content source' do
    error_msg = 'You cannot specify more than one of $content, $source, $ensure => /target'

    context 'ensure => target and source' do
      let(:title) { 'motd_header' }
      let(:facts) {{ :concat_basedir => '/tmp' }}
      let(:params) do
        {
          :target  => '/etc/motd',
          :ensure  => '/foo',
          :source  => '/bar',
        }
      end

      it 'should fail' do
        expect { should }.to raise_error(Puppet::Error, /#{Regexp.escape(error_msg)}/m)
      end
    end

    context 'ensure => target and content' do
      let(:title) { 'motd_header' }
      let(:facts) {{ :concat_basedir => '/tmp' }}
      let(:params) do
        {
          :target  => '/etc/motd',
          :ensure  => '/foo',
          :content => 'bar',
        }
      end

      it 'should fail' do
        expect { should }.to raise_error(Puppet::Error, /#{Regexp.escape(error_msg)}/m)
      end
    end

    context 'source and content' do
      let(:title) { 'motd_header' }
      let(:facts) {{ :concat_basedir => '/tmp' }}
      let(:params) do
        {
          :target => '/etc/motd',
          :source => '/foo',
          :content => 'bar',
        }
      end

      it 'should fail' do
        expect { should }.to raise_error(Puppet::Error, /#{Regexp.escape(error_msg)}/m)
      end
    end

  end # more than one content source

  describe 'deprecated parameter' do
    context 'mode =>' do
      context '1755' do
        it_behaves_like 'fragment', 'motd_header', {
          :mode   => '1755',
          :target => '/etc/motd',
        }

        it 'should create a warning' do
          pending('rspec-puppet support for testing warning()')
        end
      end
    end # mode =>

    context 'owner =>' do
      context 'apenny' do
        it_behaves_like 'fragment', 'motd_header', {
          :owner  => 'apenny',
          :target => '/etc/motd',
        }

        it 'should create a warning' do
          pending('rspec-puppet support for testing warning()')
        end
      end
    end # owner =>

    context 'group =>' do
      context 'apenny' do
        it_behaves_like 'fragment', 'motd_header', {
          :group  => 'apenny',
          :target => '/etc/motd',
        }

        it 'should create a warning' do
          pending('rspec-puppet support for testing warning()')
        end
      end
    end # group =>

    context 'backup =>' do
      context 'foo' do
        it_behaves_like 'fragment', 'motd_header', {
          :backup => 'foo',
          :target => '/etc/motd',
        }

        it 'should create a warning' do
          pending('rspec-puppet support for testing warning()')
        end
      end
    end # backup =>
  end # deprecated params

end
require 'spec_helper'

describe 'concat', :type => :define do

  shared_examples 'concat' do |title, params, id| 
    params = {} if params.nil?
    id = 'root' if id.nil?

    # default param values
    p = {
      :ensure         => 'present',
      :path           => title,
      :owner          => nil,
      :group          => nil,
      :mode           => '0644',
      :warn           => false,
      :force          => false,
      :backup         => 'puppet',
      :replace        => true,
      :order          => 'alpha',
      :ensure_newline => false,
    }.merge(params)

    safe_name            = title.gsub('/', '_')
    concatdir            = '/var/lib/puppet/concat'
    fragdir              = "#{concatdir}/#{safe_name}"
    concat_name          = 'fragments.concat.out'
    default_warn_message = '# This file is managed by Puppet. DO NOT EDIT.'

    file_defaults = {
      :backup  => false,
    }

    let(:title) { title }
    let(:params) { params }
    let(:facts) {{ :concat_basedir => concatdir, :id => id }}

    if p[:ensure] == 'present'
      it do
        should contain_file(fragdir).with(file_defaults.merge({
          :ensure => 'directory',
          :mode   => '0750',
        }))
      end

      it do
        should contain_file("#{fragdir}/fragments").with(file_defaults.merge({
          :ensure  => 'directory',
          :mode    => '0750',
          :force   => true,
          :ignore  => ['.svn', '.git', '.gitignore'],
          :purge   => true,
          :recurse => true,
        }))
      end

      [
        "#{fragdir}/fragments.concat",
        "#{fragdir}/#{concat_name}",
      ].each do |file|
        it do
          should contain_file(file).with(file_defaults.merge({
            :ensure => 'present',
            :mode   => '0640',
          }))
        end
      end

      it do
        should contain_file(title).with(file_defaults.merge({
          :ensure  => 'present',
          :owner   => p[:owner],
          :group   => p[:group],
          :mode    => p[:mode],
          :replace => p[:replace],
          :path    => p[:path],
          :alias   => "concat_#{title}",
          :source  => "#{fragdir}/#{concat_name}",
          :backup  => p[:backup],
        }))
      end

      cmd = "#{concatdir}/bin/concatfragments.sh " +
            "-o \"#{concatdir}/#{safe_name}/fragments.concat.out\" " +
            "-d \"#{concatdir}/#{safe_name}\""

      # flag order: fragdir, warnflag, forceflag, orderflag, newlineflag 
      if p.has_key?(:warn)
        case p[:warn]
        when TrueClass
          message = default_warn_message
        when 'true', 'yes', 'on'
          # should generate a stringified boolean warning
          message = default_warn_message
        when FalseClass
          message = nil
        when 'false', 'no', 'off'
          # should generate a stringified boolean warning
          message = nil
        else
          message = p[:warn]
        end

        unless message.nil?
          cmd += " -w \'#{message}\'"
        end
      end

      cmd += " -f" if p[:force]
      cmd += " -n" if p[:order] == 'numeric'
      cmd += " -l" if p[:ensure_newline] == true

      it do
        should contain_exec("concat_#{title}").with({
          :alias   => "concat_#{fragdir}",
          :command => cmd,
          :unless  => "#{cmd} -t",
        })
      end
    else
      [
        fragdir,
        "#{fragdir}/fragments",
        "#{fragdir}/fragments.concat",
        "#{fragdir}/#{concat_name}",
      ].each do |file|
        it do
          should contain_file(file).with(file_defaults.merge({
            :ensure => 'absent',
            :backup => false,
            :force  => true,
          }))
        end
      end

      it do
        should contain_file(title).with(file_defaults.merge({
          :ensure => 'absent',
          :backup => p[:backup],
        }))
      end

      it do
        should contain_exec("concat_#{title}").with({
          :alias   => "concat_#{fragdir}",
          :command => 'true',
          :path    => '/bin:/usr/bin',
        })
      end
    end
  end

  context 'title' do
    context 'without path param' do
      # title/name is the default value for the path param. therefore, the
      # title must be an absolute path unless path is specified
      ['/foo', '/foo/bar', '/foo/bar/baz'].each do |title|
        context title do
          it_behaves_like 'concat', '/etc/foo.bar'
        end
      end

      ['./foo', 'foo', 'foo/bar'].each do |title|
        context title do
          let(:title) { title }
          it 'should fail' do
            expect { should }.to raise_error(Puppet::Error, /is not an absolute path/)
          end
        end
      end
    end

    context 'with path param' do
      ['./foo', 'foo', 'foo/bar'].each do |title|
        context title do
          it_behaves_like 'concat', title, { :path => '/etc/foo.bar' }
        end
      end
    end
  end # title =>

  context 'as non-root user' do
    it_behaves_like 'concat', '/etc/foo.bar', {}, 'bob'
  end

  context 'ensure =>' do
    ['present', 'absent'].each do |ens|
      context ens do
        it_behaves_like 'concat', '/etc/foo.bar', { :ensure => ens }
      end
    end

    context 'invalid' do
      let(:title) { '/etc/foo.bar' }
      let(:params) {{ :ensure => 'invalid' }}
      it 'should fail' do
        expect { should }.to raise_error(Puppet::Error, /#{Regexp.escape('does not match "^present$|^absent$"')}/)
      end
    end
  end # ensure =>

  context 'path =>' do
    context '/foo' do
      it_behaves_like 'concat', '/etc/foo.bar', { :path => '/foo' }
    end

    ['./foo', 'foo', 'foo/bar', false].each do |path|
      context path do
        let(:title) { '/etc/foo.bar' }
        let(:params) {{ :path => path }}
        it 'should fail' do
          expect { should }.to raise_error(Puppet::Error, /is not an absolute path/)
        end
      end
    end
  end # path =>

  context 'owner =>' do
    context 'apenney' do
      it_behaves_like 'concat', '/etc/foo.bar', { :owner => 'apenny' }
    end

    context 'false' do
      let(:title) { '/etc/foo.bar' }
      let(:params) {{ :owner => false }}
      it 'should fail' do
        expect { should }.to raise_error(Puppet::Error, /is not a string/)
      end
    end
  end # owner =>

  context 'group =>' do
    context 'apenney' do
      it_behaves_like 'concat', '/etc/foo.bar', { :group => 'apenny' }
    end

    context 'false' do
      let(:title) { '/etc/foo.bar' }
      let(:params) {{ :group => false }}
      it 'should fail' do
        expect { should }.to raise_error(Puppet::Error, /is not a string/)
      end
    end
  end # group =>

  context 'mode =>' do
    context '1755' do
      it_behaves_like 'concat', '/etc/foo.bar', { :mode => '1755' }
    end

    context 'false' do
      let(:title) { '/etc/foo.bar' }
      let(:params) {{ :mode => false }}
      it 'should fail' do
        expect { should }.to raise_error(Puppet::Error, /is not a string/)
      end
    end
  end # mode =>

  context 'warn =>' do
    [true, false, '# foo'].each do |warn|
      context warn do
        it_behaves_like 'concat', '/etc/foo.bar', { :warn => warn }
      end
    end

    context '(stringified boolean)' do
      ['true', 'yes', 'on', 'false', 'no', 'off'].each do |warn|
        context warn do
          it_behaves_like 'concat', '/etc/foo.bar', { :warn => warn }

          it 'should create a warning' do
            pending('rspec-puppet support for testing warning()')
          end
        end
      end
    end

    context '123' do
      let(:title) { '/etc/foo.bar' }
      let(:params) {{ :warn => 123 }}
      it 'should fail' do
        expect { should }.to raise_error(Puppet::Error, /is not a string or boolean/)
      end
    end
  end # warn =>

  context 'force =>' do
    [true, false].each do |force|
      context force do
        it_behaves_like 'concat', '/etc/foo.bar', { :force => force }
      end
    end

    context '123' do
      let(:title) { '/etc/foo.bar' }
      let(:params) {{ :force => 123 }}
      it 'should fail' do
        expect { should }.to raise_error(Puppet::Error, /is not a boolean/)
      end
    end
  end # force =>

  context 'backup =>' do
    context 'reverse' do
      it_behaves_like 'concat', '/etc/foo.bar', { :backup => 'reverse' }
    end

    context 'false' do
      let(:title) { '/etc/foo.bar' }
      let(:params) {{ :backup => false }}
      it 'should fail' do
        expect { should }.to raise_error(Puppet::Error, /is not a string/)
      end
    end
  end # backup =>

  context 'replace =>' do
    [true, false].each do |replace|
      context replace do
        it_behaves_like 'concat', '/etc/foo.bar', { :replace => replace }
      end
    end

    context '123' do
      let(:title) { '/etc/foo.bar' }
      let(:params) {{ :replace => 123 }}
      it 'should fail' do
        expect { should }.to raise_error(Puppet::Error, /is not a boolean/)
      end
    end
  end # replace =>

  context 'order =>' do
    ['alpha', 'numeric'].each do |order|
      context order do
        it_behaves_like 'concat', '/etc/foo.bar', { :order => order }
      end
    end

    context 'invalid' do
      let(:title) { '/etc/foo.bar' }
      let(:params) {{ :order => 'invalid' }}
      it 'should fail' do
        expect { should }.to raise_error(Puppet::Error, /#{Regexp.escape('does not match "^alpha$|^numeric$"')}/)
      end
    end
  end # order =>

  context 'ensure_newline =>' do
    [true, false].each do |ensure_newline|
      context 'true' do
        it_behaves_like 'concat', '/etc/foo.bar', { :ensure_newline => ensure_newline}
      end
    end

    context '123' do
      let(:title) { '/etc/foo.bar' }
      let(:params) {{ :ensure_newline => 123 }}
      it 'should fail' do
        expect { should }.to raise_error(Puppet::Error, /is not a boolean/)
      end
    end
  end # ensure_newline =>

  describe 'deprecated parameter' do
    context 'gnu =>' do
      context 'foo' do
        it_behaves_like 'concat', '/etc/foo.bar', { :gnu => 'foo'}

        it 'should create a warning' do
          pending('rspec-puppet support for testing warning()')
        end
      end
    end
  end

end

# vim:sw=2:ts=2:expandtab:textwidth=79
require 'spec_helper'

describe 'concat_basedir', :type => :fact do
  before(:each) { Facter.clear }

  context 'Puppet[:vardir] ==' do
    it '/var/lib/puppet' do
      Puppet.stubs(:[]).with(:vardir).returns('/var/lib/puppet')
      Facter.fact(:concat_basedir).value.should == '/var/lib/puppet/concat'
    end

    it '/home/apenny/.puppet/var' do
      Puppet.stubs(:[]).with(:vardir).returns('/home/apenny/.puppet/var')
      Facter.fact(:concat_basedir).value.should == '/home/apenny/.puppet/var/concat'
    end
  end

end
concat { 'testconcat':
  ensure => present,
  path   => '/tmp/concat',
  owner  => 'root',
  group  => 'root',
  mode   => '0664',
}

concat::fragment { '1':
  target  => 'testconcat',
  content => '1',
  order   => '01',
}

concat::fragment { '2':
  target  => 'testconcat',
  content => '2',
  order   => '02',
}
concat { '/tmp/concat':
  ensure => present,
  force  => true,
  owner  => 'root',
  group  => 'root',
  mode   => '0644',
}
fixtures:
  repositories:
    stdlib: git://github.com/puppetlabs/puppetlabs-stdlib.git
  symlinks:
    elasticsearch: "#{source_dir}"
language: ruby
rvm:
  - 1.8.7
  - 1.9.3
  - 2.0.0
script:
  - "rake lint"
  - "rake parser_validate"
  - "rake template_verify"
  - "rake spec SPEC_OPTS='--format documentation'"
env:
  - PUPPET_VERSION="~> 2.7.0"
  - PUPPET_VERSION="~> 3.0.0"
  - PUPPET_VERSION="~> 3.1.0"
  - PUPPET_VERSION="~> 3.2.0"
  - PUPPET_VERSION="~> 3.3.0"
matrix:
  allow_failures:
    - rvm: 2.0.0
gemfile: Gemfile
notifications:
  email:
    recipients:
      - richard.pijnenburg@elasticsearch.com
    on_success: change
    on_failure: always
  hipchat:
    rooms:
      secure: "gFaED3lu9MRrmoojO2iagrfOaKAbCeQSqVZ9TsIo+qkqem8hwOsMuxsYQ9evPbPbanXQoVNALXTd4fgQW16+hfg/ClqI3nDtVZZJSy0W+U0yVZtz9TXFpi9Q/Z4TwK5TMdNMjemt0l2idY2SE3leHBZEeaIAGfLf0v38tCsNI84="
    template:
       - '@electrical %{repository}#%{build_number} (%{branch} - %{commit} : %{author}): %{message} %{build_url}'
    on_success: change
    on_failure: always
0.2.2 ( Jan 23, 2014 )
  Ensure exec names are unique. This caused issues when using our logstash module
  Add spec tests for plugin define

0.2.1 ( Jan 22, 2014 )
  Simplify the management of the defaults file ( PR #64 )
  Doc improvements for the plugin define ( PR #66 )
  Allow creation of data directory ( PR #68 )
  Fail early when package version and package_url are defined

0.2.0 ( Nov 19, 2013 )
  Large rewrite of the entire module described below
  Make the core more dynamic for different service providers and multi instance capable
  Add better testing and devided into different files
  Fix template function. Replace of template is now only done when the file is changed
  Add different ways to install the package except from the repository ( puppet/http/https/ftp/file )
  Update java class to install openjdk 1.7
  Add tests for python function
  Update config file template to fix scoping issue ( from PR #57 )
  Add validation of templates
  Small changes for preperation for system tests
  Update readme for new functionality
  Added more test scenario's
  Added puppet parser validate task for added checking
  Ensure we don't add stuff when removing the module
  Update python client define
  Add ruby client define
  Add tests for ruby clients and update python client tests

0.1.3 ( Sep 06, 2013 )
  Exec path settings has been updated to fix warnings ( PR #37, #47 )
  Adding define to install python bindings ( PR #43 )
  Scope deprecation fixes ( PR #41 )
  feature to install plugins ( PR #40 )

0.1.2 ( Jun 21, 2013 )
  Update rake file to ignore the param inherit
  Added missing documentation to the template define
  Fix for template define to allow multiple templates ( PR #36 by Bruce Morrison )

0.1.1 ( Jun 14, 2013 )
  Add Oracle Linux to the OS list ( PR #25 by Stas Alekseev )
  Respect the restart_on_change on the defaults ( PR #29 by Simon Effenberg )
  Make sure the config can be empty as advertised in the readme
  Remove dependency cycle when the defaults file is updated ( PR #31 by Bruce Morrison )
  Enable retry on the template insert in case ES isn't started yet ( PR #32 by Bruce Morrison )
  Update templates to avoid deprecation notice with Puppet 3.2.x
  Update template define to avoid auto insert issue with ES
  Update spec tests to reflect changes to template define

0.1.0 ( May 09, 2013 )
  Populate .gitignore ( PR #19 by Igor Galić )
  Add ability to install initfile ( PR #20 by Justin Lambert )
  Add ability to manage default file* service parameters ( PR #21 by Mathieu Bornoz )
  Providing complete containment of the module ( PR #24 by Brian Lalor )
  Add ability to specify package version ( PR #25 by Justin Lambert )
  Adding license file

0.0.7 ( Mar 23, 2013 )
  Ensure config directory is created and managed ( PR #13 by Martin Seener )
  Dont backup package if it changes
  Create explicit dependency on template directory ( PR #16 by Igor Galić )
  Make the config directory variable ( PR #17 by Igor Galić and PR #18 by Vincent Janelle )
  Fixing template define

0.0.6 ( Mar 05, 2013 )
  Fixing issue with configuration not printing out arrays
  New feature to write the config hash shorter
  Updated readme to reflect the new feature
  Adding spec tests for config file generation

0.0.5 ( Mar 03, 2013 )
  Option to disable restart on config file change ( PR #10 by Chris Boulton )

0.0.4 ( Mar 02, 2013 )
  Fixed a major issue with the config template ( Issue #9 )

0.0.3 ( Mar 02, 2013 )
  Adding spec tests
  Fixed init issue on Ubuntu ( Issue #6 by Marcus Furlong )
  Fixed config template problem ( Issue #8 by surfchris )
  New feature to manage templates

0.0.2 ( Feb 16, 2013 )
  Feature to supply a package instead of being dependent on the repository
  Feature to install java in case one doesn't manage it externally
  Adding RedHat and Amazon as Operating systems
  fixed a typo - its a shard not a shared :) ( PR #5 by Martin Seener )

0.0.1 ( Jan 13, 2013 )
  Initial release of the module
If you have a bugfix or new feature that you would like to contribute to this puppet module, please find or open an issue about it first. Talk about what you would like to do. It may be that somebody is already working on it, or that there are particular issues that you should know about before implementing the change.

We enjoy working with contributors to get their code accepted. There are many approaches to fixing a problem and it is important to find the best approach before writing too much code.

The process for contributing to any of the Elasticsearch repositories is similar.

1. Sign the contributor license agreement  
Please make sure you have signed the [Contributor License Agreement](http://www.elasticsearch.org/contributor-agreement/). We are not asking you to assign copyright to us, but to give us the right to distribute your code without restriction. We ask this of all contributors in order to assure our users of the origin and continuing existence of the code. You only need to sign the CLA once.

2. Run the rspec tests and ensure it completes without errors with your changes.

3. Rebase your changes
Update your local repository with the most recent code from the main this puppet module repository, and rebase your branch on top of the latest master branch. We prefer your changes to be squashed into a single commit.

4. Submit a pull request
Push your local changes to your forked copy of the repository and submit a pull request. In the pull request, describe what your changes do and mention the number of the issue where discussion has taken place, eg “Closes #123″.

Then sit back and wait. There will probably be discussion about the pull request and, if any changes are needed, we would love to work with you to get your pull request merged into this puppet module.
The following is a list of people who have contributed ideas, code, bug
reports, or in general have helped this puppet module along its way.

Project Owner
* Richard Pijnenburg (electrical)

Contributors:
Martin Seener (martinseener)
Marcus Furlong (furlongm)
Chris Boulton (chrisboulton)
Igor Galić (igalic)
Vincent Janelle (vjanelle)
Mathieu Bornoz (mbornoz)
Justin Lambert (jlambert121)
Brian Lalor (blalor)
Stas Alekseev (salekseev)
Simon Effenberg (Savar)
Bruce Morrison (brucem)
deanmalmgren
Matteo Sessa (msessa-cotd)
source 'https://rubygems.org'

puppetversion = ENV['PUPPET_VERSION']
gem 'puppet', puppetversion, :require => false
gem 'puppet-lint'
gem 'rspec-puppet'
gem 'puppetlabs_spec_helper', '>= 0.1.0'
Copyright (c) 2012-2014 Elasticsearch <http://www.elasticsearch.org>

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
name    'elasticsearch-elasticsearch'
version '0.2.2'
source 'https://github.com/elasticsearch/puppet-elasticsearch'
author 'elasticsearch'
license 'Apache License, Version 2.0'
summary 'Module for managing and configuring Elasticsearch nodes'
description 'Module for managing and configuring Elasticsearch nodes'
project_page 'https://github.com/elasticsearch/puppet-elasticsearch'
dependency 'puppetlabs/stdlib', '>= 3.0.0'
# puppet-elasticsearch

A puppet module for managing elasticsearch nodes

http://www.elasticsearch.org/

[![Build Status](https://travis-ci.org/elasticsearch/puppet-elasticsearch.png?branch=master)](https://travis-ci.org/elasticsearch/puppet-elasticsearch)

## Usage

Installation, make sure service is running and will be started at boot time:

     class { 'elasticsearch': }

Install a certain version:

     class { 'elasticsearch':
       version => '0.90.3'
     }

This assumes an elasticsearch package is already available to your distribution's package manager. To install it in a different way:

To download from http/https/ftp source:

     class { 'elasticsearch':
       package_url => 'https://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-0.90.7.deb'
     }

To download from a puppet:// source:

     class { 'elasticsearch':
       package_url => 'puppet:///path/to/elasticsearch-0.90.7.deb'
     }

Or use a local file source:

     class { 'elasticsearch':
       package_url => 'file:/path/to/elasticsearch-0.90.7.deb'
     }

Automatic upgrade of the software ( default set to false ):

     class { 'elasticsearch':
       autoupgrade => true
     }

Removal/decommissioning:

     class { 'elasticsearch':
       ensure => 'absent'
     }

Install everything but disable service(s) afterwards:

     class { 'elasticsearch':
       status => 'disabled'
     }

Disable automated restart of Elasticsearch on config file change:

     class { 'elasticsearch':
       restart_on_change => false
     }

For the config variable a hash needs to be passed:

     class { 'elasticsearch':
       config                   => {
         'node'                 => {
           'name'               => 'elasticsearch001'
         },
         'index'                => {
           'number_of_replicas' => '0',
           'number_of_shards'   => '5'
         },
         'network'              => {
           'host'               => $::ipaddress
         }
       }
     }

Short write up of the config hash is also possible.

Instead of writing the full hash representation:

     class { 'elasticsearch':
       config                 => {
         'cluster'            => {
           'name'             => 'ClusterName',
           'routing'          => {
             'allocation'     => {
               'awareness'    => {
                 'attributes' => 'rack'
               }
             }
           }
         }
       }
     }

You can write the dotted key naming:

     class { 'elasticsearch':
       config => {
         'cluster' => {
           'name' => 'ClusterName',
           'routing.allocation.awareness.attributes' => 'rack'
         }
       }
     }


## Manage templates

### Add a new template

This will install and/or replace the template in Elasticearch

     elasticsearch::template { 'templatename':
       file => 'puppet:///path/to/template.json'
     }

### Delete a template

     elasticsearch::template { 'templatename':
       ensure => 'absent'
     }

### Host

  Default it uses localhost:9200 as host. you can change this with the 'host' and 'port' variables

     elasticsearch::template { 'templatename':
       host => $::ipaddress,
       port => 9200
     }

## Bindings / clients

Install a variety of [clients/bindings](http://www.elasticsearch.org/guide/clients/):

### Python

     elasticsearch::python { 'rawes': }

### Ruby

     elasticsearch::ruby { 'elasticsearch': }

## Plugins

Install [a variety of plugins](http://www.elasticsearch.org/guide/clients/):

### From official repository:

     elasticsearch::plugin{'mobz/elasticsearch-head':
       module_dir => 'head'
     }

### From custom url:

     elasticsearch::plugin{ 'elasticsearch-jetty':
       module_dir => 'jetty',
       url        => 'https://oss-es-plugins.s3.amazonaws.com/elasticsearch-jetty/elasticsearch-jetty-0.90.0.zip'
     }

## Java install

For those that have no separate module for installation of java:

     class { 'elasticsearch':
       java_install => true
     }

If you want a specific java package/version:

     class { 'elasticsearch':
       java_install => true,
       java_package => 'packagename'
     }

## Service providers

Currently only the 'init' service provider is supported but others can be implemented quite easy.

### init

#### Defaults file

You can populate the defaults file ( /etc/defaults/elasticsearch or /etc/sysconfig/elasticsearch )

##### hash representation

     class { 'elasticsearch':
       init_defaults => { 'ES_USER' => 'elasticsearch', 'ES_GROUP' => 'elasticsearch' }
     }

##### file source

     class { 'elasticsearch':
       init_defaults_file => 'puppet:///path/to/defaults'
     }

require 'rubygems'
require 'puppetlabs_spec_helper/rake_tasks'
require 'puppet-lint'
require './spec/lib/template_check_task.rb'
require './spec/lib/parser_validate_task.rb'
PuppetLint.configuration.send("disable_80chars")
PuppetLint.configuration.send("disable_class_inherits_from_params_class")
# == Class: elasticsearch::config
#
# This class exists to coordinate all configuration related actions,
# functionality and logical units in a central place.
#
#
# === Parameters
#
# This class does not provide any parameters.
#
#
# === Examples
#
# This class may be imported by other classes to use its functionality:
#   class { 'elasticsearch::config': }
#
# It is not intended to be used directly by external resources like node
# definitions or other modules.
#
#
# === Authors
#
# * Richard Pijnenburg <mailto:richard@ispavailability.com>
#
class elasticsearch::config {

  #### Configuration

  File {
    owner => $elasticsearch::elasticsearch_user,
    group => $elasticsearch::elasticsearch_group
  }

  Exec {
    path => [ '/bin', '/usr/bin', '/usr/local/bin' ],
    cwd  => '/',
  }

  if ( $elasticsearch::ensure == 'present' ) {

    $notify_service = $elasticsearch::restart_on_change ? {
      true  => Class['elasticsearch::service'],
      false => undef,
    }

    file { $elasticsearch::confdir:
      ensure => directory,
      mode   => '0644',
      purge  => $elasticsearch::purge_confdir,
      force  => $elasticsearch::purge_confdir
    }

    file { "${elasticsearch::confdir}/elasticsearch.yml":
      ensure  => file,
      content => template("${module_name}/etc/elasticsearch/elasticsearch.yml.erb"),
      mode    => '0644',
      notify  => $notify_service
    }

    exec { 'mkdir_templates_elasticsearch':
      command => "mkdir -p ${elasticsearch::confdir}/templates_import",
      creates => "${elasticsearch::confdir}/templates_import"
    }

    file { "${elasticsearch::confdir}/templates_import":
      ensure  => 'directory',
      mode    => '0644',
      require => Exec['mkdir_templates_elasticsearch']
    }

    if ( $elasticsearch::datadir != undef ) {
      file { $elasticsearch::datadir:
        ensure  => 'directory',
        owner   => $elasticsearch::elasticsearch_user,
        group   => $elasticsearch::elasticsearch_group,
        mode    => '0770',
      }
    }

  } elsif ( $elasticsearch::ensure == 'absent' ) {

    file { $elasticsearch::confdir:
      ensure  => 'absent',
      recurse => true,
      force   => true
    }

  }

}
# == Class: elasticsearch
#
# This class is able to install or remove elasticsearch on a node.
# It manages the status of the related service.
#
# === Parameters
#
# [*ensure*]
#   String. Controls if the managed resources shall be <tt>present</tt> or
#   <tt>absent</tt>. If set to <tt>absent</tt>:
#   * The managed software packages are being uninstalled.
#   * Any traces of the packages will be purged as good as possible. This may
#     include existing configuration files. The exact behavior is provider
#     dependent. Q.v.:
#     * Puppet type reference: {package, "purgeable"}[http://j.mp/xbxmNP]
#     * {Puppet's package provider source code}[http://j.mp/wtVCaL]
#   * System modifications (if any) will be reverted as good as possible
#     (e.g. removal of created users, services, changed log settings, ...).
#   * This is thus destructive and should be used with care.
#   Defaults to <tt>present</tt>.
#
# [*autoupgrade*]
#   Boolean. If set to <tt>true</tt>, any managed package gets upgraded
#   on each Puppet run when the package provider is able to find a newer
#   version than the present one. The exact behavior is provider dependent.
#   Q.v.:
#   * Puppet type reference: {package, "upgradeable"}[http://j.mp/xbxmNP]
#   * {Puppet's package provider source code}[http://j.mp/wtVCaL]
#   Defaults to <tt>false</tt>.
#
# [*status*]
#   String to define the status of the service. Possible values:
#   * <tt>enabled</tt>: Service is running and will be started at boot time.
#   * <tt>disabled</tt>: Service is stopped and will not be started at boot
#     time.
#   * <tt>running</tt>: Service is running but will not be started at boot time.
#     You can use this to start a service on the first Puppet run instead of
#     the system startup.
#   * <tt>unmanaged</tt>: Service will not be started at boot time and Puppet
#     does not care whether the service is running or not. For example, this may
#     be useful if a cluster management software is used to decide when to start
#     the service plus assuring it is running on the desired node.
#   Defaults to <tt>enabled</tt>. The singular form ("service") is used for the
#   sake of convenience. Of course, the defined status affects all services if
#   more than one is managed (see <tt>service.pp</tt> to check if this is the
#   case).
#
# [*version*]
#   String to set the specific version you want to install.
#   Defaults to <tt>false</tt>.
#
# [*restart_on_change*]
#   Boolean that determines if the application should be automatically restarted
#   whenever the configuration changes. Disabling automatic restarts on config
#   changes may be desired in an environment where you need to ensure restarts
#   occur in a controlled/rolling manner rather than during a Puppet run.
#
#   Defaults to <tt>true</tt>, which will restart the application on any config
#   change. Setting to <tt>false</tt> disables the automatic restart.
#
# [*confdir*]
#   Path to directory containing the elasticsearch configuration.
#   Use this setting if your packages deviate from the norm (/etc/elasticsearch)
#
# [*plugindir*]
#   Path to directory containing the elasticsearch plugins
#   Use this setting if your packages deviate from the norm (/usr/share/elasticsearch/plugins)
#
# [*plugintool*]
#   Path to directory containing the elasticsearch plugin installation script
#   Use this setting if your packages deviate from the norm (/usr/share/elasticsearch/bin/plugin)
#
# The default values for the parameters are set in elasticsearch::params. Have
# a look at the corresponding <tt>params.pp</tt> manifest file if you need more
# technical information about them.
#
# === Examples
#
# * Installation, make sure service is running and will be started at boot time:
#     class { 'elasticsearch': }
#
# * Removal/decommissioning:
#     class { 'elasticsearch':
#       ensure => 'absent',
#     }
#
# * Install everything but disable service(s) afterwards
#     class { 'elasticsearch':
#       status => 'disabled',
#     }
#
#
# === Authors
#
# * Richard Pijnenburg <mailto:richard@ispavailability.com>
#
class elasticsearch(
  $ensure              = $elasticsearch::params::ensure,
  $status              = $elasticsearch::params::status,
  $restart_on_change   = $elasticsearch::params::restart_on_change,
  $autoupgrade         = $elasticsearch::params::autoupgrade,
  $version             = false,
  $package_provider    = 'package',
  $package_url         = undef,
  $package_dir         = $elasticsearch::params::package_dir,
  $purge_package_dir   = $elasticsearch::params::purge_package_dir,
  $elasticsearch_user  = $elasticsearch::params::elasticsearch_user,
  $elasticsearch_group = $elasticsearch::params::elasticsearch_group,
  $purge_confdir       = $elasticsearch::params::purge_confdir,
  $service_provider    = 'init',
  $init_defaults       = undef,
  $init_defaults_file  = undef,
  $init_template       = undef,
  $config              = {},
  $confdir             = $elasticsearch::params::confdir,
  $datadir             = undef,
  $plugindir           = $elasticsearch::params::plugindir,
  $plugintool          = $elasticsearch::params::plugintool,
  $java_install        = false,
  $java_package        = undef
) inherits elasticsearch::params {

  anchor {'elasticsearch::begin': }
  anchor {'elasticsearch::end': }


  #### Validate parameters

  # ensure
  if ! ($ensure in [ 'present', 'absent' ]) {
    fail("\"${ensure}\" is not a valid ensure parameter value")
  }

  # autoupgrade
  validate_bool($autoupgrade)

  # service status
  if ! ($status in [ 'enabled', 'disabled', 'running', 'unmanaged' ]) {
    fail("\"${status}\" is not a valid status parameter value")
  }

  # restart on change
  validate_bool($restart_on_change)

  # purge conf dir
  validate_bool($purge_confdir)

  if ! ($service_provider in $elasticsearch::params::service_providers) {
    fail("\"${service_provider}\" is not a valid provider for \"${::operatingsystem}\"")
  }

  if ($package_url != undef and $version != false) {
    fail('Unable to set the version number when using package_url option.')
  }

  # validate config hash
  validate_hash($config)

  # java install validation
  validate_bool($java_install)

  #### Manage actions

  # package(s)
  class { 'elasticsearch::package': }

  # configuration
  class { 'elasticsearch::config': }

  # service(s)
  class { 'elasticsearch::service': }

  if $java_install == true {
    # Install java
    class { 'elasticsearch::java': }

    # ensure we first java java and then manage the service
    Anchor['elasticsearch::begin']
    -> Class['elasticsearch::java']
    -> Class['elasticsearch::service']
  }

  #### Manage relationships

  if $ensure == 'present' {

    # we need the software before configuring it
    Anchor['elasticsearch::begin']
    -> Class['elasticsearch::package']
    -> Class['elasticsearch::config']

    # we need the software and a working configuration before running a service
    Class['elasticsearch::package'] -> Class['elasticsearch::service']
    Class['elasticsearch::config']  -> Class['elasticsearch::service']

    Class['elasticsearch::service'] -> Anchor['elasticsearch::end']

  } else {

    # make sure all services are getting stopped before software removal
    Anchor['elasticsearch::begin']
    -> Class['elasticsearch::service']
    -> Class['elasticsearch::package']
    -> Anchor['elasticsearch::end']

  }

}
# == Class: elasticsearch::java
#
# This class exists to install java if its not managed from an other module
#
#
# === Parameters
#
# This class does not provide any parameters.
#
#
# === Examples
#
# This class may be imported by other classes to use its functionality:
#   class { 'elasticsearch::java': }
#
# It is not intended to be used directly by external resources like node
# definitions or other modules.
#
#
# === Authors
#
# * Richard Pijnenburg <mailto:richard@ispavailability.com>
#
class elasticsearch::java {

  if $elasticsearch::java_package == undef {
    # Default Java package
    case $::operatingsystem {
      'CentOS', 'Fedora', 'Scientific', 'RedHat', 'Amazon', 'OracleLinux': {
        $package = 'java-1.7.0-openjdk'
      }
      'Debian', 'Ubuntu': {
        $package = 'openjdk-7-jre-headless'
      }
      default: {
        fail("\"${module_name}\" provides no java package
              for \"${::operatingsystem}\"")
      }
    }
  } else {
    $package = $elasticsearch::java_package
  }

  ## Install the java package unless already specified somewhere else
  if !defined(Package[$package]) {
    package { $package:
      ensure => present
    }
  }
}
# == Class: elasticsearch::package
#
# This class exists to coordinate all software package management related
# actions, functionality and logical units in a central place.
#
#
# === Parameters
#
# This class does not provide any parameters.
#
#
# === Examples
#
# This class may be imported by other classes to use its functionality:
#   class { 'elasticsearch::package': }
#
# It is not intended to be used directly by external resources like node
# definitions or other modules.
#
#
# === Authors
#
# * Richard Pijnenburg <mailto:richard@ispavailability.com>
#
class elasticsearch::package {


  #### Package management

  # set params: in operation
  if $elasticsearch::ensure == 'present' {

    # Check if we want to install a specific version or not
    if $elasticsearch::version == false {

      $package_ensure = $elasticsearch::autoupgrade ? {
        true  => 'latest',
        false => 'present',
      }

    } else {

      # install specific version
      $package_ensure = $elasticsearch::version

    }

    # action
    if ($elasticsearch::package_url != undef) {

      $package_dir = $elasticsearch::package_dir

      # Create directory to place the package file
      exec { 'create_package_dir_elasticsearch':
        cwd     => '/',
        path    => ['/usr/bin', '/bin'],
        command => "mkdir -p ${elasticsearch::package_dir}",
        creates => $elasticsearch::package_dir;
      }

      file { $package_dir:
        ensure  => 'directory',
        purge   => $elasticsearch::purge_package_dir,
        force   => $elasticsearch::purge_package_dir,
        require => Exec['create_package_dir_elasticsearch'],
      }

      $filenameArray = split($elasticsearch::package_url, '/')
      $basefilename = $filenameArray[-1]

      $sourceArray = split($elasticsearch::package_url, ':')
      $protocol_type = $sourceArray[0]

      $extArray = split($basefilename, '\.')
      $ext = $extArray[-1]

      case $protocol_type {

        puppet: {

          file { "${package_dir}/${basefilename}":
            ensure  => present,
            source  => $elasticsearch::package_url,
            require => File[$package_dir],
            backup  => false,
            before  => Package[$elasticsearch::params::package]
          }

        }
        ftp, https, http: {

          exec { 'download_package_elasticsearch':
            command => "${elasticsearch::params::dlcmd} ${package_dir}/${basefilename} ${elasticsearch::package_url} 2> /dev/null",
            path    => ['/usr/bin', '/bin'],
            creates => "${package_dir}/${basefilename}",
            require => File[$package_dir],
            before  => Package[$elasticsearch::params::package]
          }

        }
        file: {

          $source_path = $sourceArray[1]
          file { "${package_dir}/${basefilename}":
            ensure  => present,
            source  => $source_path,
            require => File[$package_dir],
            backup  => false,
            before  => Package[$elasticsearch::params::package]
          }

        }
        default: {
          fail("Protocol must be puppet, file, http, https, or ftp. You have given \"${protocol_type}\"")
        }
      }

      case $ext {
        'deb':   { $pkg_provider = 'dpkg' }
        'rpm':   { $pkg_provider = 'rpm'  }
        default: { fail("Unknown file extention \"${ext}\".") }
      }

      $pkg_source = "${package_dir}/${basefilename}"

    } else {
      $pkg_source = undef
      $pkg_provider = undef
    }

  # Package removal
  } else {

    $pkg_source = undef
    $pkg_provider = undef
    $package_ensure = 'purged'
  }

  package { $elasticsearch::params::package:
    ensure   => $package_ensure,
    source   => $pkg_source,
    provider => $pkg_provider
  }

}
# == Class: elasticsearch::params
#
# This class exists to
# 1. Declutter the default value assignment for class parameters.
# 2. Manage internally used module variables in a central place.
#
# Therefore, many operating system dependent differences (names, paths, ...)
# are addressed in here.
#
#
# === Parameters
#
# This class does not provide any parameters.
#
#
# === Examples
#
# This class is not intended to be used directly.
#
#
# === Links
#
# * {Puppet Docs: Using Parameterized Classes}[http://j.mp/nVpyWY]
#
#
# === Authors
#
# * Richard Pijnenburg <mailto:richard@ispavailability.com>
#
class elasticsearch::params {

  #### Default values for the parameters of the main module class, init.pp

  # ensure
  $ensure = 'present'

  # autoupgrade
  $autoupgrade = false

  # service status
  $status = 'enabled'

  # restart on configuration change?
  $restart_on_change = true

  # Package dir. Temporary place to download the package to for installation
  $package_dir = '/var/lib/elasticsearch'

  # User and Group for the files and user to run the service as.
  $elasticsearch_user  = 'elasticsearch'
  $elasticsearch_group = 'elasticsearch'

  # Purge configuration directory
  $purge_confdir = true

  ## init service provider

  # configuration directory
  $confdir = '/etc/elasticsearch'

  # plugins directory
  $plugindir = '/usr/share/elasticsearch/plugins'

  # plugins helper binary
  $plugintool = '/usr/share/elasticsearch/bin/plugin'

  # Download tool
  $dlcmd = 'wget -O'

  $purge_package_dir = false

  #### Internal module values

  # packages
  case $::operatingsystem {
    'RedHat', 'CentOS', 'Fedora', 'Scientific', 'Amazon', 'OracleLinux': {
      # main application
      $package = [ 'elasticsearch' ]
    }
    'Debian', 'Ubuntu': {
      # main application
      $package = [ 'elasticsearch' ]
    }
    default: {
      fail("\"${module_name}\" provides no package default value
            for \"${::operatingsystem}\"")
    }
  }

  # service parameters
  case $::operatingsystem {
    'RedHat', 'CentOS', 'Fedora', 'Scientific', 'Amazon', 'OracleLinux': {
      $service_name       = 'elasticsearch'
      $service_hasrestart = true
      $service_hasstatus  = true
      $service_pattern    = $service_name
      $service_providers  = [ 'init' ]
      $defaults_location  = '/etc/sysconfig'
    }
    'Debian', 'Ubuntu': {
      $service_name       = 'elasticsearch'
      $service_hasrestart = true
      $service_hasstatus  = true
      $service_pattern    = $service_name
      $service_providers  = [ 'init' ]
      $defaults_location  = '/etc/default'
    }
    'Darwin': {
      $service_name       = 'FIXME/TODO'
      $service_hasrestart = true
      $service_hasstatus  = true
      $service_pattern    = $service_name
      $service_providers  = [ 'launchd' ]
      $defaults_location  = false
    }
    default: {
      fail("\"${module_name}\" provides no service parameters
            for \"${::operatingsystem}\"")
    }
  }

}
# == Define: elasticsearch::plugin
#
# This define allows you to install arbitrary Elasticsearch plugins
# either by using the default repositories or by specifying an URL
#
# All default values are defined in the elasticsearch::params class.
#
#
# === Parameters
#
# [*module_dir*]
#   Directory name where the module will be installed
#   Value type is string
#   Default value: None
#   This variable is required
#
# [*ensure*]
#   Whether the plugin will be installed or removed.
#   Set to 'absent' to ensure a plugin is not installed
#   Value type is string
#   Default value: present
#   This variable is optional
#
# [*url*]
#   Specify an URL where to download the plugin from.
#   Value type is string
#   Default value: None
#   This variable is optional
#
#
# === Examples
#
# # From official repository
# elasticsearch::plugin{'mobz/elasticsearch-head': module_dir => 'head'}
#
# # From custom url
# elasticsearch::plugin{ 'elasticsearch-jetty':
#  module_dir => 'elasticsearch-jetty',
#  url        => 'https://oss-es-plugins.s3.amazonaws.com/elasticsearch-jetty/elasticsearch-jetty-0.90.0.zip',
# }
#
# === Authors
#
# * Matteo Sessa <mailto:matteo.sessa@catchoftheday.com.au>
# * Dennis Konert <mailto:dkonert@gmail.com>
#
define elasticsearch::plugin(
    $module_dir,
    $ensure      = 'present',
    $url         = ''
) {

  Exec {
    path => [ '/bin', '/usr/bin', '/usr/local/bin' ],
    cwd  => '/',
  }

  $notify_service = $elasticsearch::restart_on_change ? {
    false   => undef,
    default => Service['elasticsearch'],
  }

  if ($module_dir != '') {
      validate_string($module_dir)
  } else {
      fail("module_dir undefined for plugin ${name}")
  }

  if ($url != '') {
    validate_string($url)
    $install_cmd = "${elasticsearch::plugintool} -install ${name} -url ${url}"
    $exec_rets = [0,1]
  } else {
    $install_cmd = "${elasticsearch::plugintool} -install ${name}"
    $exec_rets = [0,]
  }

  case $ensure {
    'installed', 'present': {
      exec {"install_plugin_${name}":
        command  => $install_cmd,
        creates  => "${elasticsearch::plugindir}/${module_dir}",
        returns  => $exec_rets,
        notify   => $notify_service,
        require  => Class['elasticsearch::package']
      }
    }
    default: {
      exec {"remove_plugin_${name}":
        command => "${elasticsearch::plugintool} --remove ${module_dir}",
        onlyif  => "test -d ${elasticsearch::plugindir}/${module_dir}",
        notify  => $notify_service,
      }
    }
  }
}
# == Define: elasticsearch::python
#
# there are many python bindings for elasticsearch. This provides all
# the ones we know about http://www.elasticsearch.org/guide/clients/
#
#
# === Parameters
#
# [*ensure*]
#   String. Controls if the managed resources shall be <tt>present</tt> or
#   <tt>absent</tt>. If set to <tt>absent</tt>:
#   * The managed software packages are being uninstalled.
#   * Any traces of the packages will be purged as good as possible. This may
#     include existing configuration files. The exact behavior is provider
#     dependent. Q.v.:
#     * Puppet type reference: {package, "purgeable"}[http://j.mp/xbxmNP]
#     * {Puppet's package provider source code}[http://j.mp/wtVCaL]
#   * System modifications (if any) will be reverted as good as possible
#     (e.g. removal of created users, services, changed log settings, ...).
#   * This is thus destructive and should be used with care.
#   Defaults to <tt>present</tt>.

#
#
# === Examples
#
# elasticsearch::python { 'pyes':; }
#
#
# === Authors
#
# * Richard Pijnenburg <mailto:richard@ispavailability.com>
#
define elasticsearch::python (
  $ensure = 'present'
) {

  if ! ($ensure in [ 'present', 'absent' ]) {
    fail("\"${ensure}\" is not a valid ensure parameter value")
  }

  # make sure the package name is valid and setup the provider as
  # necessary
  case $name {
    'pyes': {
      $provider = 'pip'
    }
    'rawes': {
      $provider = 'pip'
    }
    'pyelasticsearch': {
      $provider = 'pip'
    }
    'ESClient': {
      $provider = 'pip'
    }
    'elasticutils': {
      $provider = 'pip'
    }
    'elasticsearch': {
      $provider = 'pip'
    }
    default: {
      fail("unknown python binding package '${name}'")
    }
  }

  package { $name:
    ensure   => $ensure,
    provider => $provider,
  }

}
# == Define: elasticsearch::ruby
#
# there are many ruby bindings for elasticsearch. This provides all
# the ones we know about http://www.elasticsearch.org/guide/clients/
#
#
# === Parameters
#
# [*ensure*]
#   String. Controls if the managed resources shall be <tt>present</tt> or
#   <tt>absent</tt>. If set to <tt>absent</tt>:
#   * The managed software packages are being uninstalled.
#   * Any traces of the packages will be purged as good as possible. This may
#     include existing configuration files. The exact behavior is provider
#     dependent. Q.v.:
#     * Puppet type reference: {package, "purgeable"}[http://j.mp/xbxmNP]
#     * {Puppet's package provider source code}[http://j.mp/wtVCaL]
#   * System modifications (if any) will be reverted as good as possible
#     (e.g. removal of created users, services, changed log settings, ...).
#   * This is thus destructive and should be used with care.
#   Defaults to <tt>present</tt>.

#
#
# === Examples
#
# elasticsearch::ruby { 'elasticsearch':; }
#
#
# === Authors
#
# * Richard Pijnenburg <mailto:richard@ispavailability.com>
#
define elasticsearch::ruby (
  $ensure = 'present'
) {

  if ! ($ensure in [ 'present', 'absent' ]) {
    fail("\"${ensure}\" is not a valid ensure parameter value")
  }

  # make sure the package name is valid and setup the provider as
  # necessary
  case $name {
    'tire': {
      $provider = 'gem'
    }
    'stretcher': {
      $provider = 'gem'
    }
    'elastic_searchable': {
      $provider = 'gem'
    }
    'elasticsearch': {
      $provider = 'gem'
    }
    default: {
      fail("unknown ruby client package '${name}'")
    }
  }

  package { $name:
    ensure   => $ensure,
    provider => $provider,
  }

}
# == Class: elasticsearch::service
#
# This class exists to coordinate all service management related actions,
# functionality and logical units in a central place.
#
# <b>Note:</b> "service" is the Puppet term and type for background processes
# in general and is used in a platform-independent way. E.g. "service" means
# "daemon" in relation to Unix-like systems.
#
#
# === Parameters
#
# This class does not provide any parameters.
#
#
# === Examples
#
# This class may be imported by other classes to use its functionality:
#   class { 'elasticsearch::service': }
#
# It is not intended to be used directly by external resources like node
# definitions or other modules.
#
#
# === Authors
#
# * Richard Pijnenburg <mailto:richard@ispavailability.com>
#
class elasticsearch::service {

  case $elasticsearch::service_provider {

    init: {
      elasticsearch::service::init { 'elasticsearch': }
    }

    default: {
      fail("Unknown service provider ${elasticsearch::service_provider}")
    }

  }

}
# == Define: elasticsearch::service::init
#
# This class exists to coordinate all service management related actions,
# functionality and logical units in a central place.
#
# <b>Note:</b> "service" is the Puppet term and type for background processes
# in general and is used in a platform-independent way. E.g. "service" means
# "daemon" in relation to Unix-like systems.
#
#
# === Parameters
#
# This class does not provide any parameters.
#
#
# === Examples
#
# === Authors
#
# * Richard Pijnenburg <mailto:richard@ispavailability.com>
#
define elasticsearch::service::init{

  #### Service management

  # set params: in operation
  if $elasticsearch::ensure == 'present' {

    case $elasticsearch::status {
      # make sure service is currently running, start it on boot
      'enabled': {
        $service_ensure = 'running'
        $service_enable = true
      }
      # make sure service is currently stopped, do not start it on boot
      'disabled': {
        $service_ensure = 'stopped'
        $service_enable = false
      }
      # make sure service is currently running, do not start it on boot
      'running': {
        $service_ensure = 'running'
        $service_enable = false
      }
      # do not start service on boot, do not care whether currently running
      # or not
      'unmanaged': {
        $service_ensure = undef
        $service_enable = false
      }
      # unknown status
      # note: don't forget to update the parameter check in init.pp if you
      #       add a new or change an existing status.
      default: {
        fail("\"${elasticsearch::status}\" is an unknown service status value")
      }
    }

  # set params: removal
  } else {

    # make sure the service is stopped and disabled (the removal itself will be
    # done by package.pp)
    $service_ensure = 'stopped'
    $service_enable = false

  }

  $notify_service = $elasticsearch::restart_on_change ? {
    true  => Service[$name],
    false => undef,
  }


  if ( $elasticsearch::status != 'unmanaged' ) {

    # defaults file content. Either from a hash or file
    if ($elasticsearch::init_defaults_file != undef) {
      $defaults_content = undef
      $defaults_source  = $elasticsearch::init_defaults_file
    } elsif ($elasticsearch::init_defaults != undef and is_hash($elasticsearch::init_defaults) ) {
      $defaults_content = template("${module_name}/etc/sysconfig/defaults.erb")
      $defaults_source  = undef
    } else {
      $defaults_content = undef
      $defaults_source  = undef
    }

    # Check if we are going to manage the defaults file.
    if ( $defaults_content != undef or $defaults_source != undef ) {

      file { "${elasticsearch::params::defaults_location}/${name}":
        ensure  => $elasticsearch::ensure,
        source  => $defaults_source,
        content => $defaults_content,
        owner   => 'root',
        group   => 'root',
        mode    => '0644',
        before  => Service[$name],
        notify  => $notify_service
      }

    }

    # init file from template
    if ($elasticsearch::init_template != undef) {

      file { "/etc/init.d/${name}":
        ensure  => $elasticsearch::ensure,
        content => template($elasticsearch::init_template),
        owner   => 'root',
        group   => 'root',
        mode    => '0755',
        before  => Service[$name],
        notify  => $notify_service
      }

    }

  }

  # action
  service { $name:
    ensure     => $service_ensure,
    enable     => $service_enable,
    name       => $elasticsearch::params::service_name,
    hasstatus  => $elasticsearch::params::service_hasstatus,
    hasrestart => $elasticsearch::params::service_hasrestart,
    pattern    => $elasticsearch::params::service_pattern,
  }

}
# == Define: elasticsearch::template
#
#  This define allows you to insert, update or delete templates that are used within Elasticsearch for the indexes
#
# === Parameters
#
# [*file*]
#   File path of the template ( json file )
#   Value type is string
#   Default value: undef
#   This variable is optional
#
# [*replace*]
#   Set to 'true' if you intend to replace the existing template
#   Value type is boolean
#   Default value: false
#   This variable is optional
#
# [*delete*]
#   Set to 'true' if you intend to delete the existing template
#   Value type is boolean
#   Default value: false
#   This variable is optional
#
# [*host*]
#   Host name or IP address of the ES instance to connect to
#   Value type is string
#   Default value: localhost
#   This variable is optional
#
# [*port*]
#   Port number of the ES instance to connect to
#   Value type is number
#   Default value: 9200
#   This variable is optional
#
# === Authors
#
# * Richard Pijnenburg <mailto:richard@ispavailability.com>
#
define elasticsearch::template(
  $ensure  = 'present',
  $file    = undef,
  $host    = 'localhost',
  $port    = 9200
) {

  require elasticsearch

  # ensure
  if ! ($ensure in [ 'present', 'absent' ]) {
    fail("\"${ensure}\" is not a valid ensure parameter value")
  }

  if ! is_integer($port) {
    fail("\"${port}\" is not an integer")
  }

  Exec {
    path      => [ '/bin', '/usr/bin', '/usr/local/bin' ],
    cwd       => '/',
    tries     => 3,
    try_sleep => 10
  }

  # Build up the url
  $es_url = "http://${host}:${port}/_template/${name}"

  # Can't do a replace and delete at the same time

  if ($ensure == 'present') {

    # Fail when no file is supplied
    if $file == undef {
      fail('The variable "file" cannot be empty when inserting or updating a template')

    } else { # we are good to go. notify to insert in case we deleted
      $insert_notify = Exec[ "insert_template_${name}" ]
    }

  } else {

    $insert_notify = undef

  }

  # Delete the existing template
  # First check if it exists of course
  exec { "delete_template_${name}":
    command     => "curl -s -XDELETE ${es_url}",
    onlyif      => "test $(curl -s '${es_url}?pretty=true' | wc -l) -gt 1",
    notify      => $insert_notify,
    refreshonly => true
  }

  if ($ensure == 'present') {

    # place the template file
    file { "${elasticsearch::confdir}/templates_import/elasticsearch-template-${name}.json":
      ensure  => 'present',
      source  => $file,
      notify  => Exec[ "delete_template_${name}" ],
      require => Exec[ 'mkdir_templates' ],
    }

    exec { "insert_template_${name}":
      command     => "curl -s -XPUT ${es_url} -d @${elasticsearch::confdir}/templates_import/elasticsearch-template-${name}.json",
      unless      => "test $(curl -s '${es_url}?pretty=true' | wc -l) -gt 1",
      refreshonly => true
    }

  }

}
require 'spec_helper'

describe 'elasticsearch', :type => 'class' do

  [ 'Debian', 'Ubuntu'].each do |distro|

    context "on #{distro} OS" do

      let :facts do {
        :operatingsystem => distro
      } end

      context 'main class tests' do

        # init.pp
        it { should contain_class('elasticsearch::package') }
        it { should contain_class('elasticsearch::config') }
        it { should contain_class('elasticsearch::service') }

      end

      context 'package installation' do
        
        context 'via repository' do

          context 'with default settings' do
            
           it { should contain_package('elasticsearch').with(:ensure => 'present') }

          end

          context 'with specified version' do

            let :params do {
              :version => '1.0'
            } end

            it { should contain_package('elasticsearch').with(:ensure => '1.0') }
          end

          context 'with auto upgrade enabled' do

            let :params do {
              :autoupgrade => true
            } end

            it { should contain_package('elasticsearch').with(:ensure => 'latest') }
          end

        end

        context 'when setting package version and package_url' do

          let :params do {
            :version     => '0.90.10',
            :package_url => 'puppet:///path/to/some/elasticsearch-0.90.10.deb'
          } end

          it { expect { should raise_error(Puppet::Error) } }

        end

        context 'via package_url setting' do

          context 'using puppet:/// schema' do

            let :params do {
              :package_url => 'puppet:///path/to/package.deb'
            } end

            it { should contain_file('/var/lib/elasticsearch/package.deb').with(:source => 'puppet:///path/to/package.deb', :backup => false) }
            it { should contain_package('elasticsearch').with(:ensure => 'present', :source => '/var/lib/elasticsearch/package.deb', :provider => 'dpkg') }
          end

          context 'using http:// schema' do

            let :params do {
              :package_url => 'http://www.domain.com/path/to/package.deb'
            } end

            it { should contain_exec('create_package_dir_elasticsearch').with(:command => 'mkdir -p /var/lib/elasticsearch') }
            it { should contain_file('/var/lib/elasticsearch').with(:purge => false, :force => false, :require => "Exec[create_package_dir_elasticsearch]") }
            it { should contain_exec('download_package_elasticsearch').with(:command => 'wget -O /var/lib/elasticsearch/package.deb http://www.domain.com/path/to/package.deb 2> /dev/null', :require => 'File[/var/lib/elasticsearch]') }
            it { should contain_package('elasticsearch').with(:ensure => 'present', :source => '/var/lib/elasticsearch/package.deb', :provider => 'dpkg') }
          end

          context 'using https:// schema' do

            let :params do {
              :package_url => 'https://www.domain.com/path/to/package.deb'
            } end

            it { should contain_exec('create_package_dir_elasticsearch').with(:command => 'mkdir -p /var/lib/elasticsearch') }
            it { should contain_file('/var/lib/elasticsearch').with(:purge => false, :force => false, :require => 'Exec[create_package_dir_elasticsearch]') }
            it { should contain_exec('download_package_elasticsearch').with(:command => 'wget -O /var/lib/elasticsearch/package.deb https://www.domain.com/path/to/package.deb 2> /dev/null', :require => 'File[/var/lib/elasticsearch]') }
            it { should contain_package('elasticsearch').with(:ensure => 'present', :source => '/var/lib/elasticsearch/package.deb', :provider => 'dpkg') }
          end

          context 'using ftp:// schema' do

            let :params do {
              :package_url => 'ftp://www.domain.com/path/to/package.deb'
            } end

            it { should contain_exec('create_package_dir_elasticsearch').with(:command => 'mkdir -p /var/lib/elasticsearch') }
            it { should contain_file('/var/lib/elasticsearch').with(:purge => false, :force => false, :require => 'Exec[create_package_dir_elasticsearch]') }
            it { should contain_exec('download_package_elasticsearch').with(:command => 'wget -O /var/lib/elasticsearch/package.deb ftp://www.domain.com/path/to/package.deb 2> /dev/null', :require => 'File[/var/lib/elasticsearch]') }
            it { should contain_package('elasticsearch').with(:ensure => 'present', :source => '/var/lib/elasticsearch/package.deb', :provider => 'dpkg') }
          end

          context 'using file:// schema' do

            let :params do {
              :package_url => 'file:/path/to/package.deb'
            } end

            it { should contain_exec('create_package_dir_elasticsearch').with(:command => 'mkdir -p /var/lib/elasticsearch') }
            it { should contain_file('/var/lib/elasticsearch').with(:purge => false, :force => false, :require => 'Exec[create_package_dir_elasticsearch]') }
            it { should contain_file('/var/lib/elasticsearch/package.deb').with(:source => '/path/to/package.deb', :backup => false) }
            it { should contain_package('elasticsearch').with(:ensure => 'present', :source => '/var/lib/elasticsearch/package.deb', :provider => 'dpkg') }
          end

        end

      end # package

      context 'service setup' do

        context 'with provider \'init\'' do

          context 'and default settings' do

            it { should contain_service('elasticsearch').with(:ensure => 'running') }

          end

          context 'and set defaults via hash param' do

            let :params do {
              :init_defaults => { 'SERVICE_USER' => 'root', 'SERVICE_GROUP' => 'root' }
            } end

            it { should contain_file('/etc/default/elasticsearch').with(:content => "### MANAGED BY PUPPET ###\n\nSERVICE_GROUP=root\nSERVICE_USER=root\n", :notify => 'Service[elasticsearch]') }

          end

          context 'and set defaults via file param' do

            let :params do {
              :init_defaults_file => 'puppet:///path/to/elasticsearch.defaults'
            } end

            it { should contain_file('/etc/default/elasticsearch').with(:source => 'puppet:///path/to/elasticsearch.defaults', :notify => 'Service[elasticsearch]') }

          end

          context 'no service restart when defaults change' do

           let :params do {
              :init_defaults     => { 'SERVICE_USER' => 'root', 'SERVICE_GROUP' => 'root' },
              :restart_on_change => false
            } end

            it { should contain_file('/etc/default/elasticsearch').with(:content => "### MANAGED BY PUPPET ###\n\nSERVICE_GROUP=root\nSERVICE_USER=root\n").without_notify }

          end 

          context 'and set init file via template' do

            let :params do {
              :init_template => "elasticsearch/etc/init.d/elasticsearch.Debian.erb"
            } end

            it { should contain_file('/etc/init.d/elasticsearch').with(:notify => 'Service[elasticsearch]') }

          end

          context 'No service restart when restart_on_change is false' do

            let :params do {
              :init_template     => "elasticsearch/etc/init.d/elasticsearch.Debian.erb",
              :restart_on_change => false
            } end

            it { should contain_file('/etc/init.d/elasticsearch').without_notify }

          end

          context 'when its unmanaged do nothing with it' do

            let :params do {
              :status => 'unmanaged'
            } end

            it { should contain_service('elasticsearch').with(:ensure => nil, :enable => false) }

          end

        end # provider init

      end # Services

      context 'when setting the module to absent' do

         let :params do {
           :ensure => 'absent'
         } end

         it { should contain_file('/etc/elasticsearch').with(:ensure => 'absent', :force => true, :recurse => true) }
         it { should contain_package('elasticsearch').with(:ensure => 'purged') }
         it { should contain_service('elasticsearch').with(:ensure => 'stopped', :enable => false) }

      end

    end

  end

end
require 'spec_helper'

describe 'elasticsearch', :type => 'class' do

  [ 'RedHat', 'CentOS', 'Fedora', 'Scientific', 'Amazon', 'OracleLinux' ].each do |distro|

    context "on #{distro} OS" do

      let :facts do {
        :operatingsystem => distro
      } end

      context 'Main class' do

        # init.pp
        it { should contain_class('elasticsearch::package') }
        it { should contain_class('elasticsearch::config') }
        it { should contain_class('elasticsearch::service') }

      end

      context 'package installation' do
        
        context 'via repository' do

          context 'with default settings' do
            
           it { should contain_package('elasticsearch').with(:ensure => 'present') }

          end

          context 'with specified version' do

            let :params do {
              :version => '1.0'
            } end

            it { should contain_package('elasticsearch').with(:ensure => '1.0') }
          end

          context 'with auto upgrade enabled' do

            let :params do {
              :autoupgrade => true
            } end

            it { should contain_package('elasticsearch').with(:ensure => 'latest') }
          end

        end

        context 'when setting package version and package_url' do

          let :params do {
            :version     => '0.90.10',
            :package_url => 'puppet:///path/to/some/elasticsearch-0.90.10.rpm'
          } end

          it { expect { should raise_error(Puppet::Error) } }

        end

        context 'via package_url setting' do

          context 'using puppet:/// schema' do

            let :params do {
              :package_url => 'puppet:///path/to/package.rpm'
            } end

            it { should contain_file('/var/lib/elasticsearch/package.rpm').with(:source => 'puppet:///path/to/package.rpm', :backup => false) }
            it { should contain_package('elasticsearch').with(:ensure => 'present', :source => '/var/lib/elasticsearch/package.rpm', :provider => 'rpm') }
          end

          context 'using http:// schema' do

            let :params do {
              :package_url => 'http://www.domain.com/path/to/package.rpm'
            } end

            it { should contain_exec('create_package_dir_elasticsearch').with(:command => 'mkdir -p /var/lib/elasticsearch') }
            it { should contain_file('/var/lib/elasticsearch').with(:purge => false, :force => false, :require => "Exec[create_package_dir_elasticsearch]") }
            it { should contain_exec('download_package_elasticsearch').with(:command => 'wget -O /var/lib/elasticsearch/package.rpm http://www.domain.com/path/to/package.rpm 2> /dev/null', :require => 'File[/var/lib/elasticsearch]') }
            it { should contain_package('elasticsearch').with(:ensure => 'present', :source => '/var/lib/elasticsearch/package.rpm', :provider => 'rpm') }
          end

          context 'using https:// schema' do

            let :params do {
              :package_url => 'https://www.domain.com/path/to/package.rpm'
            } end

            it { should contain_exec('create_package_dir_elasticsearch').with(:command => 'mkdir -p /var/lib/elasticsearch') }
            it { should contain_file('/var/lib/elasticsearch').with(:purge => false, :force => false, :require => 'Exec[create_package_dir_elasticsearch]') }
            it { should contain_exec('download_package_elasticsearch').with(:command => 'wget -O /var/lib/elasticsearch/package.rpm https://www.domain.com/path/to/package.rpm 2> /dev/null', :require => 'File[/var/lib/elasticsearch]') }
            it { should contain_package('elasticsearch').with(:ensure => 'present', :source => '/var/lib/elasticsearch/package.rpm', :provider => 'rpm') }
          end

          context 'using ftp:// schema' do

            let :params do {
              :package_url => 'ftp://www.domain.com/path/to/package.rpm'
            } end

            it { should contain_exec('create_package_dir_elasticsearch').with(:command => 'mkdir -p /var/lib/elasticsearch') }
            it { should contain_file('/var/lib/elasticsearch').with(:purge => false, :force => false, :require => 'Exec[create_package_dir_elasticsearch]') }
            it { should contain_exec('download_package_elasticsearch').with(:command => 'wget -O /var/lib/elasticsearch/package.rpm ftp://www.domain.com/path/to/package.rpm 2> /dev/null', :require => 'File[/var/lib/elasticsearch]') }
            it { should contain_package('elasticsearch').with(:ensure => 'present', :source => '/var/lib/elasticsearch/package.rpm', :provider => 'rpm') }
          end

          context 'using file:// schema' do

            let :params do {
              :package_url => 'file:/path/to/package.rpm'
            } end

            it { should contain_exec('create_package_dir_elasticsearch').with(:command => 'mkdir -p /var/lib/elasticsearch') }
            it { should contain_file('/var/lib/elasticsearch').with(:purge => false, :force => false, :require => 'Exec[create_package_dir_elasticsearch]') }
            it { should contain_file('/var/lib/elasticsearch/package.rpm').with(:source => '/path/to/package.rpm', :backup => false) }
            it { should contain_package('elasticsearch').with(:ensure => 'present', :source => '/var/lib/elasticsearch/package.rpm', :provider => 'rpm') }
          end

        end

      end # package

      context 'service setup' do

        context 'with provider \'init\'' do

          context 'and default settings' do

            it { should contain_service('elasticsearch').with(:ensure => 'running') }

          end

          context 'and set defaults via hash param' do

            let :params do {
              :init_defaults => { 'SERVICE_USER' => 'root', 'SERVICE_GROUP' => 'root' }
            } end

            it { should contain_file('/etc/sysconfig/elasticsearch').with(:content => "### MANAGED BY PUPPET ###\n\nSERVICE_GROUP=root\nSERVICE_USER=root\n", :notify => 'Service[elasticsearch]') }

          end

          context 'and set defaults via file param' do

            let :params do {
              :init_defaults_file => 'puppet:///path/to/elasticsearch.defaults'
            } end

            it { should contain_file('/etc/sysconfig/elasticsearch').with(:source => 'puppet:///path/to/elasticsearch.defaults', :notify => 'Service[elasticsearch]') }

          end

          context 'no service restart when defaults change' do

            let :params do {
              :init_defaults     => { 'SERVICE_USER' => 'root', 'SERVICE_GROUP' => 'root' },
              :restart_on_change => false
            } end

            it { should contain_file('/etc/sysconfig/elasticsearch').with(:content => "### MANAGED BY PUPPET ###\n\nSERVICE_GROUP=root\nSERVICE_USER=root\n").without_notify }

          end

          context 'and set init file via template' do

            let :params do {
              :init_template => "elasticsearch/etc/init.d/elasticsearch.RedHat.erb"
            } end

            it { should contain_file('/etc/init.d/elasticsearch').with(:notify => 'Service[elasticsearch]') }

          end

          context 'No service restart when restart_on_change is false' do

            let :params do {
              :init_template     => "elasticsearch/etc/init.d/elasticsearch.RedHat.erb",
              :restart_on_change => false
            } end

            it { should contain_file('/etc/init.d/elasticsearch').without_notify }

          end

          context 'when its unmanaged do nothing with it' do

            let :params do {
              :status => 'unmanaged'
            } end

            it { should contain_service('elasticsearch').with(:ensure => nil, :enable => false) }

          end

        end

      end # Services

      context 'when setting the module to absent' do

         let :params do {
           :ensure => 'absent'
         } end

         it { should contain_file('/etc/elasticsearch').with(:ensure => 'absent', :force => true, :recurse => true) }
         it { should contain_package('elasticsearch').with(:ensure => 'purged') }
         it { should contain_service('elasticsearch').with(:ensure => 'stopped', :enable => false) }

      end

    end

  end

end
require 'spec_helper'

describe 'elasticsearch', :type => 'class' do

  context "on an unknown OS" do

    context "it should fail" do
      let :facts do {
        :operatingsystem => 'Windows'
      } end
 
      it { expect { should raise_error(Puppet::Error) } }

    end

  end
 
end
require 'spec_helper'

describe 'elasticsearch', :type => 'class' do

  let :facts do {
    :operatingsystem => 'CentOS'
  } end

  context "config file content" do

    context "with nothing set" do

      let :params do {
      } end

      it { should contain_file('/etc/elasticsearch/elasticsearch.yml').with(:content => "### MANAGED BY PUPPET ###\n") }

    end

    context "set a value" do

      let :params do {
        :config => { 'node' => { 'name' => 'test' }  }
      } end

      it { should contain_file('/etc/elasticsearch/elasticsearch.yml').with(:content => "### MANAGED BY PUPPET ###\n---\nnode: \n  name: test\n") }

    end

    context "set a value to true" do

      let :params do {
        :config => { 'node' => { 'master' => true }  }
      } end

      it { should contain_file('/etc/elasticsearch/elasticsearch.yml').with(:content => "### MANAGED BY PUPPET ###\n---\nnode: \n  master: true\n") }

    end

    context "set a value to false" do

      let :params do {
        :config => { 'node' => { 'data' => false }  }
      } end

      it { should contain_file('/etc/elasticsearch/elasticsearch.yml').with(:content => "### MANAGED BY PUPPET ###\n---\nnode: \n  data: false\n") }

    end

    context "deeper hash and multiple keys" do

      let :params do {
        :config => { 'index' => { 'routing' => { 'allocation' => { 'include' => 'tag1', 'exclude' => [ 'tag2', 'tag3' ] } } }, 'node' => { 'name' => 'somename' } }
      } end

      it { should contain_file('/etc/elasticsearch/elasticsearch.yml').with(:content => "### MANAGED BY PUPPET ###\n---\nindex: \n  routing: \n    allocation: \n      exclude: \n             - tag2\n             - tag3\n      include: tag1\nnode: \n  name: somename\n") }

    end

    context "Combination of full hash and shorted write up keys" do

      let :params do {
        :config => { 'node' => { 'name' => 'NodeName', 'rack' => 46 }, 'boostrap.mlockall' => true, 'cluster' => { 'name' => 'ClusterName', 'routing.allocation.awareness.attributes' => 'rack' }, 'discovery.zen' => { 'ping.unicast.hosts'=> [ "host1", "host2" ], 'minimum_master_nodes' => 3, 'ping.multicast.enabled' => false }, 'gateway' => { 'expected_nodes' => 4, 'recover_after_nodes' => 3 }, 'network.host' => '123.123.123.123' }
       } end

       it { should contain_file('/etc/elasticsearch/elasticsearch.yml').with(:content => "### MANAGED BY PUPPET ###\n---\nboostrap: \n  mlockall: true\ncluster: \n  name: ClusterName\n  routing: \n    allocation: \n      awareness: \n        attributes: rack\ndiscovery: \n  zen: \n    minimum_master_nodes: 3\n    ping: \n      multicast: \n        enabled: false\n      unicast: \n        hosts: \n             - host1\n             - host2\ngateway: \n  expected_nodes: 4\n  recover_after_nodes: 3\nnetwork: \n  host: 123.123.123.123\nnode: \n  name: NodeName\n  rack: 46\n") }

     end

  end

  context "service restarts" do

   let :facts do {
     :operatingsystem => 'CentOS'
    } end

    context "does not restart when restart_on_change is false" do
      let :params do {
        :config            => { 'node' => { 'name' => 'test' }  },
        :restart_on_change => false,
      } end

      it { should contain_file('/etc/elasticsearch/elasticsearch.yml').without_notify }
    end

    context "should happen restart_on_change is true (default)" do
      let :params do {
        :config            => { 'node' => { 'name' => 'test' }  },
        :restart_on_change => true,
      } end

      it { should contain_file('/etc/elasticsearch/elasticsearch.yml').with(:notify => "Class[Elasticsearch::Service]") }
    end

  end

  context 'data directory' do
    let(:facts) do {
      :operatingsystem => 'CentOS'
    } end

    context 'should allow creating datadir' do
      let(:params) do {
        :datadir => '/foo'
      } end

      it { should contain_file('/foo').with(:ensure => 'directory') }
    end

  end
end
require 'spec_helper'

describe 'elasticsearch', :type => 'class' do

  context "install java" do

    let :params do {
      :java_install => true,
      :config => { 'node' => { 'name' => 'test' }  }
    } end

    context "On Debian OS" do

      let :facts do {
        :operatingsystem => 'Debian'
      } end

      it { should contain_package('openjdk-7-jre-headless') }

    end

    context "On Ubuntu OS" do

      let :facts do {
        :operatingsystem => 'Ubuntu'
      } end

      it { should contain_package('openjdk-7-jre-headless') }

    end

    context "On CentOS OS " do

      let :facts do {
        :operatingsystem => 'CentOS'
      } end

      it { should contain_package('java-1.7.0-openjdk') }

    end

    context "On RedHat OS " do

      let :facts do {
        :operatingsystem => 'Redhat'
      } end

      it { should contain_package('java-1.7.0-openjdk') }

    end

    context "On Fedora OS " do

      let :facts do {
        :operatingsystem => 'Fedora'
      } end

      it { should contain_package('java-1.7.0-openjdk') }

    end

    context "On Scientific OS " do

      let :facts do {
        :operatingsystem => 'Scientific'
      } end

      it { should contain_package('java-1.7.0-openjdk') }

    end

    context "On Amazon OS " do

      let :facts do {
        :operatingsystem => 'Amazon'
      } end

      it { should contain_package('java-1.7.0-openjdk') }

    end

    context "On OracleLinux OS " do

      let :facts do {
        :operatingsystem => 'OracleLinux'
      } end

      it { should contain_package('java-1.7.0-openjdk') }

    end

    context "On an unknown OS" do

      let :facts do {
        :operatingsystem => 'Windows'
      } end

      it { expect { should raise_error(Puppet::Error) } }

    end

    context "Custom java package" do

      let :facts do {
        :operatingsystem => 'CentOS'
      } end

      let :params do {
        :java_install => true,
        :java_package => 'java-1.6.0-openjdk',
        :config => { 'node' => { 'name' => 'test' }  }
      } end

      it { should contain_package('java-1.6.0-openjdk') }

    end

  end

end
require 'spec_helper'

describe 'elasticsearch::python', :type => 'define' do

  let(:facts) { {:operatingsystem => 'CentOS' }}

  [ 'pyes', 'rawes', 'pyelasticsearch', 'ESClient', 'elasticutils', 'elasticsearch' ].each do |pythonlib|

    context "installation of library #{pythonlib}" do

      let(:title) { pythonlib }

      it { should contain_package(pythonlib).with(:provider => 'pip') }

    end

  end

end
require 'spec_helper'

describe 'elasticsearch::ruby', :type => 'define' do

  let(:facts) { {:operatingsystem => 'CentOS' }}

  [ 'tire', 'stretcher', 'elastic_searchable', 'elasticsearch'].each do |rubylib|

    context "installation of library #{rubylib}" do

      let(:title) { rubylib }

      it { should contain_package(rubylib).with(:provider => 'gem') }

    end

  end

end
require 'spec_helper'

describe 'elasticsearch::template', :type => 'define' do

  let(:title) { 'foo' }
  let(:facts) { {:operatingsystem => 'CentOS' }}
  let(:pre_condition) { 'class {"elasticsearch": config => { "node" => {"name" => "test" }}}'}

  context "Add a template" do

    let :params do {
      :ensure => 'present',
      :file   => 'puppet:///path/to/foo.json',
    } end

    it { should contain_file('/etc/elasticsearch/templates_import/elasticsearch-template-foo.json').with(:source => 'puppet:///path/to/foo.json', :notify => "Exec[delete_template_foo]", :require => "Exec[mkdir_templates]") }
    it { should contain_exec('insert_template_foo').with(:command => 'curl -s -XPUT http://localhost:9200/_template/foo -d @/etc/elasticsearch/templates_import/elasticsearch-template-foo.json', :unless => 'test $(curl -s \'http://localhost:9200/_template/foo?pretty=true\' | wc -l) -gt 1') }
  end

  context "Delete a template" do

    let :params do {
      :ensure => 'absent'
    } end

    it { should_not contain_file('/etc/elasticsearch/templates_import/elasticsearch-template-foo.json').with(:source => 'puppet:///path/to/foo.json') }
    it { should_not contain_exec('insert_template_foo') }
    it { should contain_exec('delete_template_foo').with(:command => 'curl -s -XDELETE http://localhost:9200/_template/foo', :notify => nil, :onlyif => 'test $(curl -s \'http://localhost:9200/_template/foo?pretty=true\' | wc -l) -gt 1' ) }
  end

  context "Add template with alternative host and port" do

    let :params do {
      :file => 'puppet:///path/to/foo.json',
      :host => 'otherhost',
      :port => '9201'
    } end

    it { should contain_file('/etc/elasticsearch/templates_import/elasticsearch-template-foo.json').with(:source => 'puppet:///path/to/foo.json') }
    it { should contain_exec('insert_template_foo').with(:command => 'curl -s -XPUT http://otherhost:9201/_template/foo -d @/etc/elasticsearch/templates_import/elasticsearch-template-foo.json', :unless => 'test $(curl -s \'http://otherhost:9201/_template/foo?pretty=true\' | wc -l) -gt 1') }
  end

end
require 'spec_helper'

describe 'elasticsearch::plugin', :type => 'define' do

  let(:title) { 'mobz/elasticsearch-head' }
  let(:facts) { {:operatingsystem => 'CentOS' }}
  let(:pre_condition) { 'class {"elasticsearch": config => { "node" => {"name" => "test" }}}'}

  context "Add a plugin" do

    let :params do {
      :ensure     => 'present',
      :module_dir => 'head',
    } end

    it { should contain_exec('install_plugin_mobz/elasticsearch-head').with(:command => '/usr/share/elasticsearch/bin/plugin -install mobz/elasticsearch-head', :creates => '/usr/share/elasticsearch/plugins/head') }
  end

  context "Remove a plugin" do

    let :params do {
      :ensure     => 'absent',
      :module_dir => 'head'
    } end

    it { should contain_exec('remove_plugin_mobz/elasticsearch-head').with(:command => '/usr/share/elasticsearch/bin/plugin --remove head', :onlyif => 'test -d /usr/share/elasticsearch/plugins/head') }
  end

end
require 'find'
require 'pathname'
require 'rake'
require 'rspec/core/rake_task'

desc "run Puppet parser validate"
task :parser_validate do

  pwd = ENV["PWD"]
  puppet_file_paths = []
  Find.find(pwd) do |path|
    puppet_file_paths << path if path =~ /.*\.pp$/
  end

  exit_code = 0
  puppet_file_paths.each do |puppetfile|

    pwdpath = Pathname.new(pwd)
    pn = Pathname.new(puppetfile)
    rel_path = pn.relative_path_from(pwdpath)

    print "Validating #{rel_path}....  "
    $stdout.flush

    result = `puppet parser validate #{puppetfile}`
    if $?.exitstatus == 0
      res = 'OK'
    else
      res = 'ERR'
    end

    puts "#{res}"

    if $?.exitstatus != 0
      exit_code = 1
    end
  end
  exit exit_code

end
require 'find'
require 'pathname'
require 'rake'
require 'rspec/core/rake_task'

desc "Verify puppet templates"
task :template_verify do

  pwd = ENV["PWD"]
  erb_file_paths = []
  Find.find(pwd) do |path|
    erb_file_paths << path if path =~ /.*\.erb$/
  end

  exit_code = 0
  erb_file_paths.each do |erbfile|

    pwdpath = Pathname.new(pwd)
    pn = Pathname.new(erbfile)
    rel_path = pn.relative_path_from(pwdpath)

    result = `erb -P -x -T '-' #{erbfile} | ruby -c`
    puts "Verifying #{rel_path}.... #{result}"

    if $?.exitstatus != 0
      exit_code = 1
    end
  end
  exit exit_code

end
require 'rubygems'
require 'puppetlabs_spec_helper/module_spec_helper'
<%-

  # Function to make a structured and sorted yaml representation out of a hash
  def recursive_hash_to_yml_string(hash, depth=0)
    spacer = ""
    depth.times { spacer += "  "}
    hash.keys.sort.each do |sorted_key|
      @yml_string += spacer + sorted_key + ": "
      if hash[sorted_key].is_a?(Array)
         keyspacer = ""
         sorted_key.length.times { keyspacer += " " }
         @yml_string += "\n"
         hash[sorted_key].each do |item|
           @yml_string += spacer + keyspacer + "- " + item +"\n"
         end
      elsif hash[sorted_key].is_a?(Hash)
        @yml_string += "\n"
        recursive_hash_to_yml_string(hash[sorted_key], depth+1)
      else
        @yml_string += "#{hash[sorted_key].to_s}\n"
      end
    end
  end

  # Function to transform shorted write up of the keys into full hash representation
  def transform(hash)
  return_vals = []

  hash.each do |key,val|
    if m = /^([^.]+)\.(.*)$/.match(key)
      temp = { m[1] => { m[2] => val } }
      transform(temp).each do |stuff|
        return_vals << stuff
      end
    else
      if val.is_a?(Hash)
        transform(val).each do |stuff|
          return_vals << { key => stuff }
        end
      else
        return_vals << { key => val }
      end
    end
  end

  return_vals
  end

  # Function to deep merge hashes with same keys
  class ::Hash
    def deep_merge_with_array_values_concatenated(hash)
    target = dup

    hash.keys.each do |key|
      if hash[key].is_a? Hash and self[key].is_a? Hash
        target[key] = target[key].deep_merge_with_array_values_concatenated(hash[key])
        next
      end

      if hash[key].is_a?(Array) && target[key].is_a?(Array)
        target[key] = target[key] + hash[key]
      else
        target[key] = hash[key]
      end
    end

    target
    end
  end

  # initial string
  @yml_string = "### MANAGED BY PUPPET ###\n"

  if !scope.lookupvar('elasticsearch::config').empty?

    @yml_string += "---\n"

    ## Transform shorted keys into full write up
    transformed_config = transform(scope.lookupvar('elasticsearch::config'))

    # Merge it back into a hash
    tmphash = { }
    transformed_config.each do |subhash|
      tmphash = tmphash.deep_merge_with_array_values_concatenated(subhash)
    end

    # Transform it into yaml
    recursive_hash_to_yml_string(tmphash)

  end

-%>
<%= @yml_string -%>
#!/bin/sh
#
# /etc/init.d/elasticsearch -- startup script for Elasticsearch
#
# Written by Miquel van Smoorenburg <miquels@cistron.nl>.
# Modified for Debian GNU/Linux	by Ian Murdock <imurdock@gnu.ai.mit.edu>.
# Modified for Tomcat by Stefan Gybas <sgybas@debian.org>.
# Modified for Tomcat6 by Thierry Carrez <thierry.carrez@ubuntu.com>.
# Additional improvements by Jason Brittain <jason.brittain@mulesoft.com>.
# Modified by Nicolas Huray for ElasticSearch <nicolas.huray@gmail.com>.
#
### BEGIN INIT INFO
# Provides:          elasticsearch
# Required-Start:    $network $remote_fs $named
# Required-Stop:     $network $remote_fs $named
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Starts elasticsearch
# Description:       Starts elasticsearch using start-stop-daemon
### END INIT INFO

PATH=/bin:/usr/bin:/sbin:/usr/sbin
NAME=elasticsearch
DESC="ElasticSearch Server"
DEFAULT=/etc/default/$NAME

if [ `id -u` -ne 0 ]; then
	echo "You need root privileges to run this script"
	exit 1
fi


. /lib/lsb/init-functions

if [ -r /etc/default/rcS ]; then
	. /etc/default/rcS
fi


# The following variables can be overwritten in $DEFAULT

# Run ElasticSearch as this user ID and group ID
ES_USER=elasticsearch
ES_GROUP=elasticsearch

# The first existing directory is used for JAVA_HOME (if JAVA_HOME is not defined in $DEFAULT)
JDK_DIRS="/usr/lib/jvm/java-7-oracle /usr/lib/jvm/java-7-openjdk /usr/lib/jvm/java-7-openjdk-amd64/ /usr/lib/jvm/java-7-openjdk-armhf /usr/lib/jvm/java-7-openjdk-i386/ /usr/lib/jvm/java-6-sun /usr/lib/jvm/java-6-openjdk /usr/lib/jvm/java-6-openjdk-amd64 /usr/lib/jvm/java-6-openjdk-armhf /usr/lib/jvm/java-6-openjdk-i386 /usr/lib/jvm/default-java"

# Look for the right JVM to use
for jdir in $JDK_DIRS; do
    if [ -r "$jdir/bin/java" -a -z "${JAVA_HOME}" ]; then
        JAVA_HOME="$jdir"
    fi
done
export JAVA_HOME

# Directory where the ElasticSearch binary distribution resides
ES_HOME=/usr/share/$NAME

# Heap Size (defaults to 256m min, 1g max)
#ES_HEAP_SIZE=2g

# Heap new generation
#ES_HEAP_NEWSIZE=

# max direct memory
#ES_DIRECT_SIZE=

# Additional Java OPTS
#ES_JAVA_OPTS=

# Maximum number of open files
MAX_OPEN_FILES=65535

# Maximum amount of locked memory
#MAX_LOCKED_MEMORY=

# ElasticSearch log directory
LOG_DIR=/var/log/$NAME

# ElasticSearch data directory
DATA_DIR=/var/lib/$NAME

# ElasticSearch work directory
WORK_DIR=/tmp/$NAME

# ElasticSearch configuration directory
CONF_DIR=/etc/$NAME

# ElasticSearch configuration file (elasticsearch.yml)
CONF_FILE=$CONF_DIR/elasticsearch.yml

# End of variables that can be overwritten in $DEFAULT

# overwrite settings from default file
if [ -f "$DEFAULT" ]; then
	. "$DEFAULT"
fi

# Define other required variables
PID_FILE=/var/run/$NAME.pid
DAEMON=$ES_HOME/bin/elasticsearch
DAEMON_OPTS="-p $PID_FILE -Des.default.config=$CONF_FILE -Des.default.path.home=$ES_HOME -Des.default.path.logs=$LOG_DIR -Des.default.path.data=$DATA_DIR -Des.default.path.work=$WORK_DIR -Des.default.path.conf=$CONF_DIR"

export ES_HEAP_SIZE
export ES_HEAP_NEWSIZE
export ES_DIRECT_SIZE
export ES_JAVA_OPTS

# Check DAEMON exists
test -x $DAEMON || exit 0

checkJava() {
	if [ -x "$JAVA_HOME/bin/java" ]; then
		JAVA="$JAVA_HOME/bin/java"
	else
		JAVA=`which java`
	fi

	if [ ! -x "$JAVA" ]; then
		echo "Could not find any executable java binary. Please install java in your PATH or set JAVA_HOME"
		exit 1
	fi
}

case "$1" in
  start)
	checkJava

	if [ -n "$MAX_LOCKED_MEMORY" -a -z "$ES_HEAP_SIZE" ]; then
		log_failure_msg "MAX_LOCKED_MEMORY is set - ES_HEAP_SIZE must also be set"
		exit 1
	fi

	log_daemon_msg "Starting $DESC"

	pid=`pidofproc -p $PID_FILE elasticsearch`
	if [ -n "$pid" ] ; then
		log_begin_msg "Already running."
		log_end_msg 0
		exit 0
	fi

	# Prepare environment
	mkdir -p "$LOG_DIR" "$DATA_DIR" "$WORK_DIR" && chown "$ES_USER":"$ES_GROUP" "$LOG_DIR" "$DATA_DIR" "$WORK_DIR"
	touch "$PID_FILE" && chown "$ES_USER":"$ES_GROUP" "$PID_FILE"

	if [ -n "$MAX_OPEN_FILES" ]; then
		ulimit -n $MAX_OPEN_FILES
	fi

	if [ -n "$MAX_LOCKED_MEMORY" ]; then
		ulimit -l $MAX_LOCKED_MEMORY
	fi

	# Start Daemon
	start-stop-daemon --start -b --user "$ES_USER" -c "$ES_USER" --pidfile "$PID_FILE" --exec $DAEMON -- $DAEMON_OPTS
	log_end_msg $?
	;;		
  stop)
	log_daemon_msg "Stopping $DESC"

	if [ -f "$PID_FILE" ]; then 
		start-stop-daemon --stop --pidfile "$PID_FILE" \
			--user "$ES_USER" \
			--retry=TERM/20/KILL/5 >/dev/null
		if [ $? -eq 1 ]; then
			log_progress_msg "$DESC is not running but pid file exists, cleaning up"
		elif [ $? -eq 3 ]; then
			PID="`cat $PID_FILE`"
			log_failure_msg "Failed to stop $DESC (pid $PID)"
			exit 1
		fi
		rm -f "$PID_FILE"
	else
		log_progress_msg "(not running)"
	fi
	log_end_msg 0
	;;
  status)
	status_of_proc -p $PID_FILE elasticsearch elasticsearch && exit 0 || exit $?
    ;;
  restart|force-reload)
	if [ -f "$PID_FILE" ]; then
		$0 stop
		sleep 1
	fi
	$0 start
	;;
  *)
	log_success_msg "Usage: $0 {start|stop|restart|force-reload|status}"
	exit 1
	;;
esac

exit 0
#!/bin/sh
#
# elasticsearch <summary>
#
# chkconfig:   2345 80 20
# description: Starts and stops a single elasticsearch instance on this system 
#

### BEGIN INIT INFO
# Provides: Elasticsearch
# Required-Start: $network $named
# Required-Stop: $network $named
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: This service manages the elasticsearch daemon
# Description: Elasticsearch is a very scalable, schema-free and high-performance search solution supporting multi-tenancy and near realtime search.
### END INIT INFO

#
# init.d / servicectl compatibility (openSUSE)
#
if [ -f /etc/rc.status ]; then
    . /etc/rc.status
    rc_reset
fi

#
# Source function library.
#
if [ -f /etc/rc.d/init.d/functions ]; then
    . /etc/rc.d/init.d/functions
fi

exec="/usr/share/elasticsearch/bin/elasticsearch"
prog="elasticsearch"
pidfile=/var/run/elasticsearch/${prog}.pid

[ -e /etc/sysconfig/$prog ] && . /etc/sysconfig/$prog

export ES_HEAP_SIZE
export ES_HEAP_NEWSIZE
export ES_DIRECT_SIZE
export ES_JAVA_OPTS

lockfile=/var/lock/subsys/$prog

# backwards compatibility for old config sysconfig files, pre 0.90.1
if [ -n $USER ] && [ -z $ES_USER ] ; then 
   ES_USER=$USER
fi

checkJava() {
    if [ -x "$JAVA_HOME/bin/java" ]; then
        JAVA="$JAVA_HOME/bin/java"
    else
        JAVA=$(which java)
    fi

    if [ ! -x "$JAVA" ]; then
        echo "Could not find any executable java binary. Please install java in your PATH or set JAVA_HOME"
        exit 1
    fi
}

start() {
    checkJava
    [ -x $exec ] || exit 5
    [ -f $CONF_FILE ] || exit 6
    if [ -n "$MAX_LOCKED_MEMORY" -a -z "$ES_HEAP_SIZE" ]; then
        echo "MAX_LOCKED_MEMORY is set - ES_HEAP_SIZE must also be set"
        return 7
    fi
    if [ -n "$MAX_OPEN_FILES" ]; then
        ulimit -n $MAX_OPEN_FILES
    fi
    if [ -n "$MAX_LOCKED_MEMORY" ]; then
        ulimit -l $MAX_LOCKED_MEMORY
    fi
    if [ -n "$WORK_DIR" ]; then
        mkdir -p "$WORK_DIR"
        chown "$ES_USER":"$ES_GROUP" "$WORK_DIR"
    fi
    echo -n $"Starting $prog: "
    # if not running, start it up here, usually something like "daemon $exec"
    daemon --user $ES_USER --pidfile $pidfile $exec -p $pidfile -Des.default.path.home=$ES_HOME -Des.default.path.logs=$LOG_DIR -Des.default.path.data=$DATA_DIR -Des.default.path.work=$WORK_DIR -Des.default.path.conf=$CONF_DIR
    retval=$?
    echo
    [ $retval -eq 0 ] && touch $lockfile
    return $retval
}

stop() {
    echo -n $"Stopping $prog: "
    # stop it here, often "killproc $prog"
    killproc -p $pidfile $prog
    retval=$?
    echo
    [ $retval -eq 0 ] && rm -f $lockfile
    return $retval
}

restart() {
    stop
    start
}

reload() {
    restart
}

force_reload() {
    restart
}

rh_status() {
    # run checks to determine if the service is running or use generic status
    status -p $pidfile $prog
}

rh_status_q() {
    rh_status >/dev/null 2>&1
}


case "$1" in
    start)
        rh_status_q && exit 0
        $1
        ;;
    stop)
        rh_status_q || exit 0
        $1
        ;;
    restart)
        $1
        ;;
    reload)
        rh_status_q || exit 7
        $1
        ;;
    force-reload)
        force_reload
        ;;
    status)
        rh_status
        ;;
    condrestart|try-restart)
        rh_status_q || exit 0
        restart
        ;;
    *)
        echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload}"
        exit 2
esac
exit $?
### MANAGED BY PUPPET ###

<% scope.lookupvar('elasticsearch::init_defaults').sort.map do |key, value| -%>
<%= key %>=<%= value %>
<% end -%>
source 'https://rubygems.org'

group :development, :test do
  gem 'rake', :require => false
  gem 'rspec-puppet', :require => false
  gem 'puppetlabs_spec_helper', :require => false
  gem 'puppet-lint', :require => false
  gem 'rspec-system-puppet', '~>2.0.0'
end

if puppetversion = ENV['PUPPET_GEM_VERSION']
  gem 'puppet', puppetversion, :require => false
else
  gem 'puppet', :require => false
end
Copyright 2012-2014 Michael Stahnke

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
# Configure EPEL (Extra Repository for Enterprise Linux)

# About
This module basically just mimics the epel-release rpm. The same repos are
enabled/disabled and the GPG key is imported.  In the end you will end up with
the EPEL repos configured.

The following Repos will be setup and enabled by default:

  * epel

Other repositories that will setup but disabled (as per the epel-release setup)

  * epel-debuginfo
  * epel-source
  * epel-testing
  * epel-testing-debuginfo
  * epel-testing-source

# Proxy
If you have an http proxy required to access the internet, you can use either
a class parameter in the _epel_ class, or edit the $proxy variable in the
params.pp file. By default no proxy is assumed.

# Why?
I am a big fan of EPEL. I actually was one of the people who helped get it
going. I am also the owner of the epel-release package, so in general this
module should stay fairly up to date with the official upstream package.

I just got sick of coding Puppet modules and basically having an assumption
that EPEL was setup or installed.  I can now depend on this module instead.

I realize it is fairly trivial to get EPEL setup. Every now-and-then however
the path to epel-release changes because something changes in the package (mass
rebuild, rpm build macros updates, etc).  This  module will bypass the changing
URL and just setup the package mirrors.

This does mean that if you are looking for RPM macros that are normally
included with EPEL release, this will not have them.

# Futher Information

* [EPEL Wiki](http://fedoraproject.org/wiki/EPEL)
* [epel-release package information](http://mirrors.servercentral.net/fedora/epel/6/i386/repoview/epel-release.html)

# ChangeLog

  * Ready for 1.0 - replace Modulefile with metadata.json
  * Replace os_maj_version custom fact with operatingsystemmajrelease
  * Works for EPEL7 now as well.

# Testing

  * This is commonly used on Puppet Enterprise 3.x
  * This was tested using Puppet 3.3.0 on Centos5/6
  * This was tested using Puppet 3.1.1 on Amazon's AWS Linux
  * I assume it will work on any RHEL variant (Amazon Linux is debatable as a variant)
  * Amazon Linux compatability not promised, as EPEL doesn't always work with it.

# Lifecycle

  * No functionality has been introduced that should break Puppet 2.6 or 2.7, but I am no longer testing these versions of Puppet as they are end-of-lifed from Puppet Labs.
  * This also assumes a facter of greater than 1.7.0 -- at least from a testing perspective.

## Unit tests

Install the necessary gems

    bundle install

Run the RSpec and puppet-lint tests

    bundle exec rake ci

## System tests

If you have Vagrant >=1.1.0 you can also run system tests:

    RSPEC_SET=centos-64-x64 bundle exec rake spec:system

Available RSPEC_SET options are in .nodeset.yml

# License
Apache Software License 2.0

# Author/Contributors
  *  Aaron <slapula@users.noreply.github.com>
  *  Chad Metcalf <metcalfc@gmail.com>
  *  Ewoud Kohl van Wijngaarden <e.kohlvanwijngaarden@oxilion.nl>
  *  Joseph Swick <joseph.swick@meltwater.com>
  *  Matthaus Owens <mlitteken@gmail.com>
  *  Michael Stahnke <stahnma@puppetlabs.com>
  *  Michael Stahnke <stahnma@websages.com>
  *  Pro Cabales <proletaryo@gmail.com>
  *  Proletaryo Cabales <proletaryo@gmail.com>
  *  Stefan Goethals <stefan@zipkid.eu>
  *  Tim Rupp <caphrim007@gmail.com>
  *  Trey Dockendorf <treydock@gmail.com>
  *  Troy Bollinger <troy@us.ibm.com>
  *  Vlastimil Holer <holer@ics.muni.cz>
require 'puppetlabs_spec_helper/rake_tasks'
require 'puppet-lint/tasks/puppet-lint'
require 'rspec-system/rake_task'

task :default do
  sh %{rake -T}
end

# Disable specific puppet-lint checks
PuppetLint.configuration.send("disable_80chars")
PuppetLint.configuration.send("disable_class_inherits_from_params_class")

desc "Run rspec-puppet and puppet-lint tasks"
task :ci => [
  :lint,
  :spec,
]
{
  "Gemfile": "3189476f30a99858b367d955298fe469",
  "LICENSE": "94f0b1430ad7e59227ccabf8232f81d5",
  "README.md": "3f68d955de863c2b8cc31f0604074ac8",
  "Rakefile": "946eced163d7f8e0da85bda4baa7fa9c",
  "files/RPM-GPG-KEY-EPEL-5": "0466c259781def56dafe0a2cdc9de0c5",
  "files/RPM-GPG-KEY-EPEL-6": "d865e6b948a74cb03bc3401c0b01b785",
  "files/RPM-GPG-KEY-EPEL-7": "58fa8ae27c89f37b08429f04fd4a88cc",
  "manifests/init.pp": "e4b0eeea343e24057be5ac64b8417565",
  "manifests/params.pp": "f8fc69180399ffcbbf560131ffe6da7f",
  "manifests/rpm_gpg_key.pp": "69086f12752a14b200e462afaa59a93c",
  "metadata.json": "2c52fcd3a96a8d7df65feaa11ba3756f",
  "spec/classes/epel_spec.rb": "ab5b17fd76105206a508bbb01ff3b6bc",
  "spec/classes/shared_base.rb": "a6a46eb7225a1814b9343f32190ba75b",
  "spec/classes/shared_debuginfo.rb": "1bd23934bc1f7d14d2491c7741f10299",
  "spec/classes/shared_gpgkey.rb": "38a62fe24acfc9cc8d740d242c9f1c85",
  "spec/classes/shared_source.rb": "6581989ed1ca2edd589ed98ecb08bdfa",
  "spec/classes/shared_testing.rb": "50e936b9cf241c9849cf551961492532",
  "spec/classes/shared_testing_debuginfo.rb": "41e8a2215d347246ff241f1b3a819c91",
  "spec/classes/shared_testing_source.rb": "8cd827b2cb0b08b1633d70784417f946",
  "spec/defines/rpm_gpg_key_spec.rb": "ea1ec4f7098ac240907c305107dc683f",
  "spec/spec_helper.rb": "a5ad64bd67aa3fe2512fa7ba505c8e8b",
  "spec/spec_helper_system.rb": "d24a7ffdf4b67dbbd3ef5687292f51cf",
  "spec/system/basic_spec.rb": "49db07e43f690ac32a841b3125939450",
  "spec/system/usage_spec.rb": "68f7bd38e911009d74487c5f86b48555",
  "tests/init.pp": "7c69b7adf2ba141cb62cfc9e0704d59e"
}
Version: GnuPG v1.2.6 (GNU/Linux)

mQGiBEXopTIRBACZDBMOoFOakAjaxw1LXjeSvh/kmE35fU1rXfM7T0AV31NATCLF
l5CQiNDA4oWreDThg2Bf6+LIVTsGQb1V+XXuLak4Em5yTYwMTVB//4/nMxQEbpl/
QB2XwlJ7EQ0vW+kiPDz/7pHJz1p1jADzd9sQQicMtzysS4qT2i5A23j0VwCg1PB/
lpYqo0ZhWTrevxKMa1n34FcD/REavj0hSLQFTaKNLHRotRTF8V0BajjSaTkUT4uk
/RTaZ8Kr1mTosVtosqmdIAA2XHxi8ZLiVPPSezJjfElsSqOAxEKPL0djfpp2wrTm
l/1iVnX+PZH5DRKCbjdCMLDJhYap7YUhcPsMGSeUKrwmBCBJUPc6DhjFvyhA9IMl
1T0+A/9SKTv94ToP/JYoCTHTgnG5MoVNafisfe0wojP2mWU4gRk8X4dNGKMj6lic
vM6gne3hESyjcqZSmr7yELPPGhI9MNauJ6Ob8cTR2T12Fmv9w03DD3MnBstR6vhP
QcqZKhc5SJYYY7oVfxlSOfF4xfwcHQKoD5TOKwIAQ6T8jyFpKbQkRmVkb3JhIEVQ
RUwgPGVwZWxAZmVkb3JhcHJvamVjdC5vcmc+iGQEExECACQFAkXopTICGwMFCRLM
AwAGCwkIBwMCAxUCAwMWAgECHgECF4AACgkQEZzANiF1IfabmQCgzvE60MnHSOBa
ZXXF7uU2Vzu8EOkAoKg9h+j0NuNom6WUYZyJQt4zc5seuQINBEXopTYQCADapnR/
blrJ8FhlgNPl0X9S3JE/kygPbNXIqne4XBVYisVp0uzNCRUxNZq30MpY027JCs2J
nL2fMpwvx33f0phU029vrIZKA3CmnnwVsjcWfMJOVPBmVN7m5bGU68F+PdRIcDsl
PMOWRLkTBZOGolLgIbM4719fqA8etewILrX6uPvRDwywV7/sPCFpRcfNNBUY+Zx3
5bf4fnkaCKxgXgQS3AT+hGYhlzIqQVTkGNveHTnt4SSzgAqR9sSwQwqvEfVtYNeS
w5rDguLG41HQm1Hojv59HNYjH6F/S1rClZi21bLgZbKpCFX76qPt8CTw+iQLBPPd
yoOGHfzyp7nsfhUrAAMFB/9/H9Gpk822ZpBexQW4y3LGFo9ZSnmu+ueOZPU3SqDA
DW1ovZdYzGuJTGGM9oMl6bL8eZrcUBBOFaWge5wZczIE3hx2exEOkDdvq+MUDVD1
axmN45q/7h1NYRp5GQL2ZsoV4g9U2gMdzHOFtZCER6PP9ErVlfJpgBUCdSL93V4H
Sgpkk7znmTOklbCM6l/G/A6q4sCRqfzHwVSTiruyTBiU9lfROsAl8fjIq2OzWJ2T
P9sadBe1llUYaow7txYSUxssW+89avct35gIyrBbof5M+CBXyAOUaSWmpM2eub24
0qbqiSr/Y6Om0t6vSzR8gRk7g+1H6IE0Tt1IJCvCAMimiE8EGBECAA8FAkXopTYC
GwwFCRLMAwAACgkQEZzANiF1IfZQYgCgiZHCv4xb+sTHCn/otc1Ovvi/OgMAnRXY
bbsLFWOfmzAnNIGvFRWy+YHi
=MMNL
Version: GnuPG v1.4.5 (GNU/Linux)

mQINBEvSKUIBEADLGnUj24ZVKW7liFN/JA5CgtzlNnKs7sBg7fVbNWryiE3URbn1
JXvrdwHtkKyY96/ifZ1Ld3lE2gOF61bGZ2CWwJNee76Sp9Z+isP8RQXbG5jwj/4B
M9HK7phktqFVJ8VbY2jfTjcfxRvGM8YBwXF8hx0CDZURAjvf1xRSQJ7iAo58qcHn
XtxOAvQmAbR9z6Q/h/D+Y/PhoIJp1OV4VNHCbCs9M7HUVBpgC53PDcTUQuwcgeY6
pQgo9eT1eLNSZVrJ5Bctivl1UcD6P6CIGkkeT2gNhqindRPngUXGXW7Qzoefe+fV
QqJSm7Tq2q9oqVZ46J964waCRItRySpuW5dxZO34WM6wsw2BP2MlACbH4l3luqtp
Xo3Bvfnk+HAFH3HcMuwdaulxv7zYKXCfNoSfgrpEfo2Ex4Im/I3WdtwME/Gbnwdq
3VJzgAxLVFhczDHwNkjmIdPAlNJ9/ixRjip4dgZtW8VcBCrNoL+LhDrIfjvnLdRu
vBHy9P3sCF7FZycaHlMWP6RiLtHnEMGcbZ8QpQHi2dReU1wyr9QgguGU+jqSXYar
1yEcsdRGasppNIZ8+Qawbm/a4doT10TEtPArhSoHlwbvqTDYjtfV92lC/2iwgO6g
YgG9XrO4V8dV39Ffm7oLFfvTbg5mv4Q/E6AWo/gkjmtxkculbyAvjFtYAQARAQAB
tCFFUEVMICg2KSA8ZXBlbEBmZWRvcmFwcm9qZWN0Lm9yZz6JAjYEEwECACAFAkvS
KUICGw8GCwkIBwMCBBUCCAMEFgIDAQIeAQIXgAAKCRA7Sd8qBgi4lR/GD/wLGPv9
qO39eyb9NlrwfKdUEo1tHxKdrhNz+XYrO4yVDTBZRPSuvL2yaoeSIhQOKhNPfEgT
9mdsbsgcfmoHxmGVcn+lbheWsSvcgrXuz0gLt8TGGKGGROAoLXpuUsb1HNtKEOwP
Q4z1uQ2nOz5hLRyDOV0I2LwYV8BjGIjBKUMFEUxFTsL7XOZkrAg/WbTH2PW3hrfS
WtcRA7EYonI3B80d39ffws7SmyKbS5PmZjqOPuTvV2F0tMhKIhncBwoojWZPExft
HpKhzKVh8fdDO/3P1y1Fk3Cin8UbCO9MWMFNR27fVzCANlEPljsHA+3Ez4F7uboF
p0OOEov4Yyi4BEbgqZnthTG4ub9nyiupIZ3ckPHr3nVcDUGcL6lQD/nkmNVIeLYP
x1uHPOSlWfuojAYgzRH6LL7Idg4FHHBA0to7FW8dQXFIOyNiJFAOT2j8P5+tVdq8
wB0PDSH8yRpn4HdJ9RYquau4OkjluxOWf0uRaS//SUcCZh+1/KBEOmcvBHYRZA5J
l/nakCgxGb2paQOzqqpOcHKvlyLuzO5uybMXaipLExTGJXBlXrbbASfXa/yGYSAG
iVrGz9CE6676dMlm8F+s3XXE13QZrXmjloc6jwOljnfAkjTGXjiB7OULESed96MR
XtfLk0W5Ab9pd7tKDR6QHI7rgHXfCopRnZ2VVQ==
=V/6I
Version: GnuPG v1.4.11 (GNU/Linux)

mQINBFKuaIQBEAC1UphXwMqCAarPUH/ZsOFslabeTVO2pDk5YnO96f+rgZB7xArB
OSeQk7B90iqSJ85/c72OAn4OXYvT63gfCeXpJs5M7emXkPsNQWWSju99lW+AqSNm
jYWhmRlLRGl0OO7gIwj776dIXvcMNFlzSPj00N2xAqjMbjlnV2n2abAE5gq6VpqP
vFXVyfrVa/ualogDVmf6h2t4Rdpifq8qTHsHFU3xpCz+T6/dGWKGQ42ZQfTaLnDM
jToAsmY0AyevkIbX6iZVtzGvanYpPcWW4X0RDPcpqfFNZk643xI4lsZ+Y2Er9Yu5
S/8x0ly+tmmIokaE0wwbdUu740YTZjCesroYWiRg5zuQ2xfKxJoV5E+Eh+tYwGDJ
n6HfWhRgnudRRwvuJ45ztYVtKulKw8QQpd2STWrcQQDJaRWmnMooX/PATTjCBExB
9dkz38Druvk7IkHMtsIqlkAOQMdsX1d3Tov6BE2XDjIG0zFxLduJGbVwc/6rIc95
T055j36Ez0HrjxdpTGOOHxRqMK5m9flFbaxxtDnS7w77WqzW7HjFrD0VeTx2vnjj
GqchHEQpfDpFOzb8LTFhgYidyRNUflQY35WLOzLNV+pV3eQ3Jg11UFwelSNLqfQf
uFRGc+zcwkNjHh5yPvm9odR1BIfqJ6sKGPGbtPNXo7ERMRypWyRz0zi0twARAQAB
tChGZWRvcmEgRVBFTCAoNykgPGVwZWxAZmVkb3JhcHJvamVjdC5vcmc+iQI4BBMB
AgAiBQJSrmiEAhsPBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRBqL66iNSxk
5cfGD/4spqpsTjtDM7qpytKLHKruZtvuWiqt5RfvT9ww9GUUFMZ4ZZGX4nUXg49q
ixDLayWR8ddG/s5kyOi3C0uX/6inzaYyRg+Bh70brqKUK14F1BrrPi29eaKfG+Gu
MFtXdBG2a7OtPmw3yuKmq9Epv6B0mP6E5KSdvSRSqJWtGcA6wRS/wDzXJENHp5re
9Ism3CYydpy0GLRA5wo4fPB5uLdUhLEUDvh2KK//fMjja3o0L+SNz8N0aDZyn5Ax
CU9RB3EHcTecFgoy5umRj99BZrebR1NO+4gBrivIfdvD4fJNfNBHXwhSH9ACGCNv
HnXVjHQF9iHWApKkRIeh8Fr2n5dtfJEF7SEX8GbX7FbsWo29kXMrVgNqHNyDnfAB
VoPubgQdtJZJkVZAkaHrMu8AytwT62Q4eNqmJI1aWbZQNI5jWYqc6RKuCK6/F99q
thFT9gJO17+yRuL6Uv2/vgzVR1RGdwVLKwlUjGPAjYflpCQwWMAASxiv9uPyYPHc
ErSrbRG0wjIfAR3vus1OSOx3xZHZpXFfmQTsDP7zVROLzV98R3JwFAxJ4/xqeON4
vCPFU6OsT3lWQ8w7il5ohY95wmujfr6lk89kEzJdOTzcn7DBbUru33CQMGKZ3Evt
RjsC7FDbL017qxS+ZVA/HGkyfiu4cpgV8VUnbql5eAZ+1Ll6Dw==
=hdPa
# Class epel
#
# Actions:
#   Configure the proper repositories and import GPG keys
#
# Reqiures:
#   You should probably be on an Enterprise Linux variant. (Centos, RHEL,
#   Scientific, Oracle, Ascendos, et al)
#
# Sample Usage:
#  include epel
#
class epel (
  $epel_mirrorlist                        = $epel::params::epel_mirrorlist,
  $epel_baseurl                           = $epel::params::epel_baseurl,
  $epel_failovermethod                    = $epel::params::epel_failovermethod,
  $epel_proxy                             = $epel::params::epel_proxy,
  $epel_enabled                           = $epel::params::epel_enabled,
  $epel_gpgcheck                          = $epel::params::epel_gpgcheck,
  $epel_testing_baseurl                   = $epel::params::epel_testing_baseurl,
  $epel_testing_failovermethod            = $epel::params::epel_testing_failovermethod,
  $epel_testing_proxy                     = $epel::params::epel_testing_proxy,
  $epel_testing_enabled                   = $epel::params::epel_testing_enabled,
  $epel_testing_gpgcheck                  = $epel::params::epel_testing_gpgcheck,
  $epel_source_mirrorlist                 = $epel::params::epel_source_mirrorlist,
  $epel_source_baseurl                    = $epel::params::epel_source_baseurl,
  $epel_source_failovermethod             = $epel::params::epel_source_failovermethod,
  $epel_source_proxy                      = $epel::params::epel_source_proxy,
  $epel_source_enabled                    = $epel::params::epel_source_enabled,
  $epel_source_gpgcheck                   = $epel::params::epel_source_gpgcheck,
  $epel_debuginfo_mirrorlist              = $epel::params::epel_debuginfo_mirrorlist,
  $epel_debuginfo_baseurl                 = $epel::params::epel_debuginfo_baseurl,
  $epel_debuginfo_failovermethod          = $epel::params::epel_debuginfo_failovermethod,
  $epel_debuginfo_proxy                   = $epel::params::epel_debuginfo_proxy,
  $epel_debuginfo_enabled                 = $epel::params::epel_debuginfo_enabled,
  $epel_debuginfo_gpgcheck                = $epel::params::epel_debuginfo_gpgcheck,
  $epel_testing_source_baseurl            = $epel::params::epel_testing_source_baseurl,
  $epel_testing_source_failovermethod     = $epel::params::epel_testing_source_failovermethod,
  $epel_testing_source_proxy              = $epel::params::epel_testing_source_proxy,
  $epel_testing_source_enabled            = $epel::params::epel_testing_source_enabled,
  $epel_testing_source_gpgcheck           = $epel::params::epel_testing_source_gpgcheck,
  $epel_testing_debuginfo_baseurl         = $epel::params::epel_testing_debuginfo_baseurl,
  $epel_testing_debuginfo_failovermethod  = $epel::params::epel_testing_debuginfo_failovermethod,
  $epel_testing_debuginfo_proxy           = $epel::params::epel_testing_debuginfo_proxy,
  $epel_testing_debuginfo_enabled         = $epel::params::epel_testing_debuginfo_enabled,
  $epel_testing_debuginfo_gpgcheck        = $epel::params::epel_testing_debuginfo_gpgcheck
) inherits epel::params {

  if $::osfamily == 'RedHat' and $::operatingsystem !~ /Fedora|Amazon/ {
    yumrepo { 'epel-testing':
      baseurl        => $epel_testing_baseurl,
      failovermethod => $epel_testing_failovermethod,
      proxy          => $epel_testing_proxy,
      enabled        => $epel_testing_enabled,
      gpgcheck       => $epel_testing_gpgcheck,
      gpgkey         => "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-${::operatingsystemmajrelease}",
      descr          => "Extra Packages for Enterprise Linux ${::operatingsystemmajrelease} - Testing - \$basearch ",
    }

    yumrepo { 'epel-testing-debuginfo':
      baseurl        => $epel_testing_debuginfo_baseurl,
      failovermethod => $epel_testing_debuginfo_failovermethod,
      proxy          => $epel_testing_debuginfo_proxy,
      enabled        => $epel_testing_debuginfo_enabled,
      gpgcheck       => $epel_testing_debuginfo_gpgcheck,
      gpgkey         => "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-${::operatingsystemmajrelease}",
      descr          => "Extra Packages for Enterprise Linux ${::operatingsystemmajrelease} - Testing - \$basearch - Debug",
    }

    yumrepo { 'epel-testing-source':
      baseurl        => $epel_testing_source_baseurl,
      failovermethod => $epel_testing_source_failovermethod,
      proxy          => $epel_testing_source_proxy,
      enabled        => $epel_testing_source_enabled,
      gpgcheck       => $epel_testing_source_gpgcheck,
      gpgkey         => "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-${::operatingsystemmajrelease}",
      descr          => "Extra Packages for Enterprise Linux ${::operatingsystemmajrelease} - Testing - \$basearch - Source",
    }

    yumrepo { 'epel':
      mirrorlist     => $epel_mirrorlist,
      baseurl        => $epel_baseurl,
      failovermethod => $epel_failovermethod,
      proxy          => $epel_proxy,
      enabled        => $epel_enabled,
      gpgcheck       => $epel_gpgcheck,
      gpgkey         => "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-${::operatingsystemmajrelease}",
      descr          => "Extra Packages for Enterprise Linux ${::operatingsystemmajrelease} - \$basearch",
    }

    yumrepo { 'epel-debuginfo':
      mirrorlist     => $epel_debuginfo_mirrorlist,
      baseurl        => $epel_debuginfo_baseurl,
      failovermethod => $epel_debuginfo_failovermethod,
      proxy          => $epel_debuginfo_proxy,
      enabled        => $epel_debuginfo_enabled,
      gpgcheck       => $epel_debuginfo_gpgcheck,
      gpgkey         => "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-${::operatingsystemmajrelease}",
      descr          => "Extra Packages for Enterprise Linux ${::operatingsystemmajrelease} - \$basearch - Debug",
    }

    yumrepo { 'epel-source':
      mirrorlist     => $epel_source_mirrorlist,
      baseurl        => $epel_source_baseurl,
      failovermethod => $epel_source_failovermethod,
      proxy          => $epel_source_proxy,
      enabled        => $epel_source_enabled,
      gpgcheck       => $epel_source_gpgcheck,
      gpgkey         => "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-${::operatingsystemmajrelease}",
      descr          => "Extra Packages for Enterprise Linux ${::operatingsystemmajrelease} - \$basearch - Source",
    }

    file { "/etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-${::operatingsystemmajrelease}":
      ensure => present,
      owner  => 'root',
      group  => 'root',
      mode   => '0644',
      source => "puppet:///modules/epel/RPM-GPG-KEY-EPEL-${::operatingsystemmajrelease}",
    }

    epel::rpm_gpg_key{ "EPEL-${::operatingsystemmajrelease}":
      path   => "/etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-${::operatingsystemmajrelease}",
      before => Yumrepo['epel','epel-source','epel-debuginfo','epel-testing','epel-testing-source','epel-testing-debuginfo'],
    }

  } elsif $::osfamily == 'RedHat' and $::operatingsystem == 'Amazon' {
    yumrepo { 'epel':
      enabled  => $epel_enabled,
      gpgcheck => $epel_gpgcheck,
    }
  } else {
    notice ("Your operating system ${::operatingsystem} will not have the EPEL repository applied")
  }

}
# Optional parameters in setting up EPEL
class epel::params {
  # Setting to 'absent' will fall back to the yum.conf
  # Setting proxy here will be the default for all repos.
  #
  #  If you wish to set a proxy for an individual set of repos,
  #   you can declare $proxy in that class, and should scope to
  #   the most specific declaration of proxy.
  $proxy = 'absent'

  $epel_mirrorlist                        = "http://mirrors.fedoraproject.org/mirrorlist?repo=epel-${::operatingsystemmajrelease}&arch=\$basearch"
  $epel_baseurl                           = 'absent'
  $epel_failovermethod                    = 'priority'
  $epel_proxy                             = $proxy
  $epel_enabled                           = '1'
  $epel_gpgcheck                          = '1'
  $epel_testing_baseurl                   = "http://download.fedoraproject.org/pub/epel/testing/${::operatingsystemmajrelease}/\$basearch"
  $epel_testing_failovermethod            = 'priority'
  $epel_testing_proxy                     = $proxy
  $epel_testing_enabled                   = '0'
  $epel_testing_gpgcheck                  = '1'
  $epel_source_mirrorlist                 = "http://mirrors.fedoraproject.org/mirrorlist?repo=epel-source-${::operatingsystemmajrelease}&arch=\$basearch"
  $epel_source_baseurl                    = 'absent'
  $epel_source_failovermethod             = 'priority'
  $epel_source_proxy                      = $proxy
  $epel_source_enabled                    = '0'
  $epel_source_gpgcheck                   = '1'
  $epel_debuginfo_mirrorlist              = "http://mirrors.fedoraproject.org/mirrorlist?repo=epel-debug-${::operatingsystemmajrelease}&arch=\$basearch"
  $epel_debuginfo_baseurl                 = 'absent'
  $epel_debuginfo_failovermethod          = 'priority'
  $epel_debuginfo_proxy                   = $proxy
  $epel_debuginfo_enabled                 = '0'
  $epel_debuginfo_gpgcheck                = '1'
  $epel_testing_source_baseurl            = "http://download.fedoraproject.org/pub/epel/testing/${::operatingsystemmajrelease}/SRPMS"
  $epel_testing_source_failovermethod     = 'priority'
  $epel_testing_source_proxy              = $proxy
  $epel_testing_source_enabled            = '0'
  $epel_testing_source_gpgcheck           = '1'
  $epel_testing_debuginfo_baseurl         = "http://download.fedoraproject.org/pub/epel/testing/${::operatingsystemmajrelease}/\$basearch/debug"
  $epel_testing_debuginfo_failovermethod  = 'priority'
  $epel_testing_debuginfo_proxy           = $proxy
  $epel_testing_debuginfo_enabled         = '0'
  $epel_testing_debuginfo_gpgcheck        = '1'

}
# Define epel::rpm_gpg_key
#
# Actions:
#   Import a RPM gpg key
#
# Parameters:
#
# [*path*]
#   Path of the RPM GPG key to import
#
# Reqiures:
#   You should probably be on an Enterprise Linux variant. (Centos, RHEL, Scientific, Oracle, Ascendos, et al)
#
# Sample Usage:
#  epel::rpm_gpg_key{ "EPEL-6":
#    path => "/etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-6"
#  }
#
define epel::rpm_gpg_key($path) {
  # Given the path to a key, see if it is imported, if not, import it
  exec {  "import-${name}":
    path      => '/bin:/usr/bin:/sbin:/usr/sbin',
    command   => "rpm --import ${path}",
    unless    => "rpm -q gpg-pubkey-$(echo $(gpg --throw-keyids < ${path}) | cut --characters=11-18 | tr '[A-Z]' '[a-z]')",
    require   => File[$path],
    logoutput => 'on_failure',
  }
}
{
  "name": "stahnma-epel",
  "version": "1.0.0",
  "author": "stahnma",
  "summary": "Setup the EPEL package repo",
  "license": "Apache License, Version 2.0",
  "source": "http://github.com/stahnma/puppet-module-epel",
  "project_page": "http://github.com/stahnma/puppet-module-epel",
  "issues_url": "https://github.com/stahnma/puppet-module-epel/issues",
  "operatingsystem_support": [
    {
      "operatingsystem": "RedHat",
      "operatingsystemrelease": [
        "5",
        "6",
        "7"
      ]
    },
    {
      "operatingsystem": "CentOS",
      "operatingsystemrelease": [
        "5",
        "6",
        "7"
      ]
    },
    {
      "operatingsystem": "Scientific",
      "operatingsystemrelease": [
        "5",
        "6",
        "7"
      ]
    },
    {
      "operatingsystem": "OEL",
      "operatingsystemrelease": [
        "5",
        "6",
        "7"
      ]
    },
    {
      "operatingsystem": "OracleLinux",
      "operatingsystemrelease": [
        "5",
        "6",
        "7"
      ]
    }
  ],
  "requirements": [
    {
      "name": "pe",
      "version_requirement": ">= 3.0.0"
    },
    {
      "name": "puppet",
      "version_requirement": ">= 3.0.0"
    }
  ],
  "description": "Setup the EPEL package repo on Centos/RHEL et all",
  "dependencies": [
  
  ]
}
require 'spec_helper'
require 'classes/shared_gpgkey'
require 'classes/shared_base'
require 'classes/shared_source'
require 'classes/shared_debuginfo'
require 'classes/shared_testing'
require 'classes/shared_testing_source'
require 'classes/shared_testing_debuginfo'

describe 'epel' do
  it { should create_class('epel') }
  it { should contain_class('epel::params') }

  context "operatingsystem => #{default_facts[:operatingsystem]}" do
    context 'operatingsystemmajrelease => 6' do
      include_context :base_6
      include_context :gpgkey_6
      include_context :epel_source_6
      include_context :epel_debuginfo_6
      include_context :epel_testing_6
      include_context :epel_testing_source_6
      include_context :epel_testing_debuginfo_6

      let :facts do
        default_facts.merge({
          :operatingsystemrelease => '6.4',
          :operatingsystemmajrelease         => '6',
        })
      end

      context 'epel_baseurl => http://example.com/epel/6/x86_64' do
        let(:params) {{ :epel_baseurl => "http://example.com/epel/6/x86_64" }}
        it { should contain_yumrepo('epel').with('baseurl'  => 'http://example.com/epel/6/x86_64') }
      end
      
      context 'epel_mirrorlist => absent' do
        let(:params) {{ :epel_mirrorlist => 'absent' }}
        it { should contain_yumrepo('epel').with('mirrorlist'  => 'absent') }
      end
    end

    context 'operatingsystemmajrelease => 5' do
      include_context :base_5
      include_context :gpgkey_5
      include_context :epel_source_5
      include_context :epel_debuginfo_5
      include_context :epel_testing_5
      include_context :epel_testing_source_5
      include_context :epel_testing_debuginfo_5

      let :facts do
        default_facts.merge({
          :operatingsystemrelease => '5.9',
          :operatingsystemmajrelease         => '5',
        })
      end
    end
  end

  context 'operatingsystem => Amazon' do
    let :facts do
      default_facts.merge({
        :operatingsystem  => 'Amazon',
      })
    end

    it { should_not contain_yumrepo('epel-testing') }
    it { should_not contain_yumrepo('epel-testing-debuginfo') }
    it { should_not contain_yumrepo('epel-testing-source') }
    it { should_not contain_yumrepo('epel-debuginfo') }
    it { should_not contain_yumrepo('epel-source') }

    it do
      should contain_yumrepo('epel').with({
        'enabled'   => '1',
        'gpgcheck'  => '1',
      })
    end
  end
end
require 'spec_helper'

shared_context :base do
  it do
    should contain_yumrepo('epel').with({
      'failovermethod' => 'priority',
      'proxy'          => 'absent',
      'enabled'        => '1',
      'gpgcheck'       => '1',
    })
  end
end

shared_context :base_6 do
  include_context :base

  it do
    should contain_yumrepo('epel').with({
      'mirrorlist'     => "http://mirrors.fedoraproject.org/mirrorlist?repo=epel-6&arch=$basearch",
      'gpgkey'         => "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-6",
      'descr'          => "Extra Packages for Enterprise Linux 6 - $basearch",
    })
  end
end

shared_context :base_5 do
  include_context :base

  it do
    should contain_yumrepo('epel').with({
      'mirrorlist'     => "http://mirrors.fedoraproject.org/mirrorlist?repo=epel-5&arch=$basearch",
      'gpgkey'         => "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-5",
      'descr'          => "Extra Packages for Enterprise Linux 5 - $basearch",
    })
  end
end
require 'spec_helper'

shared_context :epel_debuginfo do
  it do
    should contain_yumrepo('epel-debuginfo').with({
      'proxy'          => 'absent',
      'failovermethod' => 'priority',
      'enabled'        => '0',
      'gpgcheck'       => '1',
    })
  end
end

shared_context :epel_debuginfo_6 do
  include_context :epel_debuginfo

  it do
    should contain_yumrepo('epel-debuginfo').with({
      'mirrorlist'     => "http://mirrors.fedoraproject.org/mirrorlist?repo=epel-debug-6&arch=$basearch",
      'gpgkey'         => "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-6",
      'descr'          => "Extra Packages for Enterprise Linux 6 - $basearch - Debug",
    })
  end
end

shared_context :epel_debuginfo_5 do
  include_context :epel_debuginfo

  it do
    should contain_yumrepo('epel-debuginfo').with({
      'mirrorlist'     => "http://mirrors.fedoraproject.org/mirrorlist?repo=epel-debug-5&arch=$basearch",
      'gpgkey'         => "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-5",
      'descr'          => "Extra Packages for Enterprise Linux 5 - $basearch - Debug",
    })
  end
end
require 'spec_helper'

shared_context :gpgkey_6 do
  it do
    should contain_file("/etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-6").with({
      'ensure' => 'present',
      'owner'  => 'root',
      'group'  => 'root',
      'mode'   => '0644',
      'source' => "puppet:///modules/epel/RPM-GPG-KEY-EPEL-6",
    })
  end

  it do
    should contain_epel__rpm_gpg_key("EPEL-6").with({
      'path' => "/etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-6"
    })
  end
end

shared_context :gpgkey_5 do
  it do
    should contain_file("/etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-5").with({
      'ensure' => 'present',
      'owner'  => 'root',
      'group'  => 'root',
      'mode'   => '0644',
      'source' => "puppet:///modules/epel/RPM-GPG-KEY-EPEL-5",
    })
  end

  it do
    should contain_epel__rpm_gpg_key("EPEL-5").with({
      'path' => "/etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-5"
    })
  end
end
require 'spec_helper'

shared_context :epel_source do
  it do
    should contain_yumrepo('epel-source').with({
      'proxy'          => 'absent',
      'failovermethod' => 'priority',
      'enabled'        => '0',
      'gpgcheck'       => '1',
    })
  end
end

shared_context :epel_source_6 do
  include_context :epel_source

  it do
    should contain_yumrepo('epel-source').with({
      'mirrorlist'     => "http://mirrors.fedoraproject.org/mirrorlist?repo=epel-source-6&arch=$basearch",
      'gpgkey'         => "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-6",
      'descr'          => "Extra Packages for Enterprise Linux 6 - $basearch - Source",
    })
  end
end

shared_context :epel_source_5 do
  include_context :epel_source

  it do
    should contain_yumrepo('epel-source').with({
      'mirrorlist'     => "http://mirrors.fedoraproject.org/mirrorlist?repo=epel-source-5&arch=$basearch",
      'gpgkey'         => "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-5",
      'descr'          => "Extra Packages for Enterprise Linux 5 - $basearch - Source",
    })
  end
end
require 'spec_helper'

shared_context :epel_testing do
  it do
    should contain_yumrepo('epel-testing').with({
      'failovermethod' => 'priority',
      'proxy'          => 'absent',
      'enabled'        => '0',
      'gpgcheck'       => '1',
    })
  end
end

shared_context :epel_testing_6 do
  include_context :epel_testing

  it do
    should contain_yumrepo('epel-testing').with({
      'baseurl'        => "http://download.fedoraproject.org/pub/epel/testing/6/$basearch",
      'gpgkey'         => "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-6",
      'descr'          => "Extra Packages for Enterprise Linux 6 - Testing - $basearch ",
    })
  end
end

shared_context :epel_testing_5 do
  include_context :epel_testing

  it do
    should contain_yumrepo('epel-testing').with({
      'baseurl'        => "http://download.fedoraproject.org/pub/epel/testing/5/$basearch",
      'gpgkey'         => "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-5",
      'descr'          => "Extra Packages for Enterprise Linux 5 - Testing - $basearch ",
    })
  end
end
require 'spec_helper'

shared_context :epel_testing_debuginfo do
  it do
    should contain_yumrepo('epel-testing-debuginfo').with({
      'failovermethod' => 'priority',
      'proxy'          => 'absent',
      'enabled'        => '0',
      'gpgcheck'       => '1',
    })
  end
end

shared_context :epel_testing_debuginfo_6 do
  include_context :epel_testing_debuginfo

  it do
    should contain_yumrepo('epel-testing-debuginfo').with({
      'baseurl'        => "http://download.fedoraproject.org/pub/epel/testing/6/$basearch/debug",
      'gpgkey'         => "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-6",
      'descr'          => "Extra Packages for Enterprise Linux 6 - Testing - $basearch - Debug",
    })
  end
end

shared_context :epel_testing_debuginfo_5 do
  include_context :epel_testing_debuginfo

  it do
    should contain_yumrepo('epel-testing-debuginfo').with({
      'baseurl'        => "http://download.fedoraproject.org/pub/epel/testing/5/$basearch/debug",
      'gpgkey'         => "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-5",
      'descr'          => "Extra Packages for Enterprise Linux 5 - Testing - $basearch - Debug",
    })
  end
end
require 'spec_helper'

shared_context :epel_testing_source do
  it do
    should contain_yumrepo('epel-testing-source').with({
      'failovermethod' => 'priority',
      'proxy'          => 'absent',
      'enabled'        => '0',
      'gpgcheck'       => '1',
    })
  end
end

shared_context :epel_testing_source_6 do
  include_context :epel_testing_source

  it do
    should contain_yumrepo('epel-testing-source').with({
      'baseurl'        => "http://download.fedoraproject.org/pub/epel/testing/6/SRPMS",
      'gpgkey'         => "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-6",
      'descr'          => "Extra Packages for Enterprise Linux 6 - Testing - $basearch - Source",
    })
  end
end

shared_context :epel_testing_source_5 do
  include_context :epel_testing_source

  it do
    should contain_yumrepo('epel-testing-source').with({
      'baseurl'        => "http://download.fedoraproject.org/pub/epel/testing/5/SRPMS",
      'gpgkey'         => "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-5",
      'descr'          => "Extra Packages for Enterprise Linux 5 - Testing - $basearch - Source",
    })
  end
end
require 'spec_helper'

describe 'epel::rpm_gpg_key' do
  context 'operatingsystemmajrelease => 6' do
    let :facts do
      default_facts.merge({
        :operatingsystemrelease => '6.4',
        :operatingsystemmajrelease         => '6',
      })
    end

    let :title do
      'EPEL-6'
    end

    let :params do
      { :path => "/etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-6" }
    end

    it do
      should contain_exec("import-#{title}").with({
        'path'      => '/bin:/usr/bin:/sbin:/usr/sbin',
        'command'   => "rpm --import #{params[:path]}",
        'unless'    => "rpm -q gpg-pubkey-$(echo $(gpg --throw-keyids < #{params[:path]}) | cut --characters=11-18 | tr '[A-Z]' '[a-z]')",
        'require'   => "File[#{params[:path]}]",
        'logoutput' => 'on_failure',
      })
    end
  end

  context 'operatingsystemmajrelease => 5' do
    let :facts do
      default_facts.merge({
        :operatingsystemrelease => '5.9',
        :operatingsystemmajrelease         => '5',
      })
    end

    let :title do
      'EPEL-5'
    end

    let :params do
      { :path => "/etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-5" }
    end

    it do
      should contain_exec("import-#{title}").with({
        'path'      => '/bin:/usr/bin:/sbin:/usr/sbin',
        'command'   => "rpm --import #{params[:path]}",
        'unless'    => "rpm -q gpg-pubkey-$(echo $(gpg --throw-keyids < #{params[:path]}) | cut --characters=11-18 | tr '[A-Z]' '[a-z]')",
        'require'   => "File[#{params[:path]}]",
        'logoutput' => 'on_failure',
      })
    end
  end
end
require 'puppetlabs_spec_helper/module_spec_helper'

def default_facts
  {
    :osfamily               => 'RedHat',
    :operatingsystem        => 'CentOS',
  }
end
require 'rspec-system/spec_helper'
require 'rspec-system-puppet/helpers'

include RSpecSystemPuppet::Helpers

RSpec.configure do |c|
  # Project root for the this module's code
  proj_root = File.expand_path(File.join(File.dirname(__FILE__), '..'))

  # Enable colour in Jenkins
  c.tty = true

  c.include RSpecSystemPuppet::Helpers

  # This is where we 'setup' the nodes before running our tests
  c.before :suite do
    # Install puppet
    puppet_install
    puppet_master_install

    puppet_module_install(:source => proj_root, :module_name => 'epel')
  end
end
require 'spec_helper_system'

describe 'epel class:' do
  context puppet_agent do
    its(:stderr) { should be_empty }
    its(:exit_code) { should_not == 1 }
  end

  # Verify the operatingsystemmajrelease fact is working
  context shell 'facter --puppet operatingsystemmajrelease' do
    its(:stdout) { should_not be_empty }
    its(:stderr) { should be_empty }
    its(:exit_code) { should be_zero }
  end

  pp = "class { 'epel': }"

  context puppet_apply pp do
    its(:stderr) { should be_empty }
    its(:exit_code) { should_not == 1 }
    its(:refresh) { should be_nil }
    its(:stderr) { should be_empty }
    its(:exit_code) { should be_zero }
  end

  context 'test EPEL repo presence' do
    facts = node.facts

    # Only test for EPEL's presence if not Fedora
    if facts['operatingsystem'] !~ /Fedora/
      context shell '/usr/bin/yum-config-manager epel | grep -q "\[epel\]"' do
        its(:exit_code) { should be_zero }
      end
    end
  end
end
require 'spec_helper_system'

describe 'standage usage tests:' do
  context 'test epel baseurl and mirrorlist' do
    facts = node.facts
    operatingsystemmajrelease = facts['operatingsystemrelease'].split('.')[0]
    pp = <<-EOS
      class { 'epel':
        epel_baseurl    => 'http://dl.fedoraproject.org/pub/epel/#{operatingsystemmajrelease}/x86_64/',
        epel_mirrorlist => 'absent',
      }
    EOS

    context puppet_apply pp do
      its(:stderr) { should be_empty }
      its(:exit_code) { should_not == 1 }
      its(:refresh) { should be_nil }
      its(:stderr) { should be_empty }
      its(:exit_code) { should be_zero }
    end

    # Only test for EPEL's presence if not Fedora
    if facts['operatingsystem'] !~ /Fedora/
      # Test the yum config to ensure mirrorlist was emptied
      context shell '/usr/bin/yum-config-manager epel | egrep "^mirrorlist ="' do
        its(:stdout) { should =~ /mirrorlist =\s+/ }
      end

      # Test the yum config to ensure baseurl was defined
      context shell '/usr/bin/yum-config-manager epel | egrep "^baseurl ="' do
        its(:stdout) { should =~ /baseurl = http:\/\/dl.fedoraproject.org\/pub\/epel\/#{operatingsystemmajrelease}\/x86_64\// }
      end
    end
  end

  context 'test epel-testing is enabled' do
    facts = node.facts
    pp = <<-EOS
      class { 'epel':
        epel_testing_enabled    => '1',
      }
    EOS

    context puppet_apply pp do
      its(:stderr) { should be_empty }
      its(:exit_code) { should_not == 1 }
      its(:refresh) { should be_nil }
      its(:stderr) { should be_empty }
      its(:exit_code) { should be_zero }
    end

    # Only test for EPEL's presence if not Fedora
    if facts['operatingsystem'] !~ /Fedora/
      # Test the yum config to ensure epel-testing was enabled
      context shell '/usr/bin/yum-config-manager epel-testing | grep -q "enabled = True"' do
        its(:exit_code) { should be_zero }
      end
    end
  end
end
# And by test, I mean, run this thing for me using Puppet apply and I'll check
# it out.
include 'epel'
fixtures:
  repositories:
    apt: git://github.com/puppetlabs/puppetlabs-apt.git
    stdlib: git://github.com/puppetlabs/puppetlabs-stdlib.git
    epel: git://github.com/stahnma/puppet-module-epel.git
  symlinks:
    erlang: "#{source_dir}"
default_set: 'centos-64-x64'
sets:
  'centos-59-x64':
    nodes:
      "main.foo.vm":
        prefab: 'centos-59-x64'
  'centos-64-x64':
    nodes:
      "main.foo.vm":
        prefab: 'centos-64-x64'
  'fedora-18-x64':
    nodes:
      "main.foo.vm":
        prefab: 'fedora-18-x64'
  'debian-607-x64':
    nodes:
      "main.foo.vm":
        prefab: 'debian-607-x64'
  'debian-70rc1-x64':
    nodes:
      "main.foo.vm":
        prefab: 'debian-70rc1-x64'
  'ubuntu-server-10044-x64':
    nodes:
      "main.foo.vm":
        prefab: 'ubuntu-server-10044-x64'
  'ubuntu-server-12042-x64':
    nodes:
      "main.foo.vm":
        prefab: 'ubuntu-server-12042-x64'
  'sles-11sp1-x64':
    nodes:
      "main.foo.vm":
        prefab: 'sles-11sp1-x64'
language: ruby
bundler_args: --without development
before_install: rm Gemfile.lock || true
rvm:
  - 1.8.7
  - 1.9.3
  - 2.0.0
script: bundle exec rake test
env:
  - PUPPET_VERSION="~> 2.7.0"
  - PUPPET_VERSION="~> 3.1.0"
  - PUPPET_VERSION="~> 3.2.0"
  - PUPPET_VERSION="~> 3.3.0"
  - PUPPET_VERSION="~> 3.4.0"
matrix:
  exclude:
  - rvm: 2.0.0
    env: PUPPET_VERSION="~> 2.7.0"
  - rvm: 2.0.0
    env: PUPPET_VERSION="~> 3.1.0"
  - rvm: 1.9.3
    env: PUPPET_VERSION="~> 2.7.0"
source "http://rubygems.org"


gem "rake"
gem "puppet", ENV['PUPPET_VERSION'] || '~> 3.2.0'
gem "puppet-lint"
gem "rspec-puppet", '~> 1.0.0'
gem "puppetlabs_spec_helper"
gem "rspec-system-puppet"
gem "vagrant-wrapper"
gem "puppet-syntax"

group :development do
  gem "puppet-blacksmith"
end
GEM
  remote: http://rubygems.org/
  specs:
    builder (3.2.2)
    diff-lcs (1.2.5)
    excon (0.31.0)
    facter (1.7.5)
    fog (1.20.0)
      builder
      excon (~> 0.31.0)
      formatador (~> 0.2.0)
      mime-types
      multi_json (~> 1.0)
      net-scp (~> 1.1)
      net-ssh (>= 2.1.3)
      nokogiri (>= 1.5.11)
    formatador (0.2.4)
    hiera (1.3.2)
      json_pure
    json_pure (1.8.1)
    kwalify (0.7.2)
    metaclass (0.0.4)
    mime-types (1.25.1)
    mocha (1.0.0)
      metaclass (~> 0.0.1)
    multi_json (1.8.4)
    net-scp (1.1.2)
      net-ssh (>= 2.6.5)
    net-ssh (2.8.0)
    nokogiri (1.5.11)
    puppet (3.2.4)
      facter (~> 1.6)
      hiera (~> 1.0)
      rgen (~> 0.6.5)
    puppet-blacksmith (2.0.2)
      nokogiri
      puppet (>= 2.7.16)
      rest-client
    puppet-lint (0.3.2)
    puppet-syntax (1.1.0)
      puppet (>= 2.7.0)
      rake
    puppetlabs_spec_helper (0.4.1)
      mocha (>= 0.10.5)
      rake
      rspec (>= 2.9.0)
      rspec-puppet (>= 0.1.1)
    rake (10.1.1)
    rbvmomi (1.8.1)
      builder
      nokogiri (>= 1.4.1)
      trollop
    rest-client (1.6.7)
      mime-types (>= 1.16)
    rgen (0.6.6)
    rspec (2.14.1)
      rspec-core (~> 2.14.0)
      rspec-expectations (~> 2.14.0)
      rspec-mocks (~> 2.14.0)
    rspec-core (2.14.8)
    rspec-expectations (2.14.5)
      diff-lcs (>= 1.1.3, < 2.0)
    rspec-mocks (2.14.6)
    rspec-puppet (1.0.1)
      rspec
    rspec-system (2.8.0)
      fog (~> 1.18)
      kwalify (~> 0.7.2)
      mime-types (~> 1.16)
      net-scp (~> 1.1)
      net-ssh (~> 2.7)
      nokogiri (~> 1.5.10)
      rbvmomi (~> 1.6)
      rspec (~> 2.14)
      systemu (~> 2.5)
    rspec-system-puppet (2.2.1)
      rspec-system (~> 2.0)
    systemu (2.6.3)
    trollop (2.0)
    vagrant-wrapper (1.2.1.1)

PLATFORMS
  ruby

DEPENDENCIES
  puppet (~> 3.2.0)
  puppet-blacksmith
  puppet-lint
  puppet-syntax
  puppetlabs_spec_helper
  rake
  rspec-puppet (~> 1.0.0)
  rspec-system-puppet
  vagrant-wrapper
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/

TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

1. Definitions.

    "License" shall mean the terms and conditions for use, reproduction, and
    distribution as defined by Sections 1 through 9 of this document.

    "Licensor" shall mean the copyright owner or entity authorized by the
    copyright owner that is granting the License.

    "Legal Entity" shall mean the union of the acting entity and all other
    entities that control, are controlled by, or are under common control with
    that entity. For the purposes of this definition, "control" means (i) the
    power, direct or indirect, to cause the direction or management of such
    entity, whether by contract or otherwise, or (ii) ownership of
    fifty percent (50%) or more of the outstanding shares, or (iii) beneficial
    ownership of such entity.

    "You" (or "Your") shall mean an individual or Legal Entity exercising
    permissions granted by this License.

    "Source" form shall mean the preferred form for making modifications,
    including but not limited to software source code, documentation source,
    and configuration files.

    "Object" form shall mean any form resulting from mechanical transformation
    or translation of a Source form, including but not limited to compiled
    object code, generated documentation, and conversions to
    other media types.

    "Work" shall mean the work of authorship, whether in Source or Object
    form, made available under the License, as indicated by a copyright notice
    that is included in or attached to the work (an example is provided in the
    Appendix below).

    "Derivative Works" shall mean any work, whether in Source or Object form,
    that is based on (or derived from) the Work and for which the editorial
    revisions, annotations, elaborations, or other modifications represent,
    as a whole, an original work of authorship. For the purposes of this
    License, Derivative Works shall not include works that remain separable
    from, or merely link (or bind by name) to the interfaces of, the Work and
    Derivative Works thereof.

    "Contribution" shall mean any work of authorship, including the original
    version of the Work and any modifications or additions to that Work or
    Derivative Works thereof, that is intentionally submitted to Licensor for
    inclusion in the Work by the copyright owner or by an individual or
    Legal Entity authorized to submit on behalf of the copyright owner.
    For the purposes of this definition, "submitted" means any form of
    electronic, verbal, or written communication sent to the Licensor or its
    representatives, including but not limited to communication on electronic
    mailing lists, source code control systems, and issue tracking systems
    that are managed by, or on behalf of, the Licensor for the purpose of
    discussing and improving the Work, but excluding communication that is
    conspicuously marked or otherwise designated in writing by the copyright
    owner as "Not a Contribution."

    "Contributor" shall mean Licensor and any individual or Legal Entity on
    behalf of whom a Contribution has been received by Licensor and
    subsequently incorporated within the Work.

2. Grant of Copyright License.

    Subject to the terms and conditions of this License, each Contributor
    hereby grants to You a perpetual, worldwide, non-exclusive, no-charge,
    royalty-free, irrevocable copyright license to reproduce, prepare
    Derivative Works of, publicly display, publicly perform, sublicense,
    and distribute the Work and such Derivative Works in
    Source or Object form.

3. Grant of Patent License.

    Subject to the terms and conditions of this License, each Contributor
    hereby grants to You a perpetual, worldwide, non-exclusive, no-charge,
    royalty-free, irrevocable (except as stated in this section) patent
    license to make, have made, use, offer to sell, sell, import, and
    otherwise transfer the Work, where such license applies only to those
    patent claims licensable by such Contributor that are necessarily
    infringed by their Contribution(s) alone or by combination of their
    Contribution(s) with the Work to which such Contribution(s) was submitted.
    If You institute patent litigation against any entity (including a
    cross-claim or counterclaim in a lawsuit) alleging that the Work or a
    Contribution incorporated within the Work constitutes direct or
    contributory patent infringement, then any patent licenses granted to
    You under this License for that Work shall terminate as of the date such
    litigation is filed.

4. Redistribution.

    You may reproduce and distribute copies of the Work or Derivative Works
    thereof in any medium, with or without modifications, and in Source or
    Object form, provided that You meet the following conditions:

    1. You must give any other recipients of the Work or Derivative Works a
    copy of this License; and

    2. You must cause any modified files to carry prominent notices stating
    that You changed the files; and

    3. You must retain, in the Source form of any Derivative Works that You
    distribute, all copyright, patent, trademark, and attribution notices from
    the Source form of the Work, excluding those notices that do not pertain
    to any part of the Derivative Works; and

    4. If the Work includes a "NOTICE" text file as part of its distribution,
    then any Derivative Works that You distribute must include a readable copy
    of the attribution notices contained within such NOTICE file, excluding
    those notices that do not pertain to any part of the Derivative Works,
    in at least one of the following places: within a NOTICE text file
    distributed as part of the Derivative Works; within the Source form or
    documentation, if provided along with the Derivative Works; or, within a
    display generated by the Derivative Works, if and wherever such
    third-party notices normally appear. The contents of the NOTICE file are
    for informational purposes only and do not modify the License.
    You may add Your own attribution notices within Derivative Works that You
    distribute, alongside or as an addendum to the NOTICE text from the Work,
    provided that such additional attribution notices cannot be construed
    as modifying the License.

    You may add Your own copyright statement to Your modifications and may
    provide additional or different license terms and conditions for use,
    reproduction, or distribution of Your modifications, or for any such
    Derivative Works as a whole, provided Your use, reproduction, and
    distribution of the Work otherwise complies with the conditions
    stated in this License.

5. Submission of Contributions.

    Unless You explicitly state otherwise, any Contribution intentionally
    submitted for inclusion in the Work by You to the Licensor shall be under
    the terms and conditions of this License, without any additional
    terms or conditions. Notwithstanding the above, nothing herein shall
    supersede or modify the terms of any separate license agreement you may
    have executed with Licensor regarding such Contributions.

6. Trademarks.

    This License does not grant permission to use the trade names, trademarks,
    service marks, or product names of the Licensor, except as required for
    reasonable and customary use in describing the origin of the Work and
    reproducing the content of the NOTICE file.

7. Disclaimer of Warranty.

    Unless required by applicable law or agreed to in writing, Licensor
    provides the Work (and each Contributor provides its Contributions)
    on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
    either express or implied, including, without limitation, any warranties
    or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS
    FOR A PARTICULAR PURPOSE. You are solely responsible for determining the
    appropriateness of using or redistributing the Work and assume any risks
    associated with Your exercise of permissions under this License.

8. Limitation of Liability.

    In no event and under no legal theory, whether in tort
    (including negligence), contract, or otherwise, unless required by
    applicable law (such as deliberate and grossly negligent acts) or agreed
    to in writing, shall any Contributor be liable to You for damages,
    including any direct, indirect, special, incidental, or consequential
    damages of any character arising as a result of this License or out of
    the use or inability to use the Work (including but not limited to damages
    for loss of goodwill, work stoppage, computer failure or malfunction,
    or any and all other commercial damages or losses), even if such
    Contributor has been advised of the possibility of such damages.

9. Accepting Warranty or Additional Liability.

    While redistributing the Work or Derivative Works thereof, You may choose
    to offer, and charge a fee for, acceptance of support, warranty,
    indemnity, or other liability obligations and/or rights consistent with
    this License. However, in accepting such obligations, You may act only
    on Your own behalf and on Your sole responsibility, not on behalf of any
    other Contributor, and only if You agree to indemnify, defend, and hold
    each Contributor harmless for any liability incurred by, or claims
    asserted against, such Contributor by reason of your accepting any such
    warranty or additional liability.

END OF TERMS AND CONDITIONS

APPENDIX: How to apply the Apache License to your work

    To apply the Apache License to your work, attach the following boilerplate
    notice, with the fields enclosed by brackets "[]" replaced with your own
    identifying information. (Don't include the brackets!) The text should be
    enclosed in the appropriate comment syntax for the file format. We also
    recommend that a file or class name and description of purpose be included
    on the same "printed page" as the copyright notice for easier
    identification within third-party archives.

        Copyright 2013 Gareth Rushgrove

        Licensed under the Apache License, Version 2.0 (the "License");
        you may not use this file except in compliance with the License.
        You may obtain a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0

        Unless required by applicable law or agreed to in writing, software
        distributed under the License is distributed on an "AS IS" BASIS,
        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
        or implied. See the License for the specific language governing
        permissions and limitations under the License.
name        'garethr-erlang'
version     '0.3.0'
source      'git://github.com/garethr/garethr-erlang.git'
author      'Gareth Rushgrove'
summary     'Module for installing erlang from official repos'
description 'Install one of the official erlang packages'
license     'Apache License, Version 2.0'
dependency  'puppetlabs/apt'
dependency  'puppetlabs/stdlib'
dependency  'stahnma/epel'
Puppet module for installing Erlang from alternative repositories.

On debian it will use the official repositories
mentioned on the [Erlang
docs](https://www.erlang-solutions.com/downloads/download-erlang-otp).

On Redhat 5 it'll use an additional EPEL repository hosted by
[Redhat](http://repos.fedorapeople.org/repos/peter/erlang/epel-erlang.repo).

On Redhat 6 it'll require EPEL.

On SUSE it'll use the official repos.

On Archlinux it'll use community repos.

This module is also available on the [Puppet
Forge](https://forge.puppetlabs.com/garethr/erlang)

[![Build
Status](https://secure.travis-ci.org/garethr/garethr-erlang.png)](http://travis-ci.org/garethr/garethr-erlang)

## Usage

The module includes a single class:

    include 'erlang'

By default this sets up the repository and installs the erlang package.
require 'puppetlabs_spec_helper/rake_tasks'
require 'puppet-lint/tasks/puppet-lint'
require 'puppet-syntax/tasks/puppet-syntax'
require 'rspec-system/rake_task'

begin
    require 'puppet_blacksmith/rake_tasks'
rescue LoadError
end

PuppetLint.configuration.log_format = "%{path}:%{linenumber}:%{check}:%{KIND}:%{message}"
PuppetLint.configuration.fail_on_warnings = true

# Forsake support for Puppet 2.6.2 for the benefit of cleaner code.
# http://puppet-lint.com/checks/class_parameter_defaults/
PuppetLint.configuration.send('disable_class_parameter_defaults')
# http://puppet-lint.com/checks/class_inherits_from_params_class/
PuppetLint.configuration.send('disable_class_inherits_from_params_class')
# http://puppet-lint.com/checks/80chars/
PuppetLint.configuration.send("disable_80chars")

exclude_paths = [
  "pkg/**/*",
  "vendor/**/*",
  "spec/**/*",
]
PuppetLint.configuration.ignore_paths = exclude_paths
PuppetSyntax.exclude_paths = exclude_paths

desc "Run syntax, lint, and spec tests."
task :test => [
  :syntax,
  :lint,
  :spec,
]
# == Class: erlang
#
# Module to install an up-to-date version of Erlang from the
# official repositories
#
# === Parameters
# [*version*]
#   The package version to install, passed to ensure.
#   Defaults to present.
#
class erlang (
  $epel_enable              = $erlang::params::epel_enable,
  $key_signature            = $erlang::params::key_signature,
  $local_repo_location      = $erlang::params::local_repo_location,
  $package_name             = $erlang::params::package_name,
  $remote_repo_location     = $erlang::params::remote_repo_location,
  $remote_repo_key_location = $erlang::params::remote_repo_key_location,
  $repos                    = $erlang::params::repos,
  $version                  = 'present',
) inherits erlang::params {
  validate_string($version)

  case $::osfamily {
    'Debian' : {
      include '::apt'
      include '::erlang::repo::apt'
    }
    'RedHat' : {
      if $epel_enable {
        # Include epel as this is a requirement for erlang in RHEL6.
        include '::epel'
        Class['epel'] -> Package[$package_name]
      }

      # This is only needed on RHEL5, RHEL6 has erlang in EPEL.
      if $::operatingsystemrelease =~ /^5/ {
        include '::erlang::repo::yum'
      }
    }
    default : {
    }
  }

  package { $package_name: ensure => $version, }
}
# == Class: erlang::params
#
# Default paramaters setting repository details for different
# operating systems
#
class erlang::params {
  $epel_enable = false

  case $::osfamily {
    'Debian' : {
      $key_signature            = 'D208507CA14F4FCA'
      $package_name             = 'erlang-nox'
      $remote_repo_key_location = 'http://packages.erlang-solutions.com/debian/erlang_solutions.asc'
      $remote_repo_location     = 'http://packages.erlang-solutions.com/debian'
      $repos                    = 'contrib'
    }
    'RedHat', 'SUSE', 'Archlinux' : {
      $package_name = 'erlang'

      if $::operatingsystemrelease =~ /^5/ {
        $local_repo_location  = '/etc/yum.repos.d/epel-erlang.repo'
        $remote_repo_location = 'http://repos.fedorapeople.org/repos/peter/erlang/epel-erlang.repo'
      }
    }
    default : {
      fail("The ${module_name} module is not supported on an ${::osfamily} based system.")
    }
  }
}
# == Class: erlang::repo::apt
#
# Install an apt package repository containing Erlang.
# All parameters have sane default values in erlang::params.
#
# === Parameters
# [*key_signature*]
#   The signature for the key used to sign packages in the repository.
#
# [*package_name*]
#   Name of the Erlang package in the specified repository.
#
# [*remote_repo_key_location*]
#   URL of the public key for the remote repository.
#
# [*remote_repo_location*]
#   URL of the remote debian repository.
#
# [*repos*]
#   Which of the standard repositories to install from the
#   remote repo. For instance main, contrib, restricted.
#
class erlang::repo::apt(
  $key_signature            = $erlang::key_signature,
  $package_name             = $erlang::package_name,
  $remote_repo_key_location = $erlang::remote_repo_key_location,
  $remote_repo_location     = $erlang::remote_repo_location,
  $repos                    = $erlang::repos,
) {

  Class['erlang::repo::apt'] -> Package<| title == $package_name |>

  apt::source { 'erlang':
    include_src => false,
    key         => $key_signature,
    key_source  => $remote_repo_key_location,
    location    => $remote_repo_location,
    repos       => $repos,
  }

}
# == Class: erlang::repo::yum
#
# Install a yum package repository containing Erlang.
# All parameters have sane default values in erlang::params.
#
# === Parameters
# [*local_repo_location*]
#   File system location to store the repository details
#
# [*package_name*]
#   Name of the Erlang package in the specified repository
#
# [*remote_repo_location*]
#   URL of the remote repository
#
class erlang::repo::yum (
  $local_repo_location  = $erlang::local_repo_location,
  $package_name         = $erlang::package_name,
  $remote_repo_location = $erlang::remote_repo_location,
) inherits erlang {

  Class['erlang::repo::yum'] -> Package<| title == $package_name |>

  exec { 'erlang-repo-download':
    command => "curl -o ${local_repo_location} ${remote_repo_location}",
    path    => '/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin',
    creates => $local_repo_location,
  }

}
require 'spec_helper'

describe 'erlang', :type => :class do


  context 'on Debian' do
    let(:facts) { {
      :osfamily => 'Debian',
      :lsbdistid => 'debian',
      :lsbdistcodename => 'squeeze'
    }}

    context 'with no parameters' do
      it { should compile.with_all_deps }
      it { should contain_package('erlang-nox').with_ensure('present') }
      it { should contain_apt__source('erlang').with(
        'key_source' => 'http://packages.erlang-solutions.com/debian/erlang_solutions.asc',
        'key'        => 'D208507CA14F4FCA'
        ) }
    end

    context 'with a custom version' do
      let(:params) { {'version' => 'absent' } }
      it { should contain_package('erlang-nox').with_ensure('absent') }
    end

    context 'with a custom package name' do
      let(:params) { {'package_name' => 'not-erlang' } }
      it { should contain_package('not-erlang').with_ensure('present') }
    end

    context 'with custom repository details' do
      let(:params) { {
          'key_signature'            => '1234ABCD',
          'repos'                    => 'main',
          'remote_repo_location'     => 'http://example.com/debian',
          'remote_repo_key_location' => 'http://example.com/debian/key.asc',
        } }
      it { should contain_apt__source('erlang').with(
        'location'   => 'http://example.com/debian',
        'key_source' => 'http://example.com/debian/key.asc',
        'key'        => '1234ABCD',
        'repos'      => 'main'
        ) }
    end

  end

  context 'on RedHat 5' do
    let(:facts) { {:osfamily => 'RedHat', :operatingsystemrelease => '5.9' } }

    context "epel enabled" do
      let(:params) {{ :epel_enable => true }}
      it { should contain_class('epel') }
    end

    context "epel disabled" do
      let(:params) {{ :epel_enable => false }}
      it { should_not contain_class('epel') }
    end

    context 'with no parameters' do
      it { should contain_package('erlang').with_ensure('present') }
      it { should contain_exec('erlang-repo-download').with(
        'command' => 'curl -o /etc/yum.repos.d/epel-erlang.repo http://repos.fedorapeople.org/repos/peter/erlang/epel-erlang.repo',
        'path'    => '/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin'
        )
      }
    end

    context 'with a custom repository' do
      let(:params) { {
          'local_repo_location'  => '/tmp/yum.repos.d/tmp.repo',
          'remote_repo_location' => 'http://example.com/fake.repo',
        } }

      it { should contain_exec('erlang-repo-download').with(
        'command' => 'curl -o /tmp/yum.repos.d/tmp.repo http://example.com/fake.repo'
        )
      }
    end

    context 'with a custom version' do
      let(:params) { {'version' => 'absent' } }
      it { should contain_package('erlang').with_ensure('absent') }
    end
  end

  context 'on RedHat 6' do
    let(:facts) { {:osfamily => 'RedHat', :operatingsystemrelease => '6.4' } }

    context "epel enabled" do
      let(:params) {{ :epel_enable => true }}
      it { should contain_class('epel') }
    end

    context "epel disabled" do
      let(:params) {{ :epel_enable => false }}
      it { should_not contain_class('epel') }
    end

    context 'with no parameters' do
      it { should contain_package('erlang').with_ensure('present') }
    end

    context 'with a custom version' do
      let(:params) { {'version' => 'absent' } }
      it { should contain_package('erlang').with_ensure('absent') }
    end
  end

  context 'on SUSE' do
    let(:facts) {{ :osfamily => 'SUSE', }}

    context 'with no parameters' do
      it { should contain_package('erlang').with_ensure('present') }
    end

    context 'with a custom version' do
      let(:params) { {'version' => 'absent' } }
      it { should contain_package('erlang').with_ensure('absent') }
    end
  end

  context 'on Archlinux' do
    let(:facts) {{ :osfamily => 'Archlinux', }}

    context 'with no parameters' do
      it { should contain_package('erlang').with_ensure('present') }
    end

    context 'with a custom version' do
      let(:params) { {'version' => 'absent' } }
      it { should contain_package('erlang').with_ensure('absent') }
    end
  end

end
require 'puppetlabs_spec_helper/module_spec_helper'
require 'rspec-system/spec_helper'
require 'rspec-system-puppet/helpers'

include RSpecSystemPuppet::Helpers

RSpec.configure do |c|
  proj_root = File.expand_path(File.join(File.dirname(__FILE__), '..'))
  c.tty = true
  c.include RSpecSystemPuppet::Helpers

  c.before :suite do
    puppet_install
    puppet_module_install(:source => proj_root, :module_name => 'erlang')
    shell('puppet module install puppetlabs-apt')
    shell('puppet module install stahnma-epel')
  end
end
require 'spec_helper_system'

describe 'The erlang puppet module' do
  it 'should run without errors' do
    pp = <<-EOS
      class { 'erlang':
        epel_enable => true
      }
    EOS

    puppet_apply(pp) do |r|
      r.exit_code.should == 2
      r.refresh
      r.exit_code.should be_zero
    end
  end

  it 'should install the erl binary into /usr/bin' do
    shell 'which erl' do |r|
      r.stdout.should =~ /\/usr\/bin\/erl/
      r.stderr.should be_empty
      r.exit_code.should be_zero
    end
  end
end
fixtures:
  symlinks:
    "firewall": "#{source_dir}"
default_set: 'centos-64-x64'
sets:
  'centos-59-x64':
    nodes:
      "main.foo.vm":
        prefab: 'centos-59-x64'
  'centos-64-x64':
    nodes:
      "main.foo.vm":
        prefab: 'centos-64-x64'
  'fedora-18-x64':
    nodes:
      "main.foo.vm":
        prefab: 'fedora-18-x64'
  'debian-607-x64':
    nodes:
      "main.foo.vm":
        prefab: 'debian-607-x64'
  'debian-70rc1-x64':
    nodes:
      "main.foo.vm":
        prefab: 'debian-70rc1-x64'
  'ubuntu-server-10044-x64':
    nodes:
      "main.foo.vm":
        prefab: 'ubuntu-server-10044-x64'
  'ubuntu-server-12042-x64':
    nodes:
      "main.foo.vm":
        prefab: 'ubuntu-server-12042-x64'
language: ruby
bundler_args: --without development
script: "bundle exec rake ci SPEC_OPTS='--format documentation'"
rvm:
  - 1.8.7
  - 1.9.3
  - 2.0.0
env:
  - PUPPET_GEM_VERSION="~> 2.7.0"
  - PUPPET_GEM_VERSION="~> 3.0.0"
  - PUPPET_GEM_VERSION="~> 3.1.0"
  - PUPPET_GEM_VERSION="~> 3.2.0"
  - PUPPET_GEM_VERSION="~> 3.4.0"
matrix:
  fast_finish: true
  exclude:
    - rvm: 1.9.3
      env: PUPPET_GEM_VERSION="~> 2.7.0"
    - rvm: 2.0.0
      env: PUPPET_GEM_VERSION="~> 2.7.0"
    - rvm: 2.0.0
      env: PUPPET_GEM_VERSION="~> 3.0.0"
    - rvm: 2.0.0
      env: PUPPET_GEM_VERSION="~> 3.1.0"
    - rvm: 1.8.7
      env: PUPPET_GEM_VERSION="~> 3.2.0"
notifications:
  email: false
## 2014-05-16 Release 1.1.1
###Summary

This release reverts the alphabetical ordering of 1.1.0.  We found this caused
a regression in the Openstack modules so in the interest of safety we have
removed this for now.

## 2014-05-13 Release 1.1.0
###Summary

This release has a significant change from previous releases; we now apply the
firewall resources alphabetically by default, removing the need to create pre
and post classes just to enforce ordering.  It only effects default ordering
and further information can be found in the README about this.  Please test
this in development before rolling into production out of an abundance of
caution.

We've also added `mask` which is required for --recent in recent (no pun
intended) versions of iptables, as well as connlimit and connmark.  This
release has been validated against Ubuntu 14.04 and RHEL7 and should be fully
working on those platforms.

####Features

- Apply firewall resources alphabetically. 
- Add support for connlimit and connmark.
- Add `mask` as a parameter. (Used exclusively with the recent parameter).

####Bugfixes

- Add systemd support for RHEL7.
- Replace &&'s with the correct and in manifests.
- Fix tests on Trusty and RHEL7
- Fix for Fedora Rawhide.
- Fix boolean flag tests.
- Fix DNAT->SNAT typo in an error message.

####Known Bugs

* For Oracle, the `owner` and `socket` parameters require a workaround to function. Please see the Limitations section of the README.


## 2014-03-04 Supported Release 1.0.2
###Summary

This is a supported release.  This release removes a testing symlink that can
cause trouble on systems where /var is on a seperate filesystem from the
modulepath.

####Features
####Bugfixes
####Known Bugs

* For Oracle, the `owner` and `socket` parameters require a workaround to function. Please see the Limitations section of the README.

### Supported release - 2014-03-04 1.0.1

####Summary

An important bugfix was made to the offset calculation for unmanaged rules
to handle rules with 9000+ in the name.

####Features

####Bugfixes
- Offset calculations assumed unmanaged rules were numbered 9000+.
- Gracefully fail to manage ip6tables on iptables 1.3.x

####Known Bugs

* For Oracle, the `owner` and `socket` parameters require a workaround to function. Please see the Limitations section of the README.

### 1.0.0 - 2014-02-11

No changes, just renumbering to 1.0.0.

### 0.5.0 - 2014-02-10

##### Summary:
This is a bigger release that brings in "recent" connection limiting (think
"port knocking"), firewall chain purging on a per-chain/per-table basis, and
support for a few other use cases. This release also fixes a major bug which
could cause modifications to the wrong rules when unmanaged rules are present.

##### New Features:
* Add "recent" limiting via parameters `rdest`, `reap`, `recent`, `rhitcount`,
  `rname`, `rseconds`, `rsource`, and `rttl`
* Add negation support for source and destination
* Add per-chain/table purging support to `firewallchain`
* IPv4 specific
  * Add random port forwarding support
  * Add ipsec policy matching via `ipsec_dir` and `ipsec_policy`
* IPv6 specific
  * Add support for hop limiting via `hop_limit` parameter
  * Add fragmentation matchers via `ishasmorefrags`, `islastfrag`, and `isfirstfrag`
  * Add support for conntrack stateful firewall matching via `ctstate`

##### Bugfixes:
- Boolean fixups allowing false values
- Better detection of unmanaged rules
- Fix multiport rule detection
- Fix sport/dport rule detection
- Make INPUT, OUTPUT, and FORWARD not autorequired for firewall chain filter
- Allow INPUT with the nat table
- Fix `src_range` & `dst_range` order detection
- Documentation clarifications
- Fixes to spec tests


### 0.4.2 - 2013-09-10

Another attempt to fix the packaging issue.  We think we understand exactly
what is failing and this should work properly for the first time.


### 0.4.1 - 2013-08-09

Bugfix release to fix a packaging issue that may have caused puppet module
install commands to fail.


### 0.4.0 - 2013-07-11

This release adds support for address type, src/dest ip ranges, and adds
additional testing and bugfixes.

#### Features
* Add `src_type` and `dst_type` attributes (Nick Stenning)
* Add `src_range` and `dst_range` attributes (Lei Zhang)
* Add SL and SLC operatingsystems as supported (Steve Traylen)

#### Bugfixes
* Fix parser for bursts other than 5 (Chris Rutter)
* Fix parser for -f in --comment (Georg Koester)
* Add doc headers to class files (Dan Carley)
* Fix lint warnings/errors (Wolf Noble)


### 0.3.1 - 2013/6/10

This minor release provides some bugfixes and additional tests.

#### Changes

* Update tests for rspec-system-puppet 2 (Ken Barber)
* Update rspec-system tests for rspec-system-puppet 1.5 (Ken Barber)
* Ensure all services have 'hasstatus => true' for Puppet 2.6 (Ken Barber)
* Accept pre-existing rule with invalid name (Joe Julian)
* Swap log_prefix and log_level order to match the way it's saved (Ken Barber)
* Fix log test to replicate bug #182 (Ken Barber)
* Split argments while maintaining quoted strings (Joe Julian)
* Add more log param tests (Ken Barber)
* Add extra tests for logging parameters (Ken Barber)
* Clarify OS support (Ken Barber)


### 0.3.0 - 2013/4/25

This release introduces support for Arch Linux and extends support for Fedora 15 and up. There are also lots of bugs fixed and improved testing to prevent regressions.

##### Changes

* Fix error reporting for insane hostnames (Tomas Doran)
* Support systemd on Fedora 15 and up (Eduardo Gutierrez)
* Move examples to docs (Ken Barber)
* Add support for Arch Linux platform (Ingmar Steen)
* Add match rule for fragments (Georg Koester)
* Fix boolean rules being recognized as changed (Georg Koester)
* Same rules now get deleted (Anastasis Andronidis)
* Socket params test (Ken Barber)
* Ensure parameter can disable firewall (Marc Tardif)


### 0.2.1 - 2012/3/13

This maintenance release introduces the new README layout, and fixes a bug with iptables_persistent_version.

##### Changes

* (GH-139) Throw away STDERR from dpkg-query in Fact
* Update README to be consistent with module documentation template
* Fix failing spec tests due to dpkg change in iptables_persistent_version


### 0.2.0 - 2012/3/3

This release introduces automatic persistence, removing the need for the previous manual dependency requirement for persistent the running rules to the OS persistence file.

Previously you would have required the following in your site.pp (or some other global location):

    # Always persist firewall rules
    exec { 'persist-firewall':
      command     => $operatingsystem ? {
        'debian'          => '/sbin/iptables-save > /etc/iptables/rules.v4',
        /(RedHat|CentOS)/ => '/sbin/iptables-save > /etc/sysconfig/iptables',
      },
      refreshonly => true,
    }
    Firewall {
      notify  => Exec['persist-firewall'],
      before  => Class['my_fw::post'],
      require => Class['my_fw::pre'],
    }
    Firewallchain {
      notify  => Exec['persist-firewall'],
    }
    resources { "firewall":
      purge => true
    }

You only need:

    class { 'firewall': }
    Firewall {
      before  => Class['my_fw::post'],
      require => Class['my_fw::pre'],
    }

To install pre-requisites and to create dependencies on your pre & post rules. Consult the README for more information.

##### Changes

* Firewall class manifests (Dan Carley)
* Firewall and firewallchain persistence (Dan Carley)
* (GH-134) Autorequire iptables related packages (Dan Carley)
* Typo in #persist_iptables OS normalisation (Dan Carley)
* Tests for #persist_iptables (Dan Carley)
* (GH-129) Replace errant return in autoreq block (Dan Carley)


### 0.1.1 - 2012/2/28

This release primarily fixes changing parameters in 3.x

##### Changes

* (GH-128) Change method_missing usage to define_method for 3.x compatibility
* Update travis.yml gem specifications to actually test 2.6
* Change source in Gemfile to use a specific URL for Ruby 2.0.0 compatibility


### 0.1.0 - 2012/2/24

This release is somewhat belated, so no summary as there are far too many changes this time around. Hopefully we won't fall this far behind again :-).

##### Changes

* Add support for MARK target and set-mark property (Johan Huysmans)
* Fix broken call to super for ruby-1.9.2 in munge (Ken Barber)
* simple fix of the error message for allowed values of the jump property (Daniel Black)
* Adding OSPF(v3) protocol to puppetlabs-firewall (Arnoud Vermeer)
* Display multi-value: port, sport, dport and state command seperated (Daniel Black)
* Require jump=>LOG for log params (Daniel Black)
* Reject and document icmp => "any" (Dan Carley)
* add firewallchain type and iptables_chain provider (Daniel Black)
* Various fixes for firewallchain resource (Ken Barber)
* Modify firewallchain name to be chain:table:protocol (Ken Barber)
* Fix allvalidchain iteration (Ken Barber)
* Firewall autorequire Firewallchains (Dan Carley)
* Tests and docstring for chain autorequire (Dan Carley)
* Fix README so setup instructions actually work (Ken Barber)
* Support vlan interfaces (interface containing ".") (Johan Huysmans)
* Add tests for VLAN support for iniface/outiface (Ken Barber)
* Add the table when deleting rules (Johan Huysmans)
* Fix tests since we are now prefixing -t)
* Changed 'jump' to 'action', commands to lower case (Jason Short)
* Support interface names containing "+" (Simon Deziel)
* Fix for when iptables-save spews out "FATAL" errors (Sharif Nassar)
* Fix for incorrect limit command arguments for ip6tables provider (Michael Hsu)
* Document Util::Firewall.host_to_ip (Dan Carley)
* Nullify addresses with zero prefixlen (Dan Carley)
* Add support for --tcp-flags (Thomas Vander Stichele)
* Make tcp_flags support a feature (Ken Barber)
* OUTPUT is a valid chain for the mangle table (Adam Gibbins)
* Enable travis-ci support (Ken Barber)
* Convert an existing test to CIDR (Dan Carley)
* Normalise iptables-save to CIDR (Dan Carley)
* be clearer about what distributions we support (Ken Barber)
* add gre protocol to list of acceptable protocols (Jason Hancock)
* Added pkttype property (Ashley Penney)
* Fix mark to not repeat rules with iptables 1.4.1+ (Sharif Nassar)
* Stub iptables_version for now so tests run on non-Linux hosts (Ken Barber)
* Stub iptables facts for set_mark tests (Dan Carley)
* Update formatting of README to meet Puppet Labs best practices (Will Hopper)
* Support for ICMP6 type code resolutions (Dan Carley)
* Insert order hash included chains from different tables (Ken Barber)
* rspec 2.11 compatibility (Jonathan Boyett)
* Add missing class declaration in README (sfozz)
* array_matching is contraindicated (Sharif Nassar)
* Convert port Fixnum into strings (Sharif Nassar)
* Update test framework to the modern age (Ken Barber)
* working with ip6tables support (wuwx)
* Remove gemfile.lock and add to gitignore (William Van Hevelingen)
* Update travis and gemfile to be like stdlib travis files (William Van Hevelingen)
* Add support for -m socket option (Ken Barber)
* Add support for single --sport and --dport parsing (Ken Barber)
* Fix tests for Ruby 1.9.3 from 3e13bf3 (Dan Carley)
* Mock Resolv.getaddress in #host_to_ip (Dan Carley)
* Update docs for source and dest - they are not arrays (Ken Barber)


### 0.0.4 - 2011/12/05

This release adds two new parameters, 'uid' and 'gid'. As a part of the owner module, these params allow you to specify a uid, username, gid, or group got a match:

    firewall { '497 match uid':
      port => '123',
      proto => 'mangle',
      chain => 'OUTPUT',
      action => 'drop'
      uid => '123'
    }

This release also adds value munging for the 'log_level', 'source', and 'destination' parameters. The 'source' and 'destination' now support hostnames:

    firewall { '498 accept from puppetlabs.com':
      port => '123',
      proto => 'tcp',
      source => 'puppetlabs.com',
      action => 'accept'
    }


The 'log_level' parameter now supports using log level names, such as 'warn', 'debug', and 'panic':

    firewall { '499 logging':
      port => '123',
      proto => 'udp',
      log_level => 'debug',
      action => 'drop'
    }

Additional changes include iptables and ip6tables version facts, general whitespace cleanup, and adding additional unit tests.

##### Changes

* (#10957) add iptables_version and ip6tables_version facts
* (#11093) Improve log_level property so it converts names to numbers
* (#10723) Munge hostnames and IPs to IPs with CIDR
* (#10718) Add owner-match support
* (#10997) Add fixtures for ipencap
* (#11034) Whitespace cleanup
* (#10690) add port property support to ip6tables


### 0.0.3 - 2011/11/12

This release introduces a new parameter 'port' which allows you to set both
source and destination ports for a match:

    firewall { "500 allow NTP requests":
      port => "123",
      proto => "udp",
      action => "accept",
    }

We also have the limit parameter finally working:

    firewall { "500 limit HTTP requests":
      dport => 80,
      proto => tcp,
      limit => "60/sec",
      burst => 30,
      action => accept,
    }

State ordering has been fixed now, and more characters are allowed in the
namevar:

* Alphabetical
* Numbers
* Punctuation
* Whitespace

##### Changes

* (#10693) Ensure -m limit is added for iptables when using 'limit' param
* (#10690) Create new port property
* (#10700) allow additional characters in comment string
* (#9082) Sort iptables --state option values internally to keep it consistent across runs
* (#10324) Remove extraneous whitespace from iptables rule line in spec tests


### 0.0.2 - 2011/10/26

This is largely a maintanence and cleanup release, but includes the ability to
specify ranges of ports in the sport/dport parameter:

    firewall { "500 allow port range":
      dport => ["3000-3030","5000-5050"],
      sport => ["1024-65535"],
      action => "accept",
    }

##### Changes

* (#10295) Work around bug #4248 whereby the puppet/util paths are not being loaded correctly on the puppetmaster
* (#10002) Change to dport and sport to handle ranges, and fix handling of name to name to port
* (#10263) Fix tests on Puppet 2.6.x
* (#10163) Cleanup some of the inline documentation and README file to align with general forge usage


### 0.0.1 - 2011/10/18

Initial release.

##### Changes

* (#9362) Create action property and perform transformation for accept, drop, reject value for iptables jump parameter
* (#10088) Provide a customised version of CONTRIBUTING.md
* (#10026) Re-arrange provider and type spec files to align with Puppet
* (#10026) Add aliases for test,specs,tests to Rakefile and provide -T as default
* (#9439) fix parsing and deleting existing rules
* (#9583) Fix provider detection for gentoo and unsupported linuxes for the iptables provider
* (#9576) Stub provider so it works properly outside of Linux
* (#9576) Align spec framework with Puppet core
* and lots of other earlier development tasks ...
# How to contribute

Third-party patches are essential for keeping puppet great. We simply can't
access the huge number of platforms and myriad configurations for running
puppet. We want to keep it as easy as possible to contribute changes that
get things working in your environment. There are a few guidelines that we
need contributors to follow so that we can have a chance of keeping on
top of things.

## Getting Started

* Make sure you have a [Jira account](http://tickets.puppetlabs.com)
* Make sure you have a [GitHub account](https://github.com/signup/free)
* Submit a ticket for your issue, assuming one does not already exist.
  * Clearly describe the issue including steps to reproduce when it is a bug.
  * Make sure you fill in the earliest version that you know has the issue.
* Fork the repository on GitHub

## Making Changes

* Create a topic branch from where you want to base your work.
  * This is usually the master branch.
  * Only target release branches if you are certain your fix must be on that
    branch.
  * To quickly create a topic branch based on master; `git branch
    fix/master/my_contribution master` then checkout the new branch with `git
    checkout fix/master/my_contribution`.  Please avoid working directly on the
    `master` branch.
* Make commits of logical units.
* Check for unnecessary whitespace with `git diff --check` before committing.
* Make sure your commit messages are in the proper format.

````
    (MODULES-1234) Make the example in CONTRIBUTING imperative and concrete

    Without this patch applied the example commit message in the CONTRIBUTING
    document is not a concrete example.  This is a problem because the
    contributor is left to imagine what the commit message should look like
    based on a description rather than an example.  This patch fixes the
    problem by making the example concrete and imperative.

    The first line is a real life imperative statement with a ticket number
    from our issue tracker.  The body describes the behavior without the patch,
    why this is a problem, and how the patch fixes the problem when applied.
````

* Make sure you have added the necessary tests for your changes.
* Run _all_ the tests to assure nothing else was accidentally broken.

## Making Trivial Changes

### Documentation

For changes of a trivial nature to comments and documentation, it is not
always necessary to create a new ticket in Jira. In this case, it is
appropriate to start the first line of a commit with '(doc)' instead of
a ticket number. 

````
    (doc) Add documentation commit example to CONTRIBUTING

    There is no example for contributing a documentation commit
    to the Puppet repository. This is a problem because the contributor
    is left to assume how a commit of this nature may appear.

    The first line is a real life imperative statement with '(doc)' in
    place of what would have been the ticket number in a 
    non-documentation related commit. The body describes the nature of
    the new documentation or comments added.
````

## Submitting Changes

* Sign the [Contributor License Agreement](http://links.puppetlabs.com/cla).
* Push your changes to a topic branch in your fork of the repository.
* Submit a pull request to the repository in the puppetlabs organization.
* Update your Jira ticket to mark that you have submitted code and are ready for it to be reviewed (Status: Ready for Merge).
  * Include a link to the pull request in the ticket.

# Additional Resources

* [More information on contributing](http://projects.puppetlabs.com/projects/module-site/wiki/Module_contributing)
* [Bug tracker (Jira)](http://tickets.puppetlabs.com)
* [Contributor License Agreement](http://links.puppetlabs.com/cla)
* [General GitHub documentation](http://help.github.com/)
* [GitHub pull request documentation](http://help.github.com/send-pull-requests/)
* #puppet-dev IRC channel on freenode.org
source ENV['GEM_SOURCE'] || "https://rubygems.org"

group :development, :test do
  gem 'puppetlabs_spec_helper', :require => false
  gem 'rspec-puppet',           :require => false
  gem 'serverspec',             :require => false
  gem 'beaker-rspec',           :require => false
  gem 'puppet-lint',            :require => false
  gem 'pry',                    :require => false
end

if puppetversion = ENV['PUPPET_GEM_VERSION']
  gem 'puppet', puppetversion, :require => false
else
  gem 'puppet', :require => false
end

# vim:ft=ruby
Puppet Firewall Module - Puppet module for managing Firewalls

Copyright (C) 2011-2013 Puppet Labs, Inc.
Copyright (C) 2011 Jonathan Boyett
Copyright (C) 2011 Media Temple, Inc.

Some of the iptables code was taken from puppet-iptables which was:

Copyright (C) 2011 Bob.sh Limited
Copyright (C) 2008 Camptocamp Association
Copyright (C) 2007 Dmitri Priimak

Puppet Labs can be contacted at: info@puppetlabs.com

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
name 'puppetlabs-firewall'
version '1.1.1'
source 'git://github.com/puppetlabs/puppetlabs-firewall.git'
author 'puppetlabs'
license 'ASL 2.0'
summary 'Firewall Module'
description 'Manages Firewalls such as iptables'
project_page 'http://forge.puppetlabs.com/puppetlabs/firewall'
#firewall

[![Build Status](https://travis-ci.org/puppetlabs/puppetlabs-firewall.png?branch=master)](https://travis-ci.org/puppetlabs/puppetlabs-firewall)

####Table of Contents

1. [Overview - What is the Firewall module?](#overview)
2. [Module Description - What does the module do?](#module-description)
3. [Setup - The basics of getting started with Firewall](#setup)
    * [What Firewall affects](#what-firewall-affects)
    * [Setup Requirements](#setup-requirements)
    * [Beginning with Firewall](#beginning-with-firewall)
    * [Upgrading](#upgrading)
4. [Usage - Configuration and customization options](#usage)
    * [Default rules - Setting up general configurations for all firewalls](#default-rules)
    * [Application-specific rules - Options for configuring and managing firewalls across applications](#application-specific-rules)
    * [Other Rules](#other-rules)
5. [Reference - An under-the-hood peek at what the module is doing](#reference)
6. [Limitations - OS compatibility, etc.](#limitations)
7. [Development - Guide for contributing to the module](#development)
    * [Tests - Testing your configuration](#tests)

##Overview

The Firewall module lets you manage firewall rules with Puppet.

##Module Description

PuppetLabs' Firewall introduces the resource `firewall`, which is used to manage and configure firewall rules from within the Puppet DSL. This module offers support for iptables, ip6tables, and ebtables.

The module also introduces the resource `firewallchain`, which allows you to manage chains or firewall lists. At the moment, only iptables and ip6tables chains are supported.

##Setup

###What Firewall affects:

* every node running a firewall
* system's firewall settings
* connection settings for managed nodes
* unmanaged resources (get purged)
* site.pp

###Setup Requirements

Firewall uses Ruby-based providers, so you must have [pluginsync enabled](http://docs.puppetlabs.com/guides/plugins_in_modules.html#enabling-pluginsync).

###Beginning with Firewall

To begin, you need to provide some initial top-scope configuration to ensure your firewall configurations are ordered properly and you do not lock yourself out of your box or lose any configuration.

Persistence of rules between reboots is handled automatically, although there are known issues with ip6tables on older Debian/Ubuntu, as well as known issues with ebtables.

In your `site.pp` (or some similarly top-scope file), set up a metatype to purge unmanaged firewall resources. This will clear any existing rules and make sure that only rules defined in Puppet exist on the machine.

    resources { "firewall":
      purge => true
    }

Next, set up the default parameters for all of the firewall rules you will be establishing later. These defaults will ensure that the pre and post classes (you will be setting up in just a moment) are run in the correct order to avoid locking you out of your box during the first puppet run.

    Firewall {
      before  => Class['my_fw::post'],
      require => Class['my_fw::pre'],
    }

You also need to declare the `my_fw::pre` & `my_fw::post` classes so that dependencies are satisfied. This can be achieved using an External Node Classifier or the following

    class { ['my_fw::pre', 'my_fw::post']: }

Finally, you should include the `firewall` class to ensure the correct packages are installed.

    class { 'firewall': }

Now to create the `my_fw::pre` and `my_fw::post` classes. Firewall acts on your running firewall, making immediate changes as the catalog executes. Defining default pre and post rules allows you provide global defaults for your hosts before and after any custom rules; it is also required to avoid locking yourself out of your own boxes when Puppet runs. This approach employs a whitelist setup, so you can define what rules you want and everything else is ignored rather than removed.

The `pre` class should be located in `my_fw/manifests/pre.pp` and should contain any default rules to be applied first.

    class my_fw::pre {
      Firewall {
        require => undef,
      }

      # Default firewall rules
      firewall { '000 accept all icmp':
        proto   => 'icmp',
        action  => 'accept',
      }->
      firewall { '001 accept all to lo interface':
        proto   => 'all',
        iniface => 'lo',
        action  => 'accept',
      }->
      firewall { '002 accept related established rules':
        proto   => 'all',
        state => ['RELATED', 'ESTABLISHED'],
        action  => 'accept',
      }
    }

The rules in `pre` should allow basic networking (such as ICMP and TCP), as well as ensure that existing connections are not closed.

The `post` class should be located in `my_fw/manifests/post.pp` and include any default rules to be applied last.

    class my_fw::post {
      firewall { '999 drop all':
        proto   => 'all',
        action  => 'drop',
        before  => undef,
      }
    }

To put it all together: the `require` parameter in `Firewall {}` ensures `my_fw::pre` is run before any other rules and the `before` parameter ensures `my_fw::post` is run after any other rules. So the run order is:

* run the rules in `my_fw::pre`
* run your rules (defined in code)
* run the rules in `my_fw::post`

###Upgrading

####Upgrading from version 0.2.0 and newer

Upgrade the module with the puppet module tool as normal:

    puppet module upgrade puppetlabs/firewall

####Upgrading from version 0.1.1 and older

Start by upgrading the module using the puppet module tool:

    puppet module upgrade puppetlabs/firewall

Previously, you would have required the following in your `site.pp` (or some other global location):

    # Always persist firewall rules
    exec { 'persist-firewall':
      command     => $operatingsystem ? {
        'debian'          => '/sbin/iptables-save > /etc/iptables/rules.v4',
        /(RedHat|CentOS)/ => '/sbin/iptables-save > /etc/sysconfig/iptables',
      },
      refreshonly => true,
    }
    Firewall {
      notify  => Exec['persist-firewall'],
      before  => Class['my_fw::post'],
      require => Class['my_fw::pre'],
    }
    Firewallchain {
      notify  => Exec['persist-firewall'],
    }
    resources { "firewall":
      purge => true
    }

With the latest version, we now have in-built persistence, so this is no longer needed. However, you will still need some basic setup to define pre & post rules.

    resources { "firewall":
      purge => true
    }
    Firewall {
      before  => Class['my_fw::post'],
      require => Class['my_fw::pre'],
    }
    class { ['my_fw::pre', 'my_fw::post']: }
    class { 'firewall': }

Consult the the documentation below for more details around the classes `my_fw::pre` and `my_fw::post`.

##Usage

There are two kinds of firewall rules you can use with Firewall: default rules and application-specific rules. Default rules apply to general firewall settings, whereas application-specific rules manage firewall settings of a specific application, node, etc.

All rules employ a numbering system in the resource's title that is used for ordering. When titling your rules, make sure you prefix the rule with a number.

      000 this runs first
      999 this runs last

###Default rules

You can place default rules in either `my_fw::pre` or `my_fw::post`, depending on when you would like them to run. Rules placed in the `pre` class will run first, rules in the `post` class, last.

Depending on the provider, the title of the rule can be stored using the comment feature of the underlying firewall subsystem. Values can match `/^\d+[[:alpha:][:digit:][:punct:][:space:]]+$/`.

####Examples of default rules

Basic accept ICMP request example:

    firewall { "000 accept all icmp requests":
      proto  => "icmp",
      action => "accept",
    }

Drop all:

    firewall { "999 drop all other requests":
      action => "drop",
    }

###Application-specific rules

Puppet doesn't care where you define rules, and this means that you can place
your firewall resources as close to the applications and services that you
manage as you wish.  If you use the [roles and profiles
pattern](https://puppetlabs.com/learn/roles-profiles-introduction) then it
would make sense to create your firewall rules in the profiles, so that they
remain close to the services managed by the profile.

An example of this might be:

```puppet
class profile::apache {
  include apache
  apache::vhost { 'mysite': ensure => present }

  firewall { '100 allow http and https access':
    port   => [80, 443],
    proto  => tcp,
    action => accept,
  }
}
```


However, if you're not using that pattern then you can place them directly into
the individual module that manages a service, such as:

```puppet
class apache {
  firewall { '100 allow http and https access':
    port   => [80, 443],
    proto  => tcp,
    action => accept,
  }
  # ... the rest of your code ...
}
```

This means if someone includes either the profile:

```puppet
include profile::apache
```

Or the module, if you're not using roles and profiles:

```puppet
  include ::apache
```

Then they would automatically get appropriate firewall rules.

###Other rules

You can also apply firewall rules to specific nodes. Usually, you will want to put the firewall rule in another class and apply that class to a node. But you can apply a rule to a node.

    node 'foo.bar.com' {
      firewall { '111 open port 111':
        dport => 111
      }
    }

You can also do more complex things with the `firewall` resource. Here we are doing some NAT configuration.

    firewall { '100 snat for network foo2':
      chain    => 'POSTROUTING',
      jump     => 'MASQUERADE',
      proto    => 'all',
      outiface => "eth0",
      source   => '10.1.2.0/24',
      table    => 'nat',
    }

In the below example, we are creating a new chain and forwarding any port 5000 access to it.

    firewall { '100 forward to MY_CHAIN':
      chain   => 'INPUT',
      jump    => 'MY_CHAIN',
    }
    # The namevar here is in the format chain_name:table:protocol
    firewallchain { 'MY_CHAIN:filter:IPv4':
      ensure  => present,
    }
    firewall { '100 my rule':
      chain   => 'MY_CHAIN',
      action  => 'accept',
      proto   => 'tcp',
      dport   => 5000,
    }

###Additional Information

You can access the inline documentation:

    puppet describe firewall

Or

    puppet doc -r type
    (and search for firewall)

##Reference

Classes:

* [firewall](#class-firewall)

Types:

* [firewall](#type-firewall)
* [firewallchain](#type-firewallchain)

Facts:

* [ip6tables_version](#fact-ip6tablesversion)
* [iptables_version](#fact-iptablesversion)
* [iptables_persistent_version](#fact-iptablespersistentversion)

###Class: firewall

This class is provided to do the basic setup tasks required for using the firewall resources.

At the moment this takes care of:

* iptables-persistent package installation

You should include the class for nodes that need to use the resources in this module. For example

    class { 'firewall': }

####`ensure`

Indicates the state of `iptables` on your system, allowing you to disable `iptables` if desired.

Can either be `running` or `stopped`. Default to `running`.

###Type: firewall

This type provides the capability to manage firewall rules within puppet.

For more documentation on the type, access the 'Types' tab on the Puppet Labs Forge:

<http://forge.puppetlabs.com/puppetlabs/firewall#types>

###Type:: firewallchain

This type provides the capability to manage rule chains for firewalls.

For more documentation on the type, access the 'Types' tab on the Puppet Labs Forge:

<http://forge.puppetlabs.com/puppetlabs/firewall#types>

###Fact: ip6tables_version

The module provides a Facter fact that can be used to determine what the default version of ip6tables is for your operating system/distribution.

###Fact: iptables_version

The module provides a Facter fact that can be used to determine what the default version of iptables is for your operating system/distribution.

###Fact: iptables_persistent_version

Retrieves the version of iptables-persistent from your OS. This is a Debian/Ubuntu specific fact.

##Limitations

###SLES

The `socket` parameter is not supported on SLES.  In this release it will cause
the catalog to fail with iptables failures, rather than correctly warn you that
the features are unusable.

###Oracle Enterprise Linux

The `socket` and `owner` parameters are unsupported on Oracle Enterprise Linux
when the "Unbreakable" kernel is used. These may function correctly when using
the stock RedHat kernel instead. Declaring either of these parameters on an
unsupported system will result in iptable rules failing to apply.

###Other

Bugs can be reported using JIRA issues

<http://tickets.puppetlabs.com>

##Development

Puppet Labs modules on the Puppet Forge are open projects, and community contributions are essential for keeping them great. We can’t access the huge number of platforms and myriad of hardware, software, and deployment configurations that Puppet is intended to serve.

We want to keep it as easy as possible to contribute changes so that our modules work in your environment. There are a few guidelines that we need contributors to follow so that we can have a chance of keeping on top of things.

You can read the complete module contribution guide [on the Puppet Labs wiki.](http://projects.puppetlabs.com/projects/module-site/wiki/Module_contributing)

For this particular module, please also read CONTRIBUTING.md before contributing.

Currently we support:

* iptables
* ip6tables
* ebtables (chains only)

But plans are to support lots of other firewall implementations:

* FreeBSD (ipf)
* Mac OS X (ipfw)
* OpenBSD (pf)
* Cisco (ASA and basic access lists)

If you have knowledge in these technologies, know how to code, and wish to contribute to this project, we would welcome the help.

###Testing

Make sure you have:

* rake
* bundler

Install the necessary gems:

    bundle install

And run the tests from the root of the source code:

    rake test

If you have a copy of Vagrant 1.1.0 you can also run the system tests:

    RSPEC_SET=debian-606-x64 rake spec:system
    RSPEC_SET=centos-58-x64 rake spec:system

*Note:* system testing is fairly alpha at this point, your mileage may vary.
require 'puppetlabs_spec_helper/rake_tasks'

require 'puppet-lint/tasks/puppet-lint'
PuppetLint.configuration.ignore_paths = ['vendor/**/*.pp']

task :default do
  sh %{rake -T}
end

desc 'Run reasonably quick tests for CI'
task :ci => [
  :lint,
  :spec,
]
Facter.add(:ip6tables_version) do
  confine :kernel => :linux
  setcode do
    version = Facter::Util::Resolution.exec('ip6tables --version')
    if version
      version.match(/\d+\.\d+\.\d+/).to_s
    else
      nil
    end
  end
end
Facter.add(:iptables_persistent_version) do
  confine :operatingsystem => %w{Debian Ubuntu}
  setcode do
    # Throw away STDERR because dpkg >= 1.16.7 will make some noise if the
    # package isn't currently installed.
    cmd = "dpkg-query -Wf '${Version}' iptables-persistent 2>/dev/null"
    version = Facter::Util::Resolution.exec(cmd)

    if version.nil? or !version.match(/\d+\.\d+/)
      nil
    else
      version
    end
  end
end
Facter.add(:iptables_version) do
  confine :kernel => :linux
  setcode do
    version = Facter::Util::Resolution.exec('iptables --version')
    if version
      version.match(/\d+\.\d+\.\d+/).to_s
    else
      nil
    end
  end
end
class Puppet::Provider::Firewall < Puppet::Provider

  # Prefetch our rule list. This is ran once every time before any other
  # action (besides initialization of each object).
  def self.prefetch(resources)
    debug("[prefetch(resources)]")
    instances.each do |prov|
      if resource = resources[prov.name] || resources[prov.name.downcase]
        resource.provider = prov
      end
    end
  end

  # Look up the current status. This allows us to conventiently look up
  # existing status with properties[:foo].
  def properties
    if @property_hash.empty?
      @property_hash = query || {:ensure => :absent}
      @property_hash[:ensure] = :absent if @property_hash.empty?
    end
    @property_hash.dup
  end

  # Pull the current state of the list from the full list.  We're
  # getting some double entendre here....
  def query
    self.class.instances.each do |instance|
      if instance.name == self.name or instance.name.downcase == self.name
        return instance.properties
      end
    end
    nil
  end
end
Puppet::Type.type(:firewall).provide :ip6tables, :parent => :iptables, :source => :iptables do
  @doc = "Ip6tables type provider"

  has_feature :iptables
  has_feature :connection_limiting
  has_feature :hop_limiting
  has_feature :rate_limiting
  has_feature :recent_limiting
  has_feature :snat
  has_feature :dnat
  has_feature :interface_match
  has_feature :icmp_match
  has_feature :owner
  has_feature :state_match
  has_feature :reject_type
  has_feature :log_level
  has_feature :log_prefix
  has_feature :mark
  has_feature :tcp_flags
  has_feature :pkttype
  has_feature :ishasmorefrags
  has_feature :islastfrag
  has_feature :isfirstfrag

  optional_commands({
    :ip6tables      => 'ip6tables',
    :ip6tables_save => 'ip6tables-save',
  })

  def initialize(*args)
    if Facter.fact('ip6tables_version').value.match /1\.3\.\d/
      raise ArgumentError, 'The ip6tables provider is not supported on version 1.3 of iptables'
    else
      super
    end
  end

  def self.iptables(*args)
    ip6tables(*args)
  end

  def self.iptables_save(*args)
    ip6tables_save(*args)
  end

  @protocol = "IPv6"

  @resource_map = {
    :burst => "--limit-burst",
    :connlimit_above => "-m connlimit --connlimit-above",
    :connlimit_mask => "--connlimit-mask",
    :connmark => "-m connmark --mark",
    :ctstate => "-m conntrack --ctstate",
    :destination => "-d",
    :dport => "-m multiport --dports",
    :gid => "-m owner --gid-owner",
    :icmp => "-m icmp6 --icmpv6-type",
    :iniface => "-i",
    :jump => "-j",
    :hop_limit => "-m hl --hl-eq",
    :limit => "-m limit --limit",
    :log_level => "--log-level",
    :log_prefix => "--log-prefix",
    :name => "-m comment --comment",
    :outiface => "-o",
    :port => '-m multiport --ports',
    :proto => "-p",
    :rdest => "--rdest",
    :reap => "--reap",
    :recent => "-m recent",
    :reject => "--reject-with",
    :rhitcount => "--hitcount",
    :rname => "--name",
    :rseconds => "--seconds",
    :rsource => "--rsource",
    :rttl => "--rttl",
    :source => "-s",
    :state => "-m state --state",
    :sport => "-m multiport --sports",
    :table => "-t",
    :todest => "--to-destination",
    :toports => "--to-ports",
    :tosource => "--to-source",
    :uid => "-m owner --uid-owner",
    :pkttype => "-m pkttype --pkt-type",
    :ishasmorefrags => "-m frag --fragid 0 --fragmore",
    :islastfrag => "-m frag --fragid 0 --fraglast",
    :isfirstfrag => "-m frag --fragid 0 --fragfirst",
  }

  # These are known booleans that do not take a value, but we want to munge
  # to true if they exist.
  @known_booleans = [:ishasmorefrags, :islastfrag, :isfirstfrag, :rsource, :rdest, :reap, :rttl]

  # Create property methods dynamically
  (@resource_map.keys << :chain << :table << :action).each do |property|
    if @known_booleans.include?(property) then
      # The boolean properties default to '' which should be read as false
      define_method "#{property}" do
        @property_hash[property] = :false if @property_hash[property] == nil
        @property_hash[property.to_sym]
      end
    else
      define_method "#{property}" do
        @property_hash[property.to_sym]
      end
    end

    if property == :chain
      define_method "#{property}=" do |value|
        if @property_hash[:chain] != value
          raise ArgumentError, "Modifying the chain for existing rules is not supported."
        end
      end
    else
      define_method "#{property}=" do |value|
        @property_hash[:needs_change] = true
      end
    end
  end

  # This is the order of resources as they appear in iptables-save output,
  # we need it to properly parse and apply rules, if the order of resource
  # changes between puppet runs, the changed rules will be re-applied again.
  # This order can be determined by going through iptables source code or just tweaking and trying manually
  # (Note: on my CentOS 6.4 ip6tables-save returns -m frag on the place
  # I put it when calling the command. So compability with manual changes
  # not provided with current parser [georg.koester])
  @resource_list = [:table, :source, :destination, :iniface, :outiface,
    :proto, :ishasmorefrags, :islastfrag, :isfirstfrag, :gid, :uid, :sport, :dport,
    :port, :pkttype, :name, :state, :ctstate, :icmp, :hop_limit, :limit, :burst,
    :recent, :rseconds, :reap, :rhitcount, :rttl, :rname, :rsource, :rdest,
    :jump, :todest, :tosource, :toports, :log_level, :log_prefix, :reject,
    :connlimit_above, :connlimit_mask, :connmark]

end
require 'puppet/provider/firewall'
require 'digest/md5'

Puppet::Type.type(:firewall).provide :iptables, :parent => Puppet::Provider::Firewall do
  include Puppet::Util::Firewall

  @doc = "Iptables type provider"

  has_feature :iptables
  has_feature :connection_limiting
  has_feature :rate_limiting
  has_feature :recent_limiting
  has_feature :snat
  has_feature :dnat
  has_feature :interface_match
  has_feature :icmp_match
  has_feature :owner
  has_feature :state_match
  has_feature :reject_type
  has_feature :log_level
  has_feature :log_prefix
  has_feature :mark
  has_feature :tcp_flags
  has_feature :pkttype
  has_feature :isfragment
  has_feature :socket
  has_feature :address_type
  has_feature :iprange
  has_feature :ipsec_dir
  has_feature :ipsec_policy
  has_feature :mask

  optional_commands({
    :iptables => 'iptables',
    :iptables_save => 'iptables-save',
  })

  defaultfor :kernel => :linux

  iptables_version = Facter.fact('iptables_version').value
  if (iptables_version and Puppet::Util::Package.versioncmp(iptables_version, '1.4.1') < 0)
    mark_flag = '--set-mark'
  else
    mark_flag = '--set-xmark'
  end

  @protocol = "IPv4"

  @resource_map = {
    :burst           => "--limit-burst",
    :connlimit_above => "-m connlimit --connlimit-above",
    :connlimit_mask  => "--connlimit-mask",
    :connmark        => "-m connmark --mark",
    :ctstate         => "-m conntrack --ctstate",
    :destination     => "-d",
    :dst_type        => "-m addrtype --dst-type",
    :dst_range       => "-m iprange --dst-range",
    :dport           => ["-m multiport --dports", "--dport"],
    :gid             => "-m owner --gid-owner",
    :icmp            => "-m icmp --icmp-type",
    :iniface         => "-i",
    :jump            => "-j",
    :limit           => "-m limit --limit",
    :log_level       => "--log-level",
    :log_prefix      => "--log-prefix",
    :name            => "-m comment --comment",
    :outiface        => "-o",
    :port            => '-m multiport --ports',
    :proto           => "-p",
    :random          => "--random",
    :rdest           => "--rdest",
    :reap            => "--reap",
    :recent          => "-m recent",
    :reject          => "--reject-with",
    :rhitcount       => "--hitcount",
    :rname           => "--name",
    :rseconds        => "--seconds",
    :rsource         => "--rsource",
    :rttl            => "--rttl",
    :set_mark        => mark_flag,
    :socket          => "-m socket",
    :source          => "-s",
    :src_type        => "-m addrtype --src-type",
    :src_range       => "-m iprange --src-range",
    :sport           => ["-m multiport --sports", "--sport"],
    :state           => "-m state --state",
    :table           => "-t",
    :tcp_flags       => "-m tcp --tcp-flags",
    :todest          => "--to-destination",
    :toports         => "--to-ports",
    :tosource        => "--to-source",
    :uid             => "-m owner --uid-owner",
    :pkttype         => "-m pkttype --pkt-type",
    :isfragment      => "-f",
    :ipsec_dir       => "-m policy --dir",
    :ipsec_policy    => "--pol",
    :mask            => '--mask',
  }

  # These are known booleans that do not take a value, but we want to munge
  # to true if they exist.
  @known_booleans = [
    :isfragment,
    :random,
    :rdest,
    :reap,
    :rsource,
    :rttl,
    :socket
  ]


  # Create property methods dynamically
  (@resource_map.keys << :chain << :table << :action).each do |property|
    if @known_booleans.include?(property) then
      # The boolean properties default to '' which should be read as false
      define_method "#{property}" do
        @property_hash[property] = :false if @property_hash[property] == nil
        @property_hash[property.to_sym]
      end
    else
      define_method "#{property}" do
        @property_hash[property.to_sym]
      end
    end

    if property == :chain
      define_method "#{property}=" do |value|
        if @property_hash[:chain] != value
          raise ArgumentError, "Modifying the chain for existing rules is not supported."
        end
      end
    else
      define_method "#{property}=" do |value|
        @property_hash[:needs_change] = true
      end
    end
  end

  # This is the order of resources as they appear in iptables-save output,
  # we need it to properly parse and apply rules, if the order of resource
  # changes between puppet runs, the changed rules will be re-applied again.
  # This order can be determined by going through iptables source code or just tweaking and trying manually
  @resource_list = [
    :table, :source, :destination, :iniface, :outiface, :proto, :isfragment,
    :src_range, :dst_range, :tcp_flags, :gid, :uid, :sport, :dport, :port,
    :dst_type, :src_type, :socket, :pkttype, :name, :ipsec_dir, :ipsec_policy,
    :state, :ctstate, :icmp, :limit, :burst, :recent, :rseconds, :reap,
    :rhitcount, :rttl, :rname, :mask, :rsource, :rdest, :jump, :todest,
    :tosource, :toports, :random, :log_prefix, :log_level, :reject, :set_mark,
    :connlimit_above, :connlimit_mask, :connmark
  ]

  def insert
    debug 'Inserting rule %s' % resource[:name]
    iptables insert_args
  end

  def update
    debug 'Updating rule %s' % resource[:name]
    iptables update_args
  end

  def delete
    debug 'Deleting rule %s' % resource[:name]
    iptables delete_args
  end

  def exists?
    properties[:ensure] != :absent
  end

  # Flush the property hash once done.
  def flush
    debug("[flush]")
    if @property_hash.delete(:needs_change)
      notice("Properties changed - updating rule")
      update
    end
    persist_iptables(self.class.instance_variable_get(:@protocol))
    @property_hash.clear
  end

  def self.instances
    debug "[instances]"
    table = nil
    rules = []
    counter = 1

    # String#lines would be nice, but we need to support Ruby 1.8.5
    iptables_save.split("\n").each do |line|
      unless line =~ /^\#\s+|^\:\S+|^COMMIT|^FATAL/
        if line =~ /^\*/
          table = line.sub(/\*/, "")
        else
          if hash = rule_to_hash(line, table, counter)
            rules << new(hash)
            counter += 1
          end
        end
      end
    end
    rules
  end

  def self.rule_to_hash(line, table, counter)
    hash = {}
    keys = []
    values = line.dup

    ####################
    # PRE-PARSE CLUDGING
    ####################

    # --tcp-flags takes two values; we cheat by adding " around it
    # so it behaves like --comment
    values = values.sub(/--tcp-flags (\S*) (\S*)/, '--tcp-flags "\1 \2"')
    # we do a similar thing for negated address masks (source and destination).
    values = values.sub(/(-\S+) (!)\s?(\S*)/,'\1 "\2 \3"')
    # the actual rule will have the ! mark before the option.
    values = values.sub(/(!)\s*(-\S+)\s*(\S*)/, '\2 "\1 \3"')
    # The match extension for tcp & udp are optional and throws off the @resource_map.
    values = values.sub(/-m (tcp|udp) (--(s|d)port|-m multiport)/, '\2')

    # Trick the system for booleans
    @known_booleans.each do |bool|
      # append "true" because all params are expected to have values
      if bool == :isfragment then
        # -f requires special matching:
        # only replace those -f that are not followed by an l to
        # distinguish between -f and the '-f' inside of --tcp-flags.
        values = values.sub(/-f(?!l)(?=.*--comment)/, '-f true')
      else
        values = values.sub(/#{@resource_map[bool]}/, "#{@resource_map[bool]} true")
      end
    end

    ############
    # Populate parser_list with used value, in the correct order
    ############
    map_index={}
    @resource_map.each_pair do |map_k,map_v|
      [map_v].flatten.each do |v|
        ind=values.index(/\s#{v}/)
        next unless ind
        map_index[map_k]=ind
     end
    end
    # Generate parser_list based on the index of the found option
    parser_list=[]
    map_index.sort_by{|k,v| v}.each{|mapi| parser_list << mapi.first }

    ############
    # MAIN PARSE
    ############

    # Here we iterate across our values to generate an array of keys
    parser_list.reverse.each do |k|
      resource_map_key = @resource_map[k]
      [resource_map_key].flatten.each do |opt|
        if values.slice!(/\s#{opt}/)
          keys << k
          break
        end
      end
    end

    # Manually remove chain
    values.slice!('-A')
    keys << :chain

    # Here we generate the main hash
    keys.zip(values.scan(/"[^"]*"|\S+/).reverse) { |f, v| hash[f] = v.gsub(/"/, '') }

    #####################
    # POST PARSE CLUDGING
    #####################

    # Normalise all rules to CIDR notation.
    [:source, :destination].each do |prop|
      next if hash[prop].nil?
      m = hash[prop].match(/(!?)\s?(.*)/)
      neg = "! " if m[1] == "!"
      hash[prop] = "#{neg}#{Puppet::Util::IPCidr.new(m[2]).cidr}"
    end

    [:dport, :sport, :port, :state, :ctstate].each do |prop|
      hash[prop] = hash[prop].split(',') if ! hash[prop].nil?
    end

    # Convert booleans removing the previous cludge we did
    @known_booleans.each do |bool|
      if hash[bool] != nil then
        if hash[bool] != "true" then
          raise "Parser error: #{bool} was meant to be a boolean but received value: #{hash[bool]}."
        end
      end
    end

    # Our type prefers hyphens over colons for ranges so ...
    # Iterate across all ports replacing colons with hyphens so that ranges match
    # the types expectations.
    [:dport, :sport, :port].each do |prop|
      next unless hash[prop]
      hash[prop] = hash[prop].collect do |elem|
        elem.gsub(/:/,'-')
      end
    end

    # States should always be sorted. This ensures that the output from
    # iptables-save and user supplied resources is consistent.
    hash[:state]   = hash[:state].sort   unless hash[:state].nil?
    hash[:ctstate] = hash[:ctstate].sort unless hash[:ctstate].nil?

    # This forces all existing, commentless rules or rules with invalid comments to be moved 
    # to the bottom of the stack.
    # Puppet-firewall requires that all rules have comments (resource names) and match this 
    # regex and will fail if a rule in iptables does not have a comment. We get around this 
    # by appending a high level
    if ! hash[:name]
      num = 9000 + counter
      hash[:name] = "#{num} #{Digest::MD5.hexdigest(line)}"
    elsif not /^\d+[[:alpha:][:digit:][:punct:][:space:]]+$/ =~ hash[:name]
      num = 9000 + counter
      hash[:name] = "#{num} #{/([[:alpha:][:digit:][:punct:][:space:]]+)/.match(hash[:name])[1]}"
    end

    # Iptables defaults to log_level '4', so it is omitted from the output of iptables-save.
    # If the :jump value is LOG and you don't have a log-level set, we assume it to be '4'.
    if hash[:jump] == 'LOG' && ! hash[:log_level]
      hash[:log_level] = '4'
    end

    # Iptables defaults to burst '5', so it is ommitted from the output of iptables-save.
    # If the :limit value is set and you don't have a burst set, we assume it to be '5'.
    if hash[:limit] && ! hash[:burst]
      hash[:burst] = '5'
    end

    hash[:line] = line
    hash[:provider] = self.name.to_s
    hash[:table] = table
    hash[:ensure] = :present

    # Munge some vars here ...

    # Proto should equal 'all' if undefined
    hash[:proto] = "all" if !hash.include?(:proto)

    # If the jump parameter is set to one of: ACCEPT, REJECT or DROP then
    # we should set the action parameter instead.
    if ['ACCEPT','REJECT','DROP'].include?(hash[:jump]) then
      hash[:action] = hash[:jump].downcase
      hash.delete(:jump)
    end

    hash
  end

  def insert_args
    args = []
    args << ["-I", resource[:chain], insert_order]
    args << general_args
    args
  end

  def update_args
    args = []
    args << ["-R", resource[:chain], insert_order]
    args << general_args
    args
  end

  def delete_args
    # Split into arguments
    line = properties[:line].gsub(/\-A/, '-D').split(/\s(?=(?:[^"]|"[^"]*")*$)/).map{|v| v.gsub(/"/, '')}
    line.unshift("-t", properties[:table])
  end

  # This method takes the resource, and attempts to generate the command line
  # arguments for iptables.
  def general_args
    debug "Current resource: %s" % resource.class

    args = []
    resource_list = self.class.instance_variable_get('@resource_list')
    resource_map = self.class.instance_variable_get('@resource_map')
    known_booleans = self.class.instance_variable_get('@known_booleans')

    resource_list.each do |res|
      resource_value = nil
      if (resource[res]) then
        resource_value = resource[res]
        # If socket is true then do not add the value as -m socket is standalone
        if known_booleans.include?(res) then
          if resource[res] == :true then
            resource_value = nil
          else
            # If the property is not :true then we don't want to add the value
            # to the args list
            next
          end
        end
      elsif res == :jump and resource[:action] then
        # In this case, we are substituting jump for action
        resource_value = resource[:action].to_s.upcase
      else
        next
      end

      args << [resource_map[res]].flatten.first.split(' ')

      # On negations, the '!' has to be before the option (eg: "! -d 1.2.3.4")
      if resource_value.is_a?(String) and resource_value.sub!(/^!\s*/, '') then
        # we do this after adding the 'dash' argument because of ones like "-m multiport --dports", where we want it before the "--dports" but after "-m multiport".
        # so we insert before whatever the last argument is
        args.insert(-2, '!')
      end


      # For sport and dport, convert hyphens to colons since the type
      # expects hyphens for ranges of ports.
      if [:sport, :dport, :port].include?(res) then
        resource_value = resource_value.collect do |elem|
          elem.gsub(/-/, ':')
        end
      end

      # our tcp_flags takes a single string with comma lists separated
      # by space
      # --tcp-flags expects two arguments
      if res == :tcp_flags
        one, two = resource_value.split(' ')
        args << one
        args << two
      elsif resource_value.is_a?(Array)
        args << resource_value.join(',')
      elsif !resource_value.nil?
        args << resource_value
      end
    end

    args
  end

  def insert_order
    debug("[insert_order]")
    rules = []

    # Find list of current rules based on chain and table
    self.class.instances.each do |rule|
      if rule.chain == resource[:chain].to_s and rule.table == resource[:table].to_s
        rules << rule.name
      end
    end

    # No rules at all? Just bail now.
    return 1 if rules.empty?

    # Add our rule to the end of the array of known rules
    my_rule = resource[:name].to_s
    rules << my_rule

    unmanaged_rule_regex = /^9[0-9]{3}\s[a-f0-9]{32}$/
    # Find if this is a new rule or an existing rule, then find how many
    # unmanaged rules preceed it.
    if rules.length == rules.uniq.length
      # This is a new rule so find its ordered location.
      new_rule_location = rules.sort.uniq.index(my_rule)
      if new_rule_location == 0
        # The rule will be the first rule in the chain because nothing came
        # before it.
        offset_rule = rules[0]
      else
        # This rule will come after other managed rules, so find the rule
        # immediately preceeding it.
        offset_rule = rules.sort.uniq[new_rule_location - 1]
      end
    else
      # This is a pre-existing rule, so find the offset from the original
      # ordering.
      offset_rule = my_rule
    end
    # Count how many unmanaged rules are ahead of the target rule so we know
    # how much to add to the insert order
    unnamed_offset = rules[0..rules.index(offset_rule)].inject(0) do |sum,rule|
      # This regex matches the names given to unmanaged rules (a number
      # 9000-9999 followed by an MD5 hash).
      sum + (rule.match(unmanaged_rule_regex) ? 1 : 0)
    end

    # We want our rule to come before unmanaged rules if it's not a 9-rule
    if offset_rule.match(unmanaged_rule_regex) and ! my_rule.match(/^9/)
      unnamed_offset -= 1
    end

    # Insert our new or updated rule in the correct order of named rules, but
    # offset for unnamed rules.
    rules.reject{|r|r.match(unmanaged_rule_regex)}.sort.index(my_rule) + 1 + unnamed_offset
  end
end
Puppet::Type.type(:firewallchain).provide :iptables_chain do
  include Puppet::Util::Firewall

  @doc = "Iptables chain provider"

  has_feature :iptables_chain
  has_feature :policy

  optional_commands({
    :iptables       => 'iptables',
    :iptables_save  => 'iptables-save',
    :ip6tables      => 'ip6tables',
    :ip6tables_save => 'ip6tables-save',
    :ebtables       => 'ebtables',
    :ebtables_save  => 'ebtables-save',
  })

  defaultfor :kernel => :linux

  # chain name is greedy so we anchor from the end.
  # [\d+:\d+] doesn't exist on ebtables
  Mapping = {
    :IPv4 => {
      :tables => method(:iptables),
      :save   => method(:iptables_save),
      :re     => /^:(.+)\s(\S+)\s\[\d+:\d+\]$/,
    },
    :IPv6 => {
      :tables => method(:ip6tables),
      :save   => method(:ip6tables_save),
      :re     => /^:(.+)\s(\S+)\s\[\d+:\d+\]$/,
    },
    :ethernet => {
      :tables => method(:ebtables),
      :save   => method(:ebtables_save),
      :re     => /^:(.+)\s(\S+)$/,
    }
  }
  InternalChains = /^(PREROUTING|POSTROUTING|BROUTING|INPUT|FORWARD|OUTPUT)$/
  Tables = 'nat|mangle|filter|raw|rawpost|broute'
  Nameformat = /^(.+):(#{Tables}):(IP(v[46])?|ethernet)$/

  def create
    allvalidchains do |t, chain, table, protocol|
      if chain =~ InternalChains
        # can't create internal chains
        warning "Attempting to create internal chain #{@resource[:name]}"
      end
      if properties[:ensure] == protocol
        debug "Skipping Inserting chain #{chain} on table #{table} (#{protocol}) already exists"
      else
        debug "Inserting chain #{chain} on table #{table} (#{protocol}) using #{t}"
        t.call ['-t',table,'-N',chain]
        unless @resource[:policy].nil?
          t.call ['-t',table,'-P',chain,@resource[:policy].to_s.upcase]
        end
      end
    end
  end

  def destroy
    allvalidchains do |t, chain, table|
      if chain =~ InternalChains
        # can't delete internal chains
        warning "Attempting to destroy internal chain #{@resource[:name]}"
      end
      debug "Deleting chain #{chain} on table #{table}"
      t.call ['-t',table,'-X',chain]
    end
  end

  def exists?
    allvalidchains do |t, chain|
      if chain =~ InternalChains
        # If the chain isn't present, it's likely because the module isn't loaded.
        # If this is true, then we fall into 2 cases
        # 1) It'll be loaded on demand
        # 2) It won't be loaded on demand, and we throw an error
        #    This is the intended behavior as it's not the provider's job to load kernel modules
        # So we pretend it exists...
        return true
      end
    end
    properties[:ensure] == :present
  end

  def policy=(value)
    return if value == :empty
    allvalidchains do |t, chain, table|
      p = ['-t',table,'-P',chain,value.to_s.upcase]
      debug "[set policy] #{t} #{p}"
      t.call p
    end
  end

  def policy
    debug "[get policy] #{@resource[:name]} =#{@property_hash[:policy].to_s.downcase}"
    return @property_hash[:policy].to_s.downcase
  end

  def self.prefetch(resources)
    debug("[prefetch(resources)]")
    instances.each do |prov|
      if resource = resources[prov.name]
        resource.provider = prov
      end
    end
  end

  def flush
    debug("[flush]")
    persist_iptables(@resource[:name].match(Nameformat)[3])
    # Clear the property hash so we re-initialize with updated values
    @property_hash.clear
  end

  # Look up the current status. This allows us to conventiently look up
  # existing status with properties[:foo].
  def properties
    if @property_hash.empty?
      @property_hash = query || {:ensure => :absent}
    end
    @property_hash.dup
  end

  # Pull the current state of the list from the full list.
  def query
    self.class.instances.each do |instance|
      if instance.name == self.name
        debug "query found #{self.name}" % instance.properties.inspect
        return instance.properties
      end
    end
    nil
  end

  def self.instances
    debug "[instances]"
    table = nil
    chains = []

    Mapping.each { |p, c|
      begin
        c[:save].call.each_line do |line|
          if line =~ c[:re] then
            name = $1 + ':' + (table == 'filter' ? 'filter' : table) + ':' + p.to_s
            policy = $2 == '-' ? nil : $2.downcase.to_sym

            chains << new({
              :name   => name,
              :policy => policy,
              :ensure => :present,
            })

            debug "[instance] '#{name}' #{policy}"
          elsif line =~ /^\*(\S+)/
            table = $1
          else
            next
          end
        end
      rescue Puppet::Error
        # ignore command not found for ebtables or anything that doesn't exist
      end
    }

    chains
  end

  def allvalidchains
    @resource[:name].match(Nameformat)
    chain = $1
    table = $2
    protocol = $3
    yield Mapping[protocol.to_sym][:tables],chain,table,protocol.to_sym
  end

end
# See: #10295 for more details.
#
# This is a workaround for bug: #4248 whereby ruby files outside of the normal
# provider/type path do not load until pluginsync has occured on the puppetmaster
#
# In this case I'm trying the relative path first, then falling back to normal
# mechanisms. This should be fixed in future versions of puppet but it looks
# like we'll need to maintain this for some time perhaps.
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__),"..",".."))
require 'puppet/util/firewall'

Puppet::Type.newtype(:firewall) do
  include Puppet::Util::Firewall

  @doc = <<-EOS
    This type provides the capability to manage firewall rules within
    puppet.

    **Autorequires:**

    If Puppet is managing the iptables or ip6tables chains specified in the
    `chain` or `jump` parameters, the firewall resource will autorequire
    those firewallchain resources.

    If Puppet is managing the iptables or iptables-persistent packages, and
    the provider is iptables or ip6tables, the firewall resource will
    autorequire those packages to ensure that any required binaries are
    installed.
  EOS

  feature :connection_limiting, "Connection limiting features."
  feature :hop_limiting, "Hop limiting features."
  feature :rate_limiting, "Rate limiting features."
  feature :recent_limiting, "The netfilter recent module"
  feature :snat, "Source NATing"
  feature :dnat, "Destination NATing"
  feature :interface_match, "Interface matching"
  feature :icmp_match, "Matching ICMP types"
  feature :owner, "Matching owners"
  feature :state_match, "Matching stateful firewall states"
  feature :reject_type, "The ability to control reject messages"
  feature :log_level, "The ability to control the log level"
  feature :log_prefix, "The ability to add prefixes to log messages"
  feature :mark, "Match or Set the netfilter mark value associated with the packet"
  feature :tcp_flags, "The ability to match on particular TCP flag settings"
  feature :pkttype, "Match a packet type"
  feature :socket, "Match open sockets"
  feature :isfragment, "Match fragments"
  feature :address_type, "The ability match on source or destination address type"
  feature :iprange, "The ability match on source or destination IP range "
  feature :ishasmorefrags, "Match a non-last fragment of a fragmented ipv6 packet - might be first"
  feature :islastfrag, "Match the last fragment of an ipv6 packet"
  feature :isfirstfrag, "Match the first fragment of a fragmented ipv6 packet"
  feature :ipsec_policy, "Match IPsec policy"
  feature :ipsec_dir, "Match IPsec policy direction"

  # provider specific features
  feature :iptables, "The provider provides iptables features."

  ensurable do
    desc <<-EOS
      Manage the state of this rule. The default action is *present*.
    EOS

    newvalue(:present) do
      provider.insert
    end

    newvalue(:absent) do
      provider.delete
    end

    defaultto :present
  end

  newparam(:name) do
    desc <<-EOS
      The canonical name of the rule. This name is also used for ordering
      so make sure you prefix the rule with a number:

          000 this runs first
          999 this runs last

      Depending on the provider, the name of the rule can be stored using
      the comment feature of the underlying firewall subsystem.
    EOS
    isnamevar

    # Keep rule names simple - they must start with a number
    newvalues(/^\d+[[:alpha:][:digit:][:punct:][:space:]]+$/)
  end

  newproperty(:action) do
    desc <<-EOS
      This is the action to perform on a match. Can be one of:

      * accept - the packet is accepted
      * reject - the packet is rejected with a suitable ICMP response
      * drop - the packet is dropped

      If you specify no value it will simply match the rule but perform no
      action unless you provide a provider specific parameter (such as *jump*).
    EOS
    newvalues(:accept, :reject, :drop)
  end

  # Generic matching properties
  newproperty(:source) do
    desc <<-EOS
      The source address. For example:

          source => '192.168.2.0/24'

      You can also negate a mask by putting ! in front. For example:

          source => '! 192.168.2.0/24'

      The source can also be an IPv6 address if your provider supports it.
    EOS

    munge do |value|
      begin
        @resource.host_to_mask(value)
      rescue Exception => e
        self.fail("host_to_ip failed for #{value}, exception #{e}")
      end
    end
  end

  # Source IP range
  newproperty(:src_range, :required_features => :iprange) do
    desc <<-EOS
      The source IP range. For example:

          src_range => '192.168.1.1-192.168.1.10'

      The source IP range is must in 'IP1-IP2' format.
    EOS

    newvalues(/^((25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)\.){3}(25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)-((25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)\.){3}(25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)/)
  end

  newproperty(:destination) do
    desc <<-EOS
      The destination address to match. For example:

          destination => '192.168.1.0/24'

      You can also negate a mask by putting ! in front. For example:

          destination  => '! 192.168.2.0/24'

      The destination can also be an IPv6 address if your provider supports it.
    EOS

    munge do |value|
      begin
        @resource.host_to_mask(value)
      rescue Exception => e
        self.fail("host_to_ip failed for #{value}, exception #{e}")
      end
    end
  end

  # Destination IP range
  newproperty(:dst_range, :required_features => :iprange) do
    desc <<-EOS
      The destination IP range. For example:

          dst_range => '192.168.1.1-192.168.1.10'

      The destination IP range is must in 'IP1-IP2' format.
    EOS

    newvalues(/^((25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)\.){3}(25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)-((25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)\.){3}(25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)/)
  end

  newproperty(:sport, :array_matching => :all) do
    desc <<-EOS
      The source port to match for this filter (if the protocol supports
      ports). Will accept a single element or an array.

      For some firewall providers you can pass a range of ports in the format:

          <start_number>-<ending_number>

      For example:

          1-1024

      This would cover ports 1 to 1024.
    EOS

    munge do |value|
      @resource.string_to_port(value, :proto)
    end

    def is_to_s(value)
      should_to_s(value)
    end

    def should_to_s(value)
      value = [value] unless value.is_a?(Array)
      value.join(',')
    end
  end

  newproperty(:dport, :array_matching => :all) do
    desc <<-EOS
      The destination port to match for this filter (if the protocol supports
      ports). Will accept a single element or an array.

      For some firewall providers you can pass a range of ports in the format:

          <start_number>-<ending_number>

      For example:

          1-1024

      This would cover ports 1 to 1024.
    EOS

    munge do |value|
      @resource.string_to_port(value, :proto)
    end

    def is_to_s(value)
      should_to_s(value)
    end

    def should_to_s(value)
      value = [value] unless value.is_a?(Array)
      value.join(',')
    end
  end

  newproperty(:port, :array_matching => :all) do
    desc <<-EOS
      The destination or source port to match for this filter (if the protocol
      supports ports). Will accept a single element or an array.

      For some firewall providers you can pass a range of ports in the format:

          <start_number>-<ending_number>

      For example:

          1-1024

      This would cover ports 1 to 1024.
    EOS

    munge do |value|
      @resource.string_to_port(value, :proto)
    end

    def is_to_s(value)
      should_to_s(value)
    end

    def should_to_s(value)
      value = [value] unless value.is_a?(Array)
      value.join(',')
    end
  end

  newproperty(:dst_type, :required_features => :address_type) do
    desc <<-EOS
      The destination address type. For example:

          dst_type => 'LOCAL'

      Can be one of:

      * UNSPEC - an unspecified address
      * UNICAST - a unicast address
      * LOCAL - a local address
      * BROADCAST - a broadcast address
      * ANYCAST - an anycast packet
      * MULTICAST - a multicast address
      * BLACKHOLE - a blackhole address
      * UNREACHABLE - an unreachable address
      * PROHIBIT - a prohibited address
      * THROW - undocumented
      * NAT - undocumented
      * XRESOLVE - undocumented
    EOS

    newvalues(:UNSPEC, :UNICAST, :LOCAL, :BROADCAST, :ANYCAST, :MULTICAST,
              :BLACKHOLE, :UNREACHABLE, :PROHIBIT, :THROW, :NAT, :XRESOLVE)
  end

  newproperty(:src_type, :required_features => :address_type) do
    desc <<-EOS
      The source address type. For example:

          src_type => 'LOCAL'

      Can be one of:

      * UNSPEC - an unspecified address
      * UNICAST - a unicast address
      * LOCAL - a local address
      * BROADCAST - a broadcast address
      * ANYCAST - an anycast packet
      * MULTICAST - a multicast address
      * BLACKHOLE - a blackhole address
      * UNREACHABLE - an unreachable address
      * PROHIBIT - a prohibited address
      * THROW - undocumented
      * NAT - undocumented
      * XRESOLVE - undocumented
    EOS

    newvalues(:UNSPEC, :UNICAST, :LOCAL, :BROADCAST, :ANYCAST, :MULTICAST,
              :BLACKHOLE, :UNREACHABLE, :PROHIBIT, :THROW, :NAT, :XRESOLVE)
  end

  newproperty(:proto) do
    desc <<-EOS
      The specific protocol to match for this rule. By default this is
      *tcp*.
    EOS

    newvalues(:tcp, :udp, :icmp, :"ipv6-icmp", :esp, :ah, :vrrp, :igmp, :ipencap, :ospf, :gre, :all)
    defaultto "tcp"
  end

  # tcp-specific
  newproperty(:tcp_flags, :required_features => :tcp_flags) do
    desc <<-EOS
      Match when the TCP flags are as specified.
      Is a string with a list of comma-separated flag names for the mask,
      then a space, then a comma-separated list of flags that should be set.
      The flags are: SYN ACK FIN RST URG PSH ALL NONE
      Note that you specify them in the order that iptables --list-rules
      would list them to avoid having puppet think you changed the flags.
      Example: FIN,SYN,RST,ACK SYN matches packets with the SYN bit set and the
	       ACK,RST and FIN bits cleared.  Such packets are used to request
               TCP  connection initiation.
    EOS
  end


  # Iptables specific
  newproperty(:chain, :required_features => :iptables) do
    desc <<-EOS
      Name of the chain to use. Can be one of the built-ins:

      * INPUT
      * FORWARD
      * OUTPUT
      * PREROUTING
      * POSTROUTING

      Or you can provide a user-based chain.

      The default value is 'INPUT'.
    EOS

    defaultto "INPUT"
    newvalue(/^[a-zA-Z0-9\-_]+$/)
  end

  newproperty(:table, :required_features => :iptables) do
    desc <<-EOS
      Table to use. Can be one of:

      * nat
      * mangle
      * filter
      * raw
      * rawpost

      By default the setting is 'filter'.
    EOS

    newvalues(:nat, :mangle, :filter, :raw, :rawpost)
    defaultto "filter"
  end

  newproperty(:jump, :required_features => :iptables) do
    desc <<-EOS
      The value for the iptables --jump parameter. Normal values are:

      * QUEUE
      * RETURN
      * DNAT
      * SNAT
      * LOG
      * MASQUERADE
      * REDIRECT
      * MARK

      But any valid chain name is allowed.

      For the values ACCEPT, DROP and REJECT you must use the generic
      'action' parameter. This is to enfore the use of generic parameters where
      possible for maximum cross-platform modelling.

      If you set both 'accept' and 'jump' parameters, you will get an error as
      only one of the options should be set.
    EOS

    validate do |value|
      unless value =~ /^[a-zA-Z0-9\-_]+$/
        raise ArgumentError, <<-EOS
          Jump destination must consist of alphanumeric characters, an
          underscore or a yphen.
        EOS
      end

      if ["accept","reject","drop"].include?(value.downcase)
        raise ArgumentError, <<-EOS
          Jump destination should not be one of ACCEPT, REJECT or DROP. Use
          the action property instead.
        EOS
      end

    end
  end

  # Interface specific matching properties
  newproperty(:iniface, :required_features => :interface_match) do
    desc <<-EOS
      Input interface to filter on.
    EOS
    newvalues(/^[a-zA-Z0-9\-\._\+]+$/)
  end

  newproperty(:outiface, :required_features => :interface_match) do
    desc <<-EOS
      Output interface to filter on.
    EOS
    newvalues(/^[a-zA-Z0-9\-\._\+]+$/)
  end

  # NAT specific properties
  newproperty(:tosource, :required_features => :snat) do
    desc <<-EOS
      When using jump => "SNAT" you can specify the new source address using
      this parameter.
    EOS
  end

  newproperty(:todest, :required_features => :dnat) do
    desc <<-EOS
      When using jump => "DNAT" you can specify the new destination address
      using this paramter.
    EOS
  end

  newproperty(:toports, :required_features => :dnat) do
    desc <<-EOS
      For DNAT this is the port that will replace the destination port.
    EOS
  end

  newproperty(:random, :required_features => :dnat) do
    desc <<-EOS
      When using a jump value of "MASQUERADE", "DNAT", "REDIRECT", or "SNAT"
      this boolean will enable randomized port mapping.
    EOS

    newvalues(:true, :false)
  end

  # Reject ICMP type
  newproperty(:reject, :required_features => :reject_type) do
    desc <<-EOS
      When combined with jump => "REJECT" you can specify a different icmp
      response to be sent back to the packet sender.
    EOS
  end

  # Logging properties
  newproperty(:log_level, :required_features => :log_level) do
    desc <<-EOS
      When combined with jump => "LOG" specifies the system log level to log
      to.
    EOS

    munge do |value|
      if value.kind_of?(String)
        value = @resource.log_level_name_to_number(value)
      else
        value
      end

      if value == nil && value != ""
        self.fail("Unable to determine log level")
      end
      value
    end
  end

  newproperty(:log_prefix, :required_features => :log_prefix) do
    desc <<-EOS
      When combined with jump => "LOG" specifies the log prefix to use when
      logging.
    EOS
  end

  # ICMP matching property
  newproperty(:icmp, :required_features => :icmp_match) do
    desc <<-EOS
      When matching ICMP packets, this is the type of ICMP packet to match.

      A value of "any" is not supported. To achieve this behaviour the
      parameter should simply be omitted or undefined.
    EOS

    validate do |value|
      if value == "any"
        raise ArgumentError,
          "Value 'any' is not valid. This behaviour should be achieved " \
          "by omitting or undefining the ICMP parameter."
      end
    end

    munge do |value|
      if value.kind_of?(String)
        # ICMP codes differ between IPv4 and IPv6.
        case @resource[:provider]
        when :iptables
          protocol = 'inet'
        when :ip6tables
          protocol = 'inet6'
        else
          self.fail("cannot work out protocol family")
        end

        value = @resource.icmp_name_to_number(value, protocol)
      else
        value
      end

      if value == nil && value != ""
        self.fail("cannot work out icmp type")
      end
      value
    end
  end

  newproperty(:state, :array_matching => :all, :required_features =>
    :state_match) do

    desc <<-EOS
      Matches a packet based on its state in the firewall stateful inspection
      table. Values can be:

      * INVALID
      * ESTABLISHED
      * NEW
      * RELATED
    EOS

    newvalues(:INVALID,:ESTABLISHED,:NEW,:RELATED)

    # States should always be sorted. This normalizes the resource states to
    # keep it consistent with the sorted result from iptables-save.
    def should=(values)
      @should = super(values).sort_by {|sym| sym.to_s}
    end

    def is_to_s(value)
      should_to_s(value)
    end

    def should_to_s(value)
      value = [value] unless value.is_a?(Array)
      value.join(',')
    end
  end

  newproperty(:ctstate, :array_matching => :all, :required_features =>
    :state_match) do

    desc <<-EOS
      Matches a packet based on its state in the firewall stateful inspection
      table, using the conntrack module. Values can be:

      * INVALID
      * ESTABLISHED
      * NEW
      * RELATED
    EOS

    newvalues(:INVALID,:ESTABLISHED,:NEW,:RELATED)

    # States should always be sorted. This normalizes the resource states to
    # keep it consistent with the sorted result from iptables-save.
    def should=(values)
      @should = super(values).sort_by {|sym| sym.to_s}
    end

    def is_to_s(value)
      should_to_s(value)
    end

    def should_to_s(value)
      value = [value] unless value.is_a?(Array)
      value.join(',')
    end
  end


  # Connection mark
  newproperty(:connmark, :required_features => :mark) do
    desc <<-EOS
      Match the Netfilter mark value associated with the packet.  Accepts either of:
      mark/mask or mark.  These will be converted to hex if they are not already.
    EOS
    munge do |value|
      int_or_hex = '[a-fA-F0-9x]'
      match = value.to_s.match("(#{int_or_hex}+)(/)?(#{int_or_hex}+)?")
      mark = @resource.to_hex32(match[1])

      # Values that can't be converted to hex.
      # Or contain a trailing slash with no mask.
      if mark.nil? or (mark and match[2] and match[3].nil?)
        raise ArgumentError, "MARK value must be integer or hex between 0 and 0xffffffff"
      end

      # There should not be a mask on connmark
      unless match[3].nil?
        raise ArgumentError, "iptables does not support masks on MARK match rules"
      end
      value = mark

      value
    end
  end

  # Connection limiting properties
  newproperty(:connlimit_above, :required_features => :connection_limiting) do
    desc <<-EOS
      Connection limiting value for matched connections above n.
    EOS
    newvalue(/^\d+$/)
  end

  newproperty(:connlimit_mask, :required_features => :connection_limiting) do
    desc <<-EOS
      Connection limiting by subnet mask for matched connections.
      IPv4: 0-32
      IPv6: 0-128
    EOS
    newvalue(/^\d+$/)
  end

  # Hop limiting properties
  newproperty(:hop_limit, :required_features => :hop_limiting) do
    desc <<-EOS
      Hop limiting value for matched packets.
    EOS
    newvalue(/^\d+$/)
  end

  # Rate limiting properties
  newproperty(:limit, :required_features => :rate_limiting) do
    desc <<-EOS
      Rate limiting value for matched packets. The format is:
      rate/[/second/|/minute|/hour|/day].

      Example values are: '50/sec', '40/min', '30/hour', '10/day'."
    EOS
  end

  newproperty(:burst, :required_features => :rate_limiting) do
    desc <<-EOS
      Rate limiting burst value (per second) before limit checks apply.
    EOS
    newvalue(/^\d+$/)
  end

  newproperty(:uid, :required_features => :owner) do
    desc <<-EOS
      UID or Username owner matching rule.  Accepts a string argument
      only, as iptables does not accept multiple uid in a single
      statement.
    EOS
  end

  newproperty(:gid, :required_features => :owner) do
    desc <<-EOS
      GID or Group owner matching rule.  Accepts a string argument
      only, as iptables does not accept multiple gid in a single
      statement.
    EOS
  end

  newproperty(:set_mark, :required_features => :mark) do
    desc <<-EOS
      Set the Netfilter mark value associated with the packet.  Accepts either of:
      mark/mask or mark.  These will be converted to hex if they are not already.
    EOS

    munge do |value|
      int_or_hex = '[a-fA-F0-9x]'
      match = value.to_s.match("(#{int_or_hex}+)(/)?(#{int_or_hex}+)?")
      mark = @resource.to_hex32(match[1])

      # Values that can't be converted to hex.
      # Or contain a trailing slash with no mask.
      if mark.nil? or (mark and match[2] and match[3].nil?)
        raise ArgumentError, "MARK value must be integer or hex between 0 and 0xffffffff"
      end

      # Old iptables does not support a mask. New iptables will expect one.
      iptables_version = Facter.fact('iptables_version').value
      mask_required = (iptables_version and Puppet::Util::Package.versioncmp(iptables_version, '1.4.1') >= 0)

      if mask_required
        if match[3].nil?
          value = "#{mark}/0xffffffff"
        else
          mask = @resource.to_hex32(match[3])
          if mask.nil?
            raise ArgumentError, "MARK mask must be integer or hex between 0 and 0xffffffff"
          end
          value = "#{mark}/#{mask}"
        end
      else
        unless match[3].nil?
          raise ArgumentError, "iptables version #{iptables_version} does not support masks on MARK rules"
        end
        value = mark
      end

      value
    end
  end

  newproperty(:pkttype, :required_features => :pkttype) do
    desc <<-EOS
      Sets the packet type to match.
    EOS

    newvalues(:unicast, :broadcast, :multicast)
  end

  newproperty(:isfragment, :required_features => :isfragment) do
    desc <<-EOS
      Set to true to match tcp fragments (requires type to be set to tcp)
    EOS

    newvalues(:true, :false)
  end

  newproperty(:recent, :required_features => :recent_limiting) do
    desc <<-EOS
      Enable the recent module. Takes as an argument one of set, update,
      rcheck or remove. For example:

        # If anyone's appeared on the 'badguy' blacklist within
        # the last 60 seconds, drop their traffic, and update the timestamp.
        firewall { '100 Drop badguy traffic':
          recent   => 'update',
          rseconds => 60,
          rsource  => true,
          rname    => 'badguy',
          action   => 'DROP',
          chain    => 'FORWARD',
        }
        # No-one should be sending us traffic on eth0 from localhost
        # Blacklist them
        firewall { '101 blacklist strange traffic':
          recent      => 'set',
          rsource     => true,
          rname       => 'badguy',
          destination => '127.0.0.0/8',
          iniface     => 'eth0',
          action      => 'DROP',
          chain       => 'FORWARD',
        }
    EOS

    newvalues(:set, :update, :rcheck, :remove)
    munge do |value|
       value = "--" + value
    end
  end

  newproperty(:rdest, :required_features => :recent_limiting) do
    desc <<-EOS
      Recent module; add the destination IP address to the list.
      Must be boolean true.
    EOS

    newvalues(:true, :false)
  end

  newproperty(:rsource, :required_features => :recent_limiting) do
    desc <<-EOS
      Recent module; add the source IP address to the list.
      Must be boolean true.
    EOS

    newvalues(:true, :false)
  end

  newproperty(:rname, :required_features => :recent_limiting) do
    desc <<-EOS
      Recent module; The name of the list. Takes a string argument.
    EOS
  end

  newproperty(:rseconds, :required_features => :recent_limiting) do
    desc <<-EOS
      Recent module; used in conjunction with one of `recent => 'rcheck'` or
      `recent => 'update'`. When used, this will narrow the match to only
      happen when the address is in the list and was seen within the last given
      number of seconds.
    EOS
  end

  newproperty(:reap, :required_features => :recent_limiting) do
    desc <<-EOS
      Recent module; can only be used in conjunction with the `rseconds`
      attribute. When used, this will cause entries older than 'seconds' to be
      purged.  Must be boolean true.
    EOS

    newvalues(:true, :false)
  end

  newproperty(:rhitcount, :required_features => :recent_limiting) do
    desc <<-EOS
      Recent module; used in conjunction with `recent => 'update'` or `recent
      => 'rcheck'. When used, this will narrow the match to only happen when
      the address is in the list and packets had been received greater than or
      equal to the given value.
    EOS
  end

  newproperty(:rttl, :required_features => :recent_limiting) do
    desc <<-EOS
      Recent module; may only be used in conjunction with one of `recent =>
      'rcheck'` or `recent => 'update'`. When used, this will narrow the match
      to only happen when the address is in the list and the TTL of the current
      packet matches that of the packet which hit the `recent => 'set'` rule.
      This may be useful if you have problems with people faking their source
      address in order to DoS you via this module by disallowing others access
      to your site by sending bogus packets to you.  Must be boolean true.
    EOS

    newvalues(:true, :false)
  end

  newproperty(:socket, :required_features => :socket) do
    desc <<-EOS
      If true, matches if an open socket can be found by doing a coket lookup
      on the packet.
    EOS

    newvalues(:true, :false)
  end

  newproperty(:ishasmorefrags, :required_features => :ishasmorefrags) do
    desc <<-EOS
      If true, matches if the packet has it's 'more fragments' bit set. ipv6.
    EOS

    newvalues(:true, :false)
  end

  newproperty(:islastfrag, :required_features => :islastfrag) do
    desc <<-EOS
      If true, matches if the packet is the last fragment. ipv6.
    EOS

    newvalues(:true, :false)
  end

  newproperty(:isfirstfrag, :required_features => :isfirstfrag) do
    desc <<-EOS
      If true, matches if the packet is the first fragment. 
      Sadly cannot be negated. ipv6.
    EOS

    newvalues(:true, :false)
  end

  newproperty(:ipsec_policy, :required_features => :ipsec_policy) do
	  desc <<-EOS
	  	 Sets the ipsec policy type
	  EOS

	  newvalues(:none, :ipsec)
  end

  newproperty(:ipsec_dir, :required_features => :ipsec_dir) do
	  desc <<-EOS
	  	 Sets the ipsec policy direction
	  EOS

	  newvalues(:in, :out)
  end

  newproperty(:mask, :required_features => :mask) do
    desc <<-EOS
      Sets the mask to use when `recent` is enabled.
    EOS
  end

  newparam(:line) do
    desc <<-EOS
      Read-only property for caching the rule line.
    EOS
  end

  autorequire(:firewallchain) do
    reqs = []
    protocol = nil

    case value(:provider)
    when :iptables
      protocol = "IPv4"
    when :ip6tables
      protocol = "IPv6"
    end

    unless protocol.nil?
      table = value(:table)
      [value(:chain), value(:jump)].each do |chain|
        reqs << "#{chain}:#{table}:#{protocol}" unless ( chain.nil? || (['INPUT', 'OUTPUT', 'FORWARD'].include?(chain) && table == :filter) )
      end
    end

    reqs
  end

  # Classes would be a better abstraction, pending:
  # http://projects.puppetlabs.com/issues/19001
  autorequire(:package) do
    case value(:provider)
    when :iptables, :ip6tables
      %w{iptables iptables-persistent}
    else
      []
    end
  end

  validate do
    debug("[validate]")

    # TODO: this is put here to skip validation if ensure is not set. This
    # is because there is a revalidation stage called later where the values
    # are not set correctly. I tried tracing it - but have put in this
    # workaround instead to skip. Must get to the bottom of this.
    if ! value(:ensure)
      return
    end

    # First we make sure the chains and tables are valid combinations
    if value(:table).to_s == "filter" &&
      value(:chain) =~ /PREROUTING|POSTROUTING/

      self.fail "PREROUTING and POSTROUTING cannot be used in table 'filter'"
    end

    if value(:table).to_s == "nat" && value(:chain) =~ /INPUT|FORWARD/
      self.fail "INPUT and FORWARD cannot be used in table 'nat'"
    end

    if value(:table).to_s == "raw" &&
      value(:chain) =~ /INPUT|FORWARD|POSTROUTING/

      self.fail "INPUT, FORWARD and POSTROUTING cannot be used in table raw"
    end

    # Now we analyse the individual properties to make sure they apply to
    # the correct combinations.
    if value(:iniface)
      unless value(:chain).to_s =~ /INPUT|FORWARD|PREROUTING/
        self.fail "Parameter iniface only applies to chains " \
          "INPUT,FORWARD,PREROUTING"
      end
    end

    if value(:outiface)
      unless value(:chain).to_s =~ /OUTPUT|FORWARD|POSTROUTING/
        self.fail "Parameter outiface only applies to chains " \
          "OUTPUT,FORWARD,POSTROUTING"
      end
    end

    if value(:uid)
      unless value(:chain).to_s =~ /OUTPUT|POSTROUTING/
        self.fail "Parameter uid only applies to chains " \
          "OUTPUT,POSTROUTING"
      end
    end

    if value(:gid)
      unless value(:chain).to_s =~ /OUTPUT|POSTROUTING/
        self.fail "Parameter gid only applies to chains " \
          "OUTPUT,POSTROUTING"
      end
    end

    if value(:set_mark)
      unless value(:jump).to_s  =~ /MARK/ &&
             value(:chain).to_s =~ /PREROUTING|OUTPUT/ &&
             value(:table).to_s =~ /mangle/
        self.fail "Parameter set_mark only applies to " \
          "the PREROUTING or OUTPUT chain of the mangle table and when jump => MARK"
      end
    end

    if value(:dport)
      unless value(:proto).to_s =~ /tcp|udp|sctp/
        self.fail "[%s] Parameter dport only applies to sctp, tcp and udp " \
          "protocols. Current protocol is [%s] and dport is [%s]" %
          [value(:name), should(:proto), should(:dport)]
      end
    end

    if value(:jump).to_s == "DNAT"
      unless value(:table).to_s =~ /nat/
        self.fail "Parameter jump => DNAT only applies to table => nat"
      end

      unless value(:todest)
        self.fail "Parameter jump => DNAT must have todest parameter"
      end
    end

    if value(:jump).to_s == "SNAT"
      unless value(:table).to_s =~ /nat/
        self.fail "Parameter jump => SNAT only applies to table => nat"
      end

      unless value(:tosource)
        self.fail "Parameter jump => SNAT must have tosource parameter"
      end
    end

    if value(:jump).to_s == "REDIRECT"
      unless value(:toports)
        self.fail "Parameter jump => REDIRECT missing mandatory toports " \
          "parameter"
      end
    end

    if value(:jump).to_s == "MASQUERADE"
      unless value(:table).to_s =~ /nat/
        self.fail "Parameter jump => MASQUERADE only applies to table => nat"
      end
    end

    if value(:log_prefix) || value(:log_level)
      unless value(:jump).to_s == "LOG"
        self.fail "Parameter log_prefix and log_level require jump => LOG"
      end
    end

    if value(:burst) && ! value(:limit)
      self.fail "burst makes no sense without limit"
    end

    if value(:action) && value(:jump)
      self.fail "Only one of the parameters 'action' and 'jump' can be set"
    end

    if value(:connlimit_mask) && ! value(:connlimit_above)
      self.fail "Parameter 'connlimit_mask' requires 'connlimit_above'"
    end

    if value(:mask) && ! value(:recent)
      self.fail "Mask can only be set if recent is enabled."
    end

  end
end
# This is a workaround for bug: #4248 whereby ruby files outside of the normal
# provider/type path do not load until pluginsync has occured on the puppetmaster
#
# In this case I'm trying the relative path first, then falling back to normal
# mechanisms. This should be fixed in future versions of puppet but it looks
# like we'll need to maintain this for some time perhaps.
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__),"..",".."))
require 'puppet/util/firewall'

Puppet::Type.newtype(:firewallchain) do
  include Puppet::Util::Firewall

  @doc = <<-EOS
    This type provides the capability to manage rule chains for firewalls.

    Currently this supports only iptables, ip6tables and ebtables on Linux. And
    provides support for setting the default policy on chains and tables that
    allow it.

    **Autorequires:**
    If Puppet is managing the iptables or iptables-persistent packages, and
    the provider is iptables_chain, the firewall resource will autorequire
    those packages to ensure that any required binaries are installed.
  EOS

  feature :iptables_chain, "The provider provides iptables chain features."
  feature :policy, "Default policy (inbuilt chains only)"

  ensurable do
    defaultvalues
    defaultto :present
  end

  newparam(:name) do
    desc <<-EOS
      The canonical name of the chain.

      For iptables the format must be {chain}:{table}:{protocol}.
    EOS
    isnamevar

    validate do |value|
      if value !~ Nameformat then
        raise ArgumentError, "Inbuilt chains must be in the form {chain}:{table}:{protocol} where {table} is one of FILTER, NAT, MANGLE, RAW, RAWPOST, BROUTE or empty (alias for filter), chain can be anything without colons or one of PREROUTING, POSTROUTING, BROUTING, INPUT, FORWARD, OUTPUT for the inbuilt chains, and {protocol} being IPv4, IPv6, ethernet (ethernet bridging) got '#{value}' table:'#{$1}' chain:'#{$2}' protocol:'#{$3}'"
      else
        chain = $1
        table = $2
        protocol = $3
        case table
        when 'filter'
          if chain =~ /^(PREROUTING|POSTROUTING|BROUTING)$/
            raise ArgumentError, "INPUT, OUTPUT and FORWARD are the only inbuilt chains that can be used in table 'filter'"
          end
        when 'mangle'
          if chain =~ InternalChains && chain == 'BROUTING'
            raise ArgumentError, "PREROUTING, POSTROUTING, INPUT, FORWARD and OUTPUT are the only inbuilt chains that can be used in table 'mangle'"
          end
        when 'nat'
          if chain =~ /^(BROUTING|FORWARD)$/
            raise ArgumentError, "PREROUTING, POSTROUTING, INPUT, and OUTPUT are the only inbuilt chains that can be used in table 'nat'"
          end
          if protocol =~/^(IP(v6)?)?$/
            raise ArgumentError, "table nat isn't valid in IPv6. You must specify ':IPv4' as the name suffix"
          end
        when 'raw'
          if chain =~ /^(POSTROUTING|BROUTING|INPUT|FORWARD)$/
            raise ArgumentError,'PREROUTING and OUTPUT are the only inbuilt chains in the table \'raw\''
          end
        when 'broute'
          if protocol != 'ethernet'
            raise ArgumentError,'BROUTE is only valid with protocol \'ethernet\''
          end
          if chain =~ /^PREROUTING|POSTROUTING|INPUT|FORWARD|OUTPUT$/
            raise ArgumentError,'BROUTING is the only inbuilt chain allowed on on table \'broute\''
          end
        end
        if chain == 'BROUTING' && ( protocol != 'ethernet' || table!='broute')
          raise ArgumentError,'BROUTING is the only inbuilt chain allowed on on table \'BROUTE\' with protocol \'ethernet\' i.e. \'broute:BROUTING:enternet\''
        end
      end
    end
  end

  newproperty(:policy) do
    desc <<-EOS
      This is the action to when the end of the chain is reached.
      It can only be set on inbuilt chains (INPUT, FORWARD, OUTPUT,
      PREROUTING, POSTROUTING) and can be one of:

      * accept - the packet is accepted
      * drop - the packet is dropped
      * queue - the packet is passed userspace
      * return - the packet is returned to calling (jump) queue
                 or the default of inbuilt chains
    EOS
    newvalues(:accept, :drop, :queue, :return)
    defaultto do
      # ethernet chain have an ACCEPT default while other haven't got an
      # allowed value
      if @resource[:name] =~ /:ethernet$/
        :accept
      else
        nil
      end
    end
  end

  newparam(:purge, :boolean => true) do
    desc <<-EOS
      Purge unmanaged firewall rules in this chain
    EOS
    newvalues(:false, :true)
    defaultto :false
  end

  newparam(:ignore) do
    desc <<-EOS
      Regex to perform on firewall rules to exempt unmanaged rules from purging (when enabled).
      This is matched against the output of `iptables-save`.

      This can be a single regex, or an array of them.
      To support flags, use the ruby inline flag mechanism.
      Meaning a regex such as
        /foo/i
      can be written as
        '(?i)foo' or '(?i:foo)'

      Full example:
      firewallchain { 'INPUT:filter:IPv4':
        purge => true,
        ignore => [
          '-j fail2ban-ssh', # ignore the fail2ban jump rule
          '--comment "[^"]*(?i:ignore)[^"]*"', # ignore any rules with "ignore" (case insensitive) in the comment in the rule
        ],
      }
    EOS

    validate do |value|
      unless value.is_a?(Array) or value.is_a?(String) or value == false
        self.devfail "Ignore must be a string or an Array"
      end
    end
    munge do |patterns| # convert into an array of {Regex}es
      patterns = [patterns] if patterns.is_a?(String)
      patterns.map{|p| Regexp.new(p)}
    end
  end

  # Classes would be a better abstraction, pending:
  # http://projects.puppetlabs.com/issues/19001
  autorequire(:package) do
    case value(:provider)
    when :iptables_chain
      %w{iptables iptables-persistent}
    else
      []
    end
  end

  validate do
    debug("[validate]")

    value(:name).match(Nameformat)
    chain = $1
    table = $2
    protocol = $3

    # Check that we're not removing an internal chain
    if chain =~ InternalChains && value(:ensure) == :absent
      self.fail "Cannot remove in-built chains"
    end

    if value(:policy).nil? && protocol == 'ethernet'
      self.fail "you must set a non-empty policy on all ethernet table chains"
    end

    # Check that we're not setting a policy on a user chain
    if chain !~ InternalChains &&
      !value(:policy).nil? &&
      protocol != 'ethernet'

      self.fail "policy can only be set on in-built chains (with the exception of ethernet chains) (table:#{table} chain:#{chain} protocol:#{protocol})"
    end

    # no DROP policy on nat table
    if table == 'nat' &&
      value(:policy) == :drop

      self.fail 'The "nat" table is not intended for filtering, the use of DROP is therefore inhibited'
    end
  end

  def generate
    return [] unless self.purge?

    value(:name).match(Nameformat)
    chain = $1
    table = $2
    protocol = $3

    provider = case protocol
               when 'IPv4'
                 :iptables
               when 'IPv6'
                 :ip6tables
               end

    # gather a list of all rules present on the system
    rules_resources = Puppet::Type.type(:firewall).instances

    # Keep only rules in this chain
    rules_resources.delete_if { |res| (res[:provider] != provider or res.provider.properties[:table].to_s != table or res.provider.properties[:chain] != chain) }

    # Remove rules which match our ignore filter
    rules_resources.delete_if {|res| value(:ignore).find_index{|f| res.provider.properties[:line].match(f)}} if value(:ignore)

    # We mark all remaining rules for deletion, and then let the catalog override us on rules which should be present
    rules_resources.each {|res| res[:ensure] = :absent}

    rules_resources
  end
end
require 'socket'
require 'resolv'
require 'puppet/util/ipcidr'

# Util module for puppetlabs-firewall
module Puppet::Util::Firewall
  # Translate the symbolic names for icmp packet types to integers
  def icmp_name_to_number(value_icmp, protocol)
    if value_icmp =~ /\d{1,2}$/
      value_icmp
    elsif protocol == 'inet'
      case value_icmp
        when "echo-reply" then "0"
        when "destination-unreachable" then "3"
        when "source-quench" then "4"
        when "redirect" then "6"
        when "echo-request" then "8"
        when "router-advertisement" then "9"
        when "router-solicitation" then "10"
        when "time-exceeded" then "11"
        when "parameter-problem" then "12"
        when "timestamp-request" then "13"
        when "timestamp-reply" then "14"
        when "address-mask-request" then "17"
        when "address-mask-reply" then "18"
        else nil
      end
    elsif protocol == 'inet6'
      case value_icmp
        when "destination-unreachable" then "1"
        when "time-exceeded" then "3"
        when "parameter-problem" then "4"
        when "echo-request" then "128"
        when "echo-reply" then "129"
        when "router-solicitation" then "133"
        when "router-advertisement" then "134"
        when "redirect" then "137"
        else nil
      end
    else
      raise ArgumentError, "unsupported protocol family '#{protocol}'"
    end
  end

  # Convert log_level names to their respective numbers
  def log_level_name_to_number(value)
    #TODO make this 0-7 only
    if value =~ /\d/
      value
    else
      case value
        when "panic" then "0"
        when "alert" then "1"
        when "crit" then "2"
        when "err" then "3"
        when "error" then "3"
        when "warn" then "4"
        when "warning" then "4"
        when "not" then "5"
        when "notice" then "5"
        when "info" then "6"
        when "debug" then "7"
        else nil
      end
    end
  end

  # This method takes a string and a protocol and attempts to convert
  # it to a port number if valid.
  #
  # If the string already contains a port number or perhaps a range of ports
  # in the format 22:1000 for example, it simply returns the string and does
  # nothing.
  def string_to_port(value, proto)
    proto = proto.to_s
    unless proto =~ /^(tcp|udp)$/
      proto = 'tcp'
    end

    if value.kind_of?(String)
      if value.match(/^\d+(-\d+)?$/)
        return value
      else
        return Socket.getservbyname(value, proto).to_s
      end
    else
      Socket.getservbyname(value.to_s, proto).to_s
    end
  end

  # Takes an address and returns it in CIDR notation.
  #
  # If the address is:
  #
  #   - A hostname:
  #     It will be resolved
  #   - An IPv4 address:
  #     It will be qualified with a /32 CIDR notation
  #   - An IPv6 address:
  #     It will be qualified with a /128 CIDR notation
  #   - An IP address with a CIDR notation:
  #     It will be normalised
  #   - An IP address with a dotted-quad netmask:
  #     It will be converted to CIDR notation
  #   - Any address with a resulting prefix length of zero:
  #     It will return nil which is equivilent to not specifying an address
  #
  def host_to_ip(value)
    begin
      value = Puppet::Util::IPCidr.new(value)
    rescue
      value = Puppet::Util::IPCidr.new(Resolv.getaddress(value))
    end

    return nil if value.prefixlen == 0
    value.cidr
  end

  # Takes an address mask and converts the host portion to CIDR notation.
  #
  # This takes into account you can negate a mask but follows all rules
  # defined in host_to_ip for the host/address part.
  #
  def host_to_mask(value)
    match = value.match /(!)\s?(.*)$/
    return host_to_ip(value) unless match

    cidr = host_to_ip(match[2])
    return nil if cidr == nil
    "#{match[1]} #{cidr}"
  end

  # Validates the argument is int or hex, and returns valid hex
  # conversion of the value or nil otherwise.
  def to_hex32(value)
      begin
        value = Integer(value)
        if value.between?(0, 0xffffffff)
            return '0x' + value.to_s(16)
        end
      rescue ArgumentError
        # pass
      end
    return nil
  end

  def persist_iptables(proto)
    debug("[persist_iptables]")

    # Basic normalisation for older Facter
    os_key = Facter.value(:osfamily)
    os_key ||= case Facter.value(:operatingsystem)
    when 'RedHat', 'CentOS', 'Fedora', 'Scientific', 'SL', 'SLC', 'Ascendos', 'CloudLinux', 'PSBM', 'OracleLinux', 'OVS', 'OEL', 'Amazon', 'XenServer'
      'RedHat'
    when 'Debian', 'Ubuntu'
      'Debian'
    else
      Facter.value(:operatingsystem)
    end

    # Older iptables-persistent doesn't provide save action.
    if os_key == 'Debian'
      persist_ver = Facter.value(:iptables_persistent_version)
      if (persist_ver and Puppet::Util::Package.versioncmp(persist_ver, '0.5.0') < 0)
        os_key = 'Debian_manual'
      end
    end

    # Fedora 15 and newer use systemd to persist iptable rules
    if os_key == 'RedHat' && Facter.value(:operatingsystem) == 'Fedora' && Facter.value(:operatingsystemrelease).to_i >= 15
      os_key = 'Fedora'
    end

    # RHEL 7 and newer also use systemd to persist iptable rules
    if os_key == 'RedHat' && Facter.value(:operatingsystem) == 'RedHat' && Facter.value(:operatingsystemrelease).to_i >= 7
      os_key = 'Fedora'
    end

    cmd = case os_key.to_sym
    when :RedHat
      case proto.to_sym
      when :IPv4
        %w{/sbin/service iptables save}
      when :IPv6
        %w{/sbin/service ip6tables save}
      end
    when :Fedora
      case proto.to_sym
      when :IPv4
        %w{/usr/libexec/iptables/iptables.init save}
      when :IPv6
        %w{/usr/libexec/iptables/ip6tables.init save}
      end
    when :Debian
      case proto.to_sym
      when :IPv4, :IPv6
        %w{/usr/sbin/service iptables-persistent save}
      end
    when :Debian_manual
      case proto.to_sym
      when :IPv4
        ["/bin/sh", "-c", "/sbin/iptables-save > /etc/iptables/rules"]
      end
    when :Archlinux
      case proto.to_sym
      when :IPv4
        ["/bin/sh", "-c", "/usr/sbin/iptables-save > /etc/iptables/iptables.rules"]
      when :IPv6
        ["/bin/sh", "-c", "/usr/sbin/ip6tables-save > /etc/iptables/ip6tables.rules"]
      end
    end

    # Catch unsupported OSs from the case statement above.
    if cmd.nil?
      debug('firewall: Rule persistence is not supported for this type/OS')
      return
    end

    begin
      execute(cmd)
    rescue Puppet::ExecutionFailure => detail
      warning("Unable to persist firewall rules: #{detail}")
    end
  end
end
require 'ipaddr'

# IPCidr object wrapper for IPAddr
module Puppet
  module Util
    class IPCidr < IPAddr
      def initialize(ipaddr)
        begin
          super(ipaddr)
        rescue ArgumentError => e
          if e.message =~ /invalid address/
            raise ArgumentError, "Invalid address from IPAddr.new: #{ipaddr}"
          else
            raise e
          end
        end
      end

      def netmask
        _to_string(@mask_addr)
      end

      def prefixlen
        m = case @family
            when Socket::AF_INET
              IN4MASK
            when Socket::AF_INET6
              IN6MASK
            else
              raise "unsupported address family"
            end
        return $1.length if /\A(1*)(0*)\z/ =~ (@mask_addr & m).to_s(2)
        raise "bad addr_mask format"
      end

      def cidr
        cidr = sprintf("%s/%s", self.to_s, self.prefixlen)
        cidr
      end
    end
  end
end
# = Class: firewall
#
# Manages packages and services required by the firewall type/provider.
#
# This class includes the appropriate sub-class for your operating system,
# where supported.
#
# == Parameters:
#
# [*ensure*]
#   Ensure parameter passed onto Service[] resources.
#   Default: running
#
class firewall (
  $ensure = running
) {
  case $ensure {
    /^(running|stopped)$/: {
      # Do nothing.
    }
    default: {
      fail("${title}: Ensure value '${ensure}' is not supported")
    }
  }

  case $::kernel {
    'Linux': {
      class { "${title}::linux":
        ensure => $ensure,
      }
    }
    default: {
      fail("${title}: Kernel '${::kernel}' is not currently supported")
    }
  }
}
# = Class: firewall::linux
#
# Installs the `iptables` package for Linux operating systems and includes
# the appropriate sub-class for any distribution specific services and
# additional packages.
#
# == Parameters:
#
# [*ensure*]
#   Ensure parameter passed onto Service[] resources. When `running` the
#   service will be started on boot, and when `stopped` it will not.
#   Default: running
#
class firewall::linux (
  $ensure = running
) {
  $enable = $ensure ? {
    running => true,
    stopped => false,
  }

  package { 'iptables':
    ensure => present,
  }

  case $::operatingsystem {
    'RedHat', 'CentOS', 'Fedora', 'Scientific', 'SL', 'SLC', 'Ascendos',
    'CloudLinux', 'PSBM', 'OracleLinux', 'OVS', 'OEL', 'Amazon', 'XenServer': {
      class { "${title}::redhat":
        ensure  => $ensure,
        enable  => $enable,
        require => Package['iptables'],
      }
    }
    'Debian', 'Ubuntu': {
      class { "${title}::debian":
        ensure  => $ensure,
        enable  => $enable,
        require => Package['iptables'],
      }
    }
    'Archlinux': {
      class { "${title}::archlinux":
        ensure  => $ensure,
        enable  => $enable,
        require => Package['iptables'],
      }
    }
    default: {}
  }
}
# = Class: firewall::linux::archlinux
#
# Manages `iptables` and `ip6tables` services, and creates files used for
# persistence, on Arch Linux systems.
#
# == Parameters:
#
# [*ensure*]
#   Ensure parameter passed onto Service[] resources.
#   Default: running
#
# [*enable*]
#   Enable parameter passed onto Service[] resources.
#   Default: true
#
class firewall::linux::archlinux (
  $ensure = 'running',
  $enable = true
) {
  service { 'iptables':
    ensure    => $ensure,
    enable    => $enable,
    hasstatus => true,
  }

  service { 'ip6tables':
    ensure    => $ensure,
    enable    => $enable,
    hasstatus => true,
  }

  file { '/etc/iptables/iptables.rules':
    ensure => present,
    before => Service['iptables'],
  }

  file { '/etc/iptables/ip6tables.rules':
    ensure => present,
    before => Service['ip6tables'],
  }
}
# = Class: firewall::linux::debian
#
# Installs the `iptables-persistent` package for Debian-alike systems. This
# allows rules to be stored to file and restored on boot.
#
# == Parameters:
#
# [*ensure*]
#   Ensure parameter passed onto Service[] resources.
#   Default: running
#
# [*enable*]
#   Enable parameter passed onto Service[] resources.
#   Default: true
#
class firewall::linux::debian (
  $ensure = running,
  $enable = true
) {
  package { 'iptables-persistent':
    ensure => present,
  }

  if($::operatingsystemrelease =~ /^6\./ and $enable == true
  and versioncmp($::iptables_persistent_version, '0.5.0') < 0 ) {
    # This fixes a bug in the iptables-persistent LSB headers in 6.x, without it
    # we lose idempotency
    exec { 'iptables-persistent-enable':
      logoutput => on_failure,
      command   => '/usr/sbin/update-rc.d iptables-persistent enable',
      unless    => '/usr/bin/test -f /etc/rcS.d/S*iptables-persistent',
      require   => Package['iptables-persistent'],
    }
  } else {
    # This isn't a real service/daemon. The start action loads rules, so just
    # needs to be called on system boot.
    service { 'iptables-persistent':
      ensure    => undef,
      enable    => $enable,
      hasstatus => true,
      require   => Package['iptables-persistent'],
    }
  }
}
# = Class: firewall::linux::redhat
#
# Manages the `iptables` service on RedHat-alike systems.
#
# == Parameters:
#
# [*ensure*]
#   Ensure parameter passed onto Service[] resources.
#   Default: running
#
# [*enable*]
#   Enable parameter passed onto Service[] resources.
#   Default: true
#
class firewall::linux::redhat (
  $ensure = running,
  $enable = true
) {

  # RHEL 7 and later and Fedora 15 and later require the iptables-services
  # package, which provides the /usr/libexec/iptables/iptables.init used by
  # lib/puppet/util/firewall.rb.
  if $::operatingsystem == RedHat and $::operatingsystemrelease >= 7 {
    package { 'iptables-services':
      ensure => present,
    }
  }

  if ($::operatingsystem == 'Fedora' and (( $::operatingsystemrelease =~ /^\d+/ and $::operatingsystemrelease >= 15 ) or $::operatingsystemrelease == "Rawhide")) {
    package { 'iptables-services':
      ensure => present,
    }
  }

  service { 'iptables':
    ensure    => $ensure,
    enable    => $enable,
    hasstatus => true,
  }
}
{
    "name": "puppetlabs-firewall",
    "version": "1.1.1",
    "source": "https://github.com/puppetlabs/puppetlabs-firewall",
    "author": "Puppet Labs",
    "license": "Apache-2.0",
    "project_page": "https://github.com/puppetlabs/puppetlabs-firewall",
    "summary": "Manages Firewalls such as iptable",
    "operatingsystem_support": [
      {
        "operatingsystem": "RedHat",
        "operatingsystemrelease": [
          "5",
          "6"
        ]
      },
      {
        "operatingsystem": "CentOS",
        "operatingsystemrelease": [
          "5",
          "6"
        ]
      },
      {
        "operatingsystem": "OracleLinux",
        "operatingsystemrelease": [
          "5",
          "6"
        ]
      },
      {
        "operatingsystem": "Scientific",
        "operatingsystemrelease": [
          "5",
          "6"
        ]
      },
      {
        "operatingsystem": "SLES",
        "operatingsystemrelease": [
          "11 SP1"
        ]
      },
      {
        "operatingsystem": "Debian",
        "operatingsystemrelease": [
          "6",
          "7"
        ]
      },
      {
        "operatingsystem": "Ubuntu",
        "operatingsystemrelease": [
          "10.04",
          "12.04"
        ]
      }
    ],
    "requirements": [
      { "name": "pe", "version_requirement": "3.2.x" },
      { "name": "puppet", "version_requirement": "3.x" }
    ],
    "dependencies": []
}
require 'spec_helper_acceptance'

describe 'firewall type' do
  describe 'reset' do
    it 'deletes all rules' do
      shell('iptables --flush; iptables -t nat --flush; iptables -t mangle --flush')
    end
  end

  describe 'when unmanaged rules exist' do
    it 'applies with 8.0.0.1 first' do
      pp = <<-EOS
          class { '::firewall': }
          firewall { '101 test source changes':
            proto  => tcp,
            port   => '101',
            action => accept,
            source => '8.0.0.1',
          }
          firewall { '100 test source static':
            proto  => tcp,
            port   => '100',
            action => accept,
            source => '8.0.0.2',
          }
      EOS

      apply_manifest(pp, :catch_failures => true)
    end

    it 'adds a unmanaged rule without a comment' do
      shell('iptables -A INPUT -t filter -s 8.0.0.3/32 -p tcp -m multiport --ports 102 -j ACCEPT')
      expect(shell('iptables-save').stdout).to match(/-A INPUT -s 8\.0\.0\.3(\/32)? -p tcp -m multiport --ports 102 -j ACCEPT/)
    end

    it 'contains the changable 8.0.0.1 rule' do
      shell('iptables-save') do |r|
        expect(r.stdout).to match(/-A INPUT -s 8\.0\.0\.1(\/32)? -p tcp -m multiport --ports 101 -m comment --comment "101 test source changes" -j ACCEPT/)
      end
    end
    it 'contains the static 8.0.0.2 rule' do
      shell('iptables-save') do |r|
        expect(r.stdout).to match(/-A INPUT -s 8\.0\.0\.2(\/32)? -p tcp -m multiport --ports 100 -m comment --comment "100 test source static" -j ACCEPT/)
      end
    end

    it 'changes to 8.0.0.4 second' do
      pp = <<-EOS
          class { '::firewall': }
          firewall { '101 test source changes':
            proto  => tcp,
            port   => '101',
            action => accept,
            source => '8.0.0.4',
          }
      EOS

      expect(apply_manifest(pp, :catch_failures => true).stdout).to match(/Notice: \/Stage\[main\]\/Main\/Firewall\[101 test source changes\]\/source: source changed '8\.0\.0\.1\/32' to '8\.0\.0\.4\/32'/)
    end

    it 'does not contain the old changing 8.0.0.1 rule' do
      shell('iptables-save') do |r|
        expect(r.stdout).to_not match(/8\.0\.0\.1/)
      end
    end
    it 'contains the staic 8.0.0.2 rule' do
      shell('iptables-save') do |r|
        expect(r.stdout).to match(/-A INPUT -s 8\.0\.0\.2(\/32)? -p tcp -m multiport --ports 100 -m comment --comment "100 test source static" -j ACCEPT/)
      end
    end
    it 'contains the changing new 8.0.0.4 rule' do
      shell('iptables-save') do |r|
        expect(r.stdout).to match(/-A INPUT -s 8\.0\.0\.4(\/32)? -p tcp -m multiport --ports 101 -m comment --comment "101 test source changes" -j ACCEPT/)
      end
    end
  end
end
require 'spec_helper_acceptance'

describe "firewall class:" do
  it 'should run successfully' do
    pp = "class { 'firewall': }"

    # Run it twice and test for idempotency
    apply_manifest(pp, :catch_failures => true)
    expect(apply_manifest(pp, :catch_failures => true).exit_code).to be_zero
  end

  it 'ensure => stopped:' do
    pp = "class { 'firewall': ensure => stopped }"

    # Run it twice and test for idempotency
    apply_manifest(pp, :catch_failures => true)
    expect(apply_manifest(pp, :catch_failures => true).exit_code).to be_zero
  end

  it 'ensure => running:' do
    pp = "class { 'firewall': ensure => running }"

    # Run it twice and test for idempotency
    apply_manifest(pp, :catch_failures => true)
    expect(apply_manifest(pp, :catch_failures => true).exit_code).to be_zero
  end
end
require 'spec_helper_acceptance'

describe 'firewall type' do

  describe 'connlimit_above' do
    context '10' do
      it 'applies' do
        pp = <<-EOS
          class { '::firewall': }
          firewall { '500 - test':
            proto           => tcp,
	    dport           => '22',
	    connlimit_above => '10',
            action          => reject,
          }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      it 'should contain the rule' do
        shell('iptables-save') do |r|
          #connlimit-saddr is added in Ubuntu 14.04.
          expect(r.stdout).to match(/-A INPUT -p tcp -m multiport --dports 22 -m comment --comment "500 - test" -m connlimit --connlimit-above 10 --connlimit-mask 32 (--connlimit-saddr )?-j REJECT --reject-with icmp-port-unreachable/)
        end
      end
    end
  end

  describe 'connlimit_mask' do
    context '24' do
      it 'applies' do
        pp = <<-EOS
          class { '::firewall': }
          firewall { '501 - test':
            proto           => tcp,
            dport           => '22',
            connlimit_above => '10',
            connlimit_mask  => '24',
            action          => reject,
          }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      it 'should contain the rule' do
        shell('iptables-save') do |r|
          #connlimit-saddr is added in Ubuntu 14.04.
          expect(r.stdout).to match(/-A INPUT -p tcp -m multiport --dports 22 -m comment --comment "501 - test" -m connlimit --connlimit-above 10 --connlimit-mask 24 (--connlimit-saddr )?-j REJECT --reject-with icmp-port-unreachable/)
        end
      end
    end
  end
end
require 'spec_helper_acceptance'

describe 'firewall type' do

  describe 'connmark' do
    context '50' do
      it 'applies' do
        pp = <<-EOS
          class { '::firewall': }
          firewall { '502 - test':
            proto    => 'all',
	    connmark => '0x1',
            action   => reject,
          }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      it 'should contain the rule' do
        shell('iptables-save') do |r|
          expect(r.stdout).to match(/-A INPUT -m comment --comment "502 - test" -m connmark --mark 0x1 -j REJECT --reject-with icmp-port-unreachable/)
        end
      end
    end
  end
end
require 'spec_helper_acceptance'

describe 'firewall type' do

  describe 'reset' do
    it 'deletes all rules' do
      shell('iptables --flush; iptables -t nat --flush; iptables -t mangle --flush')
    end
  end

  describe 'name' do
    context 'valid' do
      it 'applies cleanly' do
        pp = <<-EOS
          class { '::firewall': }
          firewall { '001 - test': ensure => present }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

    end

    context 'invalid' do
      it 'fails' do
        pp = <<-EOS
          class { '::firewall': }
          firewall { 'test': ensure => present }
        EOS

        apply_manifest(pp, :expect_failures => true) do |r|
          expect(r.stderr).to match(/Invalid value "test"./)
        end
      end
    end
  end

  describe 'ensure' do
    context 'default' do
      it 'applies' do
        pp = <<-EOS
          class { '::firewall': }
          firewall { '555 - test':
            proto  => tcp,
            port   => '555',
            action => accept,
          }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      it 'should contain the rule' do
         shell('iptables-save') do |r|
           expect(r.stdout).to match(/-A INPUT -p tcp -m multiport --ports 555 -m comment --comment "555 - test" -j ACCEPT/)
         end
      end
    end

    context 'present' do
      it 'applies' do
        pp = <<-EOS
          class { '::firewall': }
          firewall { '555 - test':
            ensure => present,
            proto  => tcp,
            port   => '555',
            action => accept,
          }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      it 'should contain the rule' do
         shell('iptables-save') do |r|
           expect(r.stdout).to match(/-A INPUT -p tcp -m multiport --ports 555 -m comment --comment "555 - test" -j ACCEPT/)
         end
      end
    end

    context 'absent' do
      it 'applies' do
        pp = <<-EOS
          class { '::firewall': }
          firewall { '555 - test':
            ensure => absent,
            proto  => tcp,
            port   => '555',
            action => accept,
          }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      it 'should not contain the rule' do
         shell('iptables-save') do |r|
           expect(r.stdout).to_not match(/-A INPUT -p tcp -m multiport --ports 555 -m comment --comment "555 - test" -j ACCEPT/)
         end
      end
    end
  end

  describe 'source' do
    context '192.168.2.0/24' do
      it 'applies' do
        pp = <<-EOS
          class { '::firewall': }
          firewall { '556 - test':
            proto  => tcp,
            port   => '556',
            action => accept,
            source => '192.168.2.0/24',
          }
        EOS

        apply_manifest(pp, :catch_failures => true)
        apply_manifest(pp, :catch_changes => true)
      end

      it 'should contain the rule' do
         shell('iptables-save') do |r|
           expect(r.stdout).to match(/-A INPUT -s 192.168.2.0\/(24|255\.255\.255\.0) -p tcp -m multiport --ports 556 -m comment --comment "556 - test" -j ACCEPT/)
         end
      end
    end

    context '! 192.168.2.0/24' do
      it 'applies' do
        pp = <<-EOS
          class { '::firewall': }
          firewall { '556 - test':
            proto  => tcp,
            port   => '556',
            action => accept,
            source => '! 192.168.2.0/24',
          }
        EOS

        apply_manifest(pp, :catch_failures => true)
        apply_manifest(pp, :catch_changes => true)
      end

      it 'should contain the rule' do
         shell('iptables-save') do |r|
           expect(r.stdout).to match(/-A INPUT (! -s|-s !) 192.168.2.0\/(24|255\.255\.255\.0) -p tcp -m multiport --ports 556 -m comment --comment "556 - test" -j ACCEPT/)
         end
      end
    end

    # Invalid address
    context '256.168.2.0/24' do
      it 'applies' do
        pp = <<-EOS
          class { '::firewall': }
          firewall { '556 - test':
            proto  => tcp,
            port   => '556',
            action => accept,
            source => '256.168.2.0/24',
          }
        EOS

        apply_manifest(pp, :expect_failures => true) do |r|
          expect(r.stderr).to match(/host_to_ip failed for 256.168.2.0\/(24|255\.255\.255\.0)/)
        end
      end

      it 'should not contain the rule' do
         shell('iptables-save') do |r|
           expect(r.stdout).to_not match(/-A INPUT -s 256.168.2.0\/(24|255\.255\.255\.0) -p tcp -m multiport --ports 556 -m comment --comment "556 - test" -j ACCEPT/)
         end
      end
    end
  end

  describe 'src_range' do
    context '192.168.1.1-192.168.1.10' do
      it 'applies' do
        pp = <<-EOS
          class { '::firewall': }
          firewall { '557 - test':
            proto  => tcp,
            port   => '557',
            action => accept,
            src_range => '192.168.1.1-192.168.1.10',
          }
        EOS

        apply_manifest(pp, :catch_failures => true)
        apply_manifest(pp, :catch_changes => true)
      end

      it 'should contain the rule' do
         shell('iptables-save') do |r|
           expect(r.stdout).to match(/-A INPUT -p tcp -m iprange --src-range 192.168.1.1-192.168.1.10 -m multiport --ports 557 -m comment --comment "557 - test" -j ACCEPT/)
         end
      end
    end

    # Invalid IP
    context '392.168.1.1-192.168.1.10' do
      it 'applies' do
        pp = <<-EOS
          class { '::firewall': }
          firewall { '557 - test':
            proto  => tcp,
            port   => '557',
            action => accept,
            src_range => '392.168.1.1-192.168.1.10',
          }
        EOS

        apply_manifest(pp, :expect_failures => true) do |r|
          expect(r.stderr).to match(/Invalid value "392.168.1.1-192.168.1.10"/)
        end
      end

      it 'should not contain the rule' do
         shell('iptables-save') do |r|
           expect(r.stdout).to_not match(/-A INPUT -p tcp -m iprange --src-range 392.168.1.1-192.168.1.10 -m multiport --ports 557 -m comment --comment "557 - test" -j ACCEPT/)
         end
      end
    end
  end

  describe 'destination' do
    context '192.168.2.0/24' do
      it 'applies' do
        pp = <<-EOS
          class { '::firewall': }
          firewall { '558 - test':
            proto  => tcp,
            port   => '558',
            action => accept,
            destination => '192.168.2.0/24',
          }
        EOS

        apply_manifest(pp, :catch_failures => true)
        apply_manifest(pp, :catch_changes => true)
      end

      it 'should contain the rule' do
         shell('iptables-save') do |r|
           expect(r.stdout).to match(/-A INPUT -d 192.168.2.0\/(24|255\.255\.255\.0) -p tcp -m multiport --ports 558 -m comment --comment "558 - test" -j ACCEPT/)
         end
      end
    end

    context '! 192.168.2.0/24' do
      it 'applies' do
        pp = <<-EOS
          class { '::firewall': }
          firewall { '558 - test':
            proto  => tcp,
            port   => '558',
            action => accept,
            destination => '! 192.168.2.0/24',
          }
        EOS

        apply_manifest(pp, :catch_failures => true)
        apply_manifest(pp, :catch_changes => true)
      end

      it 'should contain the rule' do
         shell('iptables-save') do |r|
           expect(r.stdout).to match(/-A INPUT (! -d|-d !) 192.168.2.0\/(24|255\.255\.255\.0) -p tcp -m multiport --ports 558 -m comment --comment "558 - test" -j ACCEPT/)
         end
      end
    end

    # Invalid address
    context '256.168.2.0/24' do
      it 'applies' do
        pp = <<-EOS
          class { '::firewall': }
          firewall { '558 - test':
            proto  => tcp,
            port   => '558',
            action => accept,
            destination => '256.168.2.0/24',
          }
        EOS

        apply_manifest(pp, :expect_failures => true) do |r|
          expect(r.stderr).to match(/host_to_ip failed for 256.168.2.0\/(24|255\.255\.255\.0)/)
        end
      end

      it 'should not contain the rule' do
         shell('iptables-save') do |r|
           expect(r.stdout).to_not match(/-A INPUT -d 256.168.2.0\/(24|255\.255\.255\.0) -p tcp -m multiport --ports 558 -m comment --comment "558 - test" -j ACCEPT/)
         end
      end
    end
  end

  describe 'dst_range' do
    context '192.168.1.1-192.168.1.10' do
      it 'applies' do
        pp = <<-EOS
          class { '::firewall': }
          firewall { '559 - test':
            proto  => tcp,
            port   => '559',
            action => accept,
            dst_range => '192.168.1.1-192.168.1.10',
          }
        EOS

        apply_manifest(pp, :catch_failures => true)
        apply_manifest(pp, :catch_changes => true)
      end

      it 'should contain the rule' do
         shell('iptables-save') do |r|
           expect(r.stdout).to match(/-A INPUT -p tcp -m iprange --dst-range 192.168.1.1-192.168.1.10 -m multiport --ports 559 -m comment --comment "559 - test" -j ACCEPT/)
         end
      end
    end

    # Invalid IP
    context '392.168.1.1-192.168.1.10' do
      it 'applies' do
        pp = <<-EOS
          class { '::firewall': }
          firewall { '559 - test':
            proto  => tcp,
            port   => '559',
            action => accept,
            dst_range => '392.168.1.1-192.168.1.10',
          }
        EOS

        apply_manifest(pp, :expect_failures => true) do |r|
          expect(r.stderr).to match(/Invalid value "392.168.1.1-192.168.1.10"/)
        end
      end

      it 'should not contain the rule' do
         shell('iptables-save') do |r|
           expect(r.stdout).to_not match(/-A INPUT -p tcp -m iprange --dst-range 392.168.1.1-192.168.1.10 -m multiport --ports 559 -m comment --comment "559 - test" -j ACCEPT/)
         end
      end
    end
  end

  describe 'sport' do
    context 'single port' do
      it 'applies' do
        pp = <<-EOS
          class { '::firewall': }
          firewall { '560 - test':
            proto  => tcp,
            sport  => '560',
            action => accept,
          }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      it 'should contain the rule' do
         shell('iptables-save') do |r|
           expect(r.stdout).to match(/-A INPUT -p tcp -m multiport --sports 560 -m comment --comment "560 - test" -j ACCEPT/)
         end
      end
    end

    context 'multiple ports' do
      it 'applies' do
        pp = <<-EOS
          class { '::firewall': }
          firewall { '560 - test':
            proto  => tcp,
            sport  => '560-561',
            action => accept,
          }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      it 'should contain the rule' do
         shell('iptables-save') do |r|
           expect(r.stdout).to match(/-A INPUT -p tcp -m multiport --sports 560:561 -m comment --comment "560 - test" -j ACCEPT/)
         end
      end
    end

    context 'invalid ports' do
      it 'applies' do
        pp = <<-EOS
          class { '::firewall': }
          firewall { '560 - test':
            proto  => tcp,
            sport  => '9999560-561',
            action => accept,
          }
        EOS

        apply_manifest(pp, :expect_failures => true) do |r|
          expect(r.stderr).to match(/invalid port\/service `9999560' specified/)
        end
      end

      it 'should contain the rule' do
         shell('iptables-save') do |r|
           expect(r.stdout).to_not match(/-A INPUT -p tcp -m multiport --sports 9999560-561 -m comment --comment "560 - test" -j ACCEPT/)
         end
      end
    end
  end

  describe 'dport' do
    context 'single port' do
      it 'applies' do
        pp = <<-EOS
          class { '::firewall': }
          firewall { '561 - test':
            proto  => tcp,
            dport  => '561',
            action => accept,
          }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      it 'should contain the rule' do
         shell('iptables-save') do |r|
           expect(r.stdout).to match(/-A INPUT -p tcp -m multiport --dports 561 -m comment --comment "561 - test" -j ACCEPT/)
         end
      end
    end

    context 'multiple ports' do
      it 'applies' do
        pp = <<-EOS
          class { '::firewall': }
          firewall { '561 - test':
            proto  => tcp,
            dport  => '561-562',
            action => accept,
          }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      it 'should contain the rule' do
         shell('iptables-save') do |r|
           expect(r.stdout).to match(/-A INPUT -p tcp -m multiport --dports 561:562 -m comment --comment "561 - test" -j ACCEPT/)
         end
      end
    end

    context 'invalid ports' do
      it 'applies' do
        pp = <<-EOS
          class { '::firewall': }
          firewall { '561 - test':
            proto  => tcp,
            dport  => '9999561-562',
            action => accept,
          }
        EOS

        apply_manifest(pp, :expect_failures => true) do |r|
          expect(r.stderr).to match(/invalid port\/service `9999561' specified/)
        end
      end

      it 'should contain the rule' do
         shell('iptables-save') do |r|
           expect(r.stdout).to_not match(/-A INPUT -p tcp -m multiport --dports 9999561-562 -m comment --comment "560 - test" -j ACCEPT/)
         end
      end
    end
  end

  describe 'port' do
    context 'single port' do
      it 'applies' do
        pp = <<-EOS
          class { '::firewall': }
          firewall { '562 - test':
            proto  => tcp,
            port  => '562',
            action => accept,
          }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      it 'should contain the rule' do
         shell('iptables-save') do |r|
           expect(r.stdout).to match(/-A INPUT -p tcp -m multiport --ports 562 -m comment --comment "562 - test" -j ACCEPT/)
         end
      end
    end

    context 'multiple ports' do
      it 'applies' do
        pp = <<-EOS
          class { '::firewall': }
          firewall { '562 - test':
            proto  => tcp,
            port  => '562-563',
            action => accept,
          }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      it 'should contain the rule' do
         shell('iptables-save') do |r|
           expect(r.stdout).to match(/-A INPUT -p tcp -m multiport --ports 562:563 -m comment --comment "562 - test" -j ACCEPT/)
         end
      end
    end

    context 'invalid ports' do
      it 'applies' do
        pp = <<-EOS
          class { '::firewall': }
          firewall { '562 - test':
            proto  => tcp,
            port  => '9999562-563',
            action => accept,
          }
        EOS

        apply_manifest(pp, :expect_failures => true) do |r|
          expect(r.stderr).to match(/invalid port\/service `9999562' specified/)
        end
      end

      it 'should contain the rule' do
         shell('iptables-save') do |r|
           expect(r.stdout).to_not match(/-A INPUT -p tcp -m multiport --ports 9999562-563 -m comment --comment "562 - test" -j ACCEPT/)
         end
      end
    end
  end

  ['dst_type', 'src_type'].each do |type|
    describe "#{type}" do
      context 'MULTICAST' do
        it 'applies' do
          pp = <<-EOS
            class { '::firewall': }
            firewall { '563 - test':
              proto  => tcp,
              action => accept,
              #{type} => 'MULTICAST',
            }
          EOS

          apply_manifest(pp, :catch_failures => true)
        end

        it 'should contain the rule' do
          shell('iptables-save') do |r|
            expect(r.stdout).to match(/-A INPUT -p tcp -m addrtype\s.*\sMULTICAST -m comment --comment "563 - test" -j ACCEPT/)
          end
        end
      end

      context 'BROKEN' do
        it 'fails' do
          pp = <<-EOS
            class { '::firewall': }
            firewall { '563 - test':
              proto  => tcp,
              action => accept,
              #{type} => 'BROKEN',
            }
          EOS

          apply_manifest(pp, :expect_failures => true) do |r|
            expect(r.stderr).to match(/Invalid value "BROKEN"./)
          end
        end

        it 'should not contain the rule' do
          shell('iptables-save') do |r|
            expect(r.stdout).to_not match(/-A INPUT -p tcp -m addrtype\s.*\sBROKEN -m comment --comment "563 - test" -j ACCEPT/)
          end
        end
      end
    end
  end

  describe 'tcp_flags' do
    context 'FIN,SYN ACK' do
      it 'applies' do
        pp = <<-EOS
          class { '::firewall': }
          firewall { '564 - test':
            proto  => tcp,
            action => accept,
            tcp_flags => 'FIN,SYN ACK',
          }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      it 'should contain the rule' do
        shell('iptables-save') do |r|
          expect(r.stdout).to match(/-A INPUT -p tcp -m tcp --tcp-flags FIN,SYN ACK -m comment --comment "564 - test" -j ACCEPT/)
        end
      end
    end
  end

  describe 'chain' do
    context 'INPUT' do
      it 'applies' do
        pp = <<-EOS
          class { '::firewall': }
          firewall { '565 - test':
            proto  => tcp,
            action => accept,
            chain  => 'FORWARD',
          }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      it 'should contain the rule' do
        shell('iptables-save') do |r|
          expect(r.stdout).to match(/-A FORWARD -p tcp -m comment --comment "565 - test" -j ACCEPT/)
        end
      end
    end
  end

  describe 'table' do
    context 'mangle' do
      it 'applies' do
        pp = <<-EOS
          class { '::firewall': }
          firewall { '566 - test':
            proto  => tcp,
            action => accept,
            table  => 'mangle',
          }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      it 'should contain the rule' do
        shell('iptables-save -t mangle') do |r|
          expect(r.stdout).to match(/-A INPUT -p tcp -m comment --comment "566 - test" -j ACCEPT/)
        end
      end
    end
    context 'nat' do
      it 'applies' do
        pp = <<-EOS
          class { '::firewall': }
          firewall { '566 - test2':
            proto  => tcp,
            action => accept,
            table  => 'nat',
            chain  => 'OUTPUT',
          }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      it 'should not contain the rule' do
        shell('iptables-save -t nat') do |r|
          expect(r.stdout).to match(/-A OUTPUT -p tcp -m comment --comment "566 - test2" -j ACCEPT/)
        end
      end
    end
  end

  describe 'jump' do
    after :all do
      iptables_flush_all_tables
      expect(shell('iptables -t filter -X TEST').stderr).to eq("")
    end

    context 'MARK' do
      it 'applies' do
        pp = <<-EOS
          class { '::firewall': }
          firewallchain { 'TEST:filter:IPv4':
            ensure => present,
          }
          firewall { '567 - test':
            proto  => tcp,
            chain  => 'INPUT',
            jump  => 'TEST',
          }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      it 'should contain the rule' do
        shell('iptables-save') do |r|
          expect(r.stdout).to match(/-A INPUT -p tcp -m comment --comment "567 - test" -j TEST/)
        end
      end
    end

    context 'jump and apply' do
      it 'applies' do
        pp = <<-EOS
          class { '::firewall': }
          firewallchain { 'TEST:filter:IPv4':
            ensure => present,
          }
          firewall { '568 - test':
            proto  => tcp,
            chain  => 'INPUT',
            action => 'accept',
            jump  => 'TEST',
          }
        EOS

        apply_manifest(pp, :expect_failures => true) do |r|
          expect(r.stderr).to match(/Only one of the parameters 'action' and 'jump' can be set/)
        end
      end

      it 'should not contain the rule' do
        shell('iptables-save') do |r|
          expect(r.stdout).to_not match(/-A INPUT -p tcp -m comment --comment "568 - test" -j TEST/)
        end
      end
    end
  end

  describe 'tosource' do
    context '192.168.1.1' do
      it 'applies' do
        pp = <<-EOS
          class { '::firewall': }
          firewall { '568 - test':
            proto  => tcp,
            table  => 'nat',
            chain  => 'POSTROUTING',
            jump  => 'SNAT',
            tosource => '192.168.1.1',
          }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      it 'should contain the rule' do
        shell('iptables-save -t nat') do |r|
          expect(r.stdout).to match(/A POSTROUTING -p tcp -m comment --comment "568 - test" -j SNAT --to-source 192.168.1.1/)
        end
      end
    end
  end

  describe 'todest' do
    context '192.168.1.1' do
      it 'applies' do
        pp = <<-EOS
          class { '::firewall': }
          firewall { '569 - test':
            proto  => tcp,
            table  => 'nat',
            chain  => 'PREROUTING',
            jump   => 'DNAT',
            source => '200.200.200.200',
            todest => '192.168.1.1',
          }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      it 'should contain the rule' do
        shell('iptables-save -t nat') do |r|
          expect(r.stdout).to match(/-A PREROUTING -s 200.200.200.200(\/32)? -p tcp -m comment --comment "569 - test" -j DNAT --to-destination 192.168.1.1/)
        end
      end
    end
  end

  describe 'toports' do
    context '192.168.1.1' do
      it 'applies' do
        pp = <<-EOS
          class { '::firewall': }
          firewall { '570 - test':
            proto  => icmp,
            table  => 'nat',
            chain  => 'PREROUTING',
            jump  => 'REDIRECT',
            toports => '2222',
          }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      it 'should contain the rule' do
        shell('iptables-save -t nat') do |r|
          expect(r.stdout).to match(/-A PREROUTING -p icmp -m comment --comment "570 - test" -j REDIRECT --to-ports 2222/)
        end
      end
    end
  end

  # RHEL5 does not support --random
  if default['platform'] !~ /el-5/
    describe 'random' do
      context '192.168.1.1' do
        it 'applies' do
          pp = <<-EOS
            class { '::firewall': }
            firewall { '570 - test 2':
              proto  => all,
              table  => 'nat',
              chain  => 'POSTROUTING',
              jump   => 'MASQUERADE',
              source => '172.30.0.0/16',
              random => true
            }
          EOS

          apply_manifest(pp, :catch_failures => true)
          apply_manifest(pp, :catch_changes => true)
        end

        it 'should contain the rule' do
          shell('iptables-save -t nat') do |r|
            expect(r.stdout).to match(/-A POSTROUTING -s 172\.30\.0\.0\/16 -m comment --comment "570 - test 2" -j MASQUERADE --random/)
          end
        end
      end
    end
  end

  describe 'icmp' do
    context 'any' do
      it 'fails' do
        pp = <<-EOS
          class { '::firewall': }
          firewall { '571 - test':
            proto  => icmp,
            icmp   => 'any',
          }
        EOS

        apply_manifest(pp, :expect_failures => true) do |r|
          expect(r.stderr).to match(/This behaviour should be achieved by omitting or undefining the ICMP parameter/)
        end
      end

      it 'should not contain the rule' do
        shell('iptables-save') do |r|
          expect(r.stdout).to_not match(/-A INPUT -p icmp -m comment --comment "570 - test" -m icmp --icmp-type 11/)
        end
      end
    end
  end

  #iptables version 1.3.5 is not suppored by the ip6tables provider
  if default['platform'] !~ /el-5/
    describe 'hop_limit' do
      context '5' do
        it 'applies' do
          pp = <<-EOS
            class { '::firewall': }
            firewall { '571 - test':
              ensure => present,
              proto => tcp,
              port   => '571',
              action => accept,
              hop_limit => '5',
              provider => 'ip6tables',
            }
          EOS

          apply_manifest(pp, :catch_failures => true)
        end

        it 'should contain the rule' do
          shell('ip6tables-save') do |r|
            expect(r.stdout).to match(/-A INPUT -p tcp -m multiport --ports 571 -m comment --comment "571 - test" -m hl --hl-eq 5 -j ACCEPT/)
          end
        end
      end

      context 'invalid' do
        it 'applies' do
          pp = <<-EOS
            class { '::firewall': }
            firewall { '571 - test':
              ensure => present,
              proto => tcp,
              port   => '571',
              action => accept,
              hop_limit => 'invalid',
              provider => 'ip6tables',
            }
          EOS

          apply_manifest(pp, :expect_failures => true) do |r|
            expect(r.stderr).to match(/Invalid value "invalid"./)
          end
        end

        it 'should not contain the rule' do
          shell('ip6tables-save') do |r|
            expect(r.stdout).to_not match(/-A INPUT -p tcp -m multiport --ports 571 -m comment --comment "571 - test" -m hl --hl-eq invalid -j ACCEPT/)
          end
        end
      end
    end

    describe 'ishasmorefrags' do
      context 'true' do
        it 'applies' do
          pp = <<-EOS
            class { '::firewall': }
            firewall { '587 - test':
              ensure => present,
              proto => tcp,
              port   => '587',
              action => accept,
              ishasmorefrags => true,
              provider => 'ip6tables',
            }
          EOS

          apply_manifest(pp, :catch_failures => true)
        end

        it 'should contain the rule' do
          shell('ip6tables-save') do |r|
            expect(r.stdout).to match(/A INPUT -p tcp -m frag --fragid 0 --fragmore -m multiport --ports 587 -m comment --comment "587 - test" -j ACCEPT/)
          end
        end
      end

      context 'false' do
        it 'applies' do
          pp = <<-EOS
            class { '::firewall': }
            firewall { '588 - test':
              ensure => present,
              proto => tcp,
              port   => '588',
              action => accept,
              ishasmorefrags => false,
              provider => 'ip6tables',
            }
          EOS

          apply_manifest(pp, :catch_failures => true)
        end

        it 'should contain the rule' do
          shell('ip6tables-save') do |r|
            expect(r.stdout).to match(/-A INPUT -p tcp -m multiport --ports 588 -m comment --comment "588 - test" -j ACCEPT/)
          end
        end
      end
    end

    describe 'islastfrag' do
      context 'true' do
        it 'applies' do
          pp = <<-EOS
            class { '::firewall': }
            firewall { '589 - test':
              ensure => present,
              proto => tcp,
              port   => '589',
              action => accept,
              islastfrag => true,
              provider => 'ip6tables',
            }
          EOS

          apply_manifest(pp, :catch_failures => true)
        end

        it 'should contain the rule' do
          shell('ip6tables-save') do |r|
            expect(r.stdout).to match(/-A INPUT -p tcp -m frag --fragid 0 --fraglast -m multiport --ports 589 -m comment --comment "589 - test" -j ACCEPT/)
          end
        end
      end

      context 'false' do
        it 'applies' do
          pp = <<-EOS
            class { '::firewall': }
            firewall { '590 - test':
              ensure => present,
              proto => tcp,
              port   => '590',
              action => accept,
              islastfrag => false,
              provider => 'ip6tables',
            }
          EOS

          apply_manifest(pp, :catch_failures => true)
        end

        it 'should contain the rule' do
          shell('ip6tables-save') do |r|
            expect(r.stdout).to match(/-A INPUT -p tcp -m multiport --ports 590 -m comment --comment "590 - test" -j ACCEPT/)
          end
        end
      end
    end

    describe 'isfirstfrag' do
      context 'true' do
        it 'applies' do
          pp = <<-EOS
            class { '::firewall': }
            firewall { '591 - test':
              ensure => present,
              proto => tcp,
              port   => '591',
              action => accept,
              isfirstfrag => true,
              provider => 'ip6tables',
            }
          EOS

          apply_manifest(pp, :catch_failures => true)
        end

        it 'should contain the rule' do
          shell('ip6tables-save') do |r|
            expect(r.stdout).to match(/-A INPUT -p tcp -m frag --fragid 0 --fragfirst -m multiport --ports 591 -m comment --comment "591 - test" -j ACCEPT/)
          end
        end
      end

      context 'false' do
        it 'applies' do
          pp = <<-EOS
            class { '::firewall': }
            firewall { '592 - test':
              ensure => present,
              proto => tcp,
              port   => '592',
              action => accept,
              isfirstfrag => false,
              provider => 'ip6tables',
            }
          EOS

          apply_manifest(pp, :catch_failures => true)
        end

        it 'should contain the rule' do
          shell('ip6tables-save') do |r|
            expect(r.stdout).to match(/-A INPUT -p tcp -m multiport --ports 592 -m comment --comment "592 - test" -j ACCEPT/)
          end
        end
      end
    end
  end

  describe 'limit' do
    context '500/sec' do
      it 'applies' do
        pp = <<-EOS
          class { '::firewall': }
          firewall { '572 - test':
            ensure => present,
            proto => tcp,
            port   => '572',
            action => accept,
            limit => '500/sec',
          }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      it 'should contain the rule' do
        shell('iptables-save') do |r|
          expect(r.stdout).to match(/-A INPUT -p tcp -m multiport --ports 572 -m comment --comment "572 - test" -m limit --limit 500\/sec -j ACCEPT/)
        end
      end
    end
  end

  describe 'burst' do
    context '500' do
      it 'applies' do
        pp = <<-EOS
          class { '::firewall': }
          firewall { '573 - test':
            ensure => present,
            proto => tcp,
            port   => '573',
            action => accept,
            limit => '500/sec',
            burst => '1500',
          }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      it 'should contain the rule' do
        shell('iptables-save') do |r|
          expect(r.stdout).to match(/-A INPUT -p tcp -m multiport --ports 573 -m comment --comment "573 - test" -m limit --limit 500\/sec --limit-burst 1500 -j ACCEPT/)
        end
      end
    end

    context 'invalid' do
      it 'applies' do
        pp = <<-EOS
          class { '::firewall': }
          firewall { '571 - test':
            ensure => present,
            proto => tcp,
            port   => '571',
            action => accept,
            limit => '500/sec',
            burst => '1500/sec',
          }
        EOS

        apply_manifest(pp, :expect_failures => true) do |r|
          expect(r.stderr).to match(/Invalid value "1500\/sec"./)
        end
      end

      it 'should not contain the rule' do
        shell('iptables-save') do |r|
          expect(r.stdout).to_not match(/-A INPUT -p tcp -m multiport --ports 573 -m comment --comment "573 - test" -m limit --limit 500\/sec --limit-burst 1500\/sec -j ACCEPT/)
        end
      end
    end
  end

  describe 'uid' do
    context 'nobody' do
      it 'applies' do
        pp = <<-EOS
          class { '::firewall': }
          firewall { '574 - test':
            ensure => present,
            proto => tcp,
            chain => 'OUTPUT',
            port   => '574',
            action => accept,
            uid => 'nobody',
          }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      it 'should contain the rule' do
        shell('iptables-save') do |r|
          expect(r.stdout).to match(/-A OUTPUT -p tcp -m owner --uid-owner (nobody|\d+) -m multiport --ports 574 -m comment --comment "574 - test" -j ACCEPT/)
        end
      end
    end
  end

  describe 'gid' do
    context 'root' do
      it 'applies' do
        pp = <<-EOS
          class { '::firewall': }
          firewall { '575 - test':
            ensure => present,
            proto => tcp,
            chain => 'OUTPUT',
            port   => '575',
            action => accept,
            gid => 'root',
          }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      it 'should contain the rule' do
        shell('iptables-save') do |r|
          expect(r.stdout).to match(/-A OUTPUT -p tcp -m owner --gid-owner (root|\d+) -m multiport --ports 575 -m comment --comment "575 - test" -j ACCEPT/)
        end
      end
    end
  end

  #iptables version 1.3.5 does not support masks on MARK rules
  if default['platform'] !~ /el-5/
    describe 'set_mark' do
      context '0x3e8/0xffffffff' do
        it 'applies' do
          pp = <<-EOS
            class { '::firewall': }
            firewall { '580 - test':
              ensure => present,
              chain => 'OUTPUT',
              proto => tcp,
              port   => '580',
              jump => 'MARK',
              table => 'mangle',
              set_mark => '0x3e8/0xffffffff',
            }
          EOS

          apply_manifest(pp, :catch_failures => true)
        end

        it 'should contain the rule' do
          shell('iptables-save -t mangle') do |r|
            expect(r.stdout).to match(/-A OUTPUT -p tcp -m multiport --ports 580 -m comment --comment "580 - test" -j MARK --set-xmark 0x3e8\/0xffffffff/)
          end
        end
      end
    end
  end

  describe 'pkttype' do
    context 'multicast' do
      it 'applies' do
        pp = <<-EOS
          class { '::firewall': }
          firewall { '581 - test':
            ensure => present,
            proto => tcp,
            port   => '581',
            action => accept,
            pkttype => 'multicast',
          }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      it 'should contain the rule' do
        shell('iptables-save') do |r|
          expect(r.stdout).to match(/-A INPUT -p tcp -m multiport --ports 581 -m pkttype --pkt-type multicast -m comment --comment "581 - test" -j ACCEPT/)
        end
      end
    end

    context 'test' do
      it 'applies' do
        pp = <<-EOS
          class { '::firewall': }
          firewall { '582 - test':
            ensure => present,
            proto => tcp,
            port   => '582',
            action => accept,
            pkttype => 'test',
          }
        EOS

        apply_manifest(pp, :expect_failures => true) do |r|
          expect(r.stderr).to match(/Invalid value "test"./)
        end
      end

      it 'should not contain the rule' do
        shell('iptables-save') do |r|
          expect(r.stdout).to_not match(/-A INPUT -p tcp -m multiport --ports 582 -m pkttype --pkt-type multicast -m comment --comment "582 - test" -j ACCEPT/)
        end
      end
    end
  end

  describe 'isfragment' do
    context 'true' do
      it 'applies' do
        pp = <<-EOS
          class { '::firewall': }
          firewall { '583 - test':
            ensure => present,
            proto => tcp,
            port   => '583',
            action => accept,
            isfragment => true,
          }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      it 'should contain the rule' do
        shell('iptables-save') do |r|
          expect(r.stdout).to match(/-A INPUT -p tcp -f -m multiport --ports 583 -m comment --comment "583 - test" -j ACCEPT/)
        end
      end
    end

    context 'false' do
      it 'applies' do
        pp = <<-EOS
          class { '::firewall': }
          firewall { '584 - test':
            ensure => present,
            proto => tcp,
            port   => '584',
            action => accept,
            isfragment => false,
          }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      it 'should contain the rule' do
        shell('iptables-save') do |r|
          expect(r.stdout).to match(/-A INPUT -p tcp -m multiport --ports 584 -m comment --comment "584 - test" -j ACCEPT/)
        end
      end
    end
  end

  # RHEL5/SLES does not support -m socket
  describe 'socket', :unless => (default['platform'] =~ /el-5/ or fact('operatingsystem') == 'SLES') do
    context 'true' do
      it 'applies' do
        pp = <<-EOS
          class { '::firewall': }
          firewall { '585 - test':
            ensure => present,
            proto => tcp,
            port   => '585',
            action => accept,
            chain  => 'PREROUTING',
            table  => 'nat',
            socket => true,
          }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      it 'should contain the rule' do
        shell('iptables-save -t nat') do |r|
          expect(r.stdout).to match(/-A PREROUTING -p tcp -m multiport --ports 585 -m socket -m comment --comment "585 - test" -j ACCEPT/)
        end
      end
    end

    context 'false' do
      it 'applies' do
        pp = <<-EOS
          class { '::firewall': }
          firewall { '586 - test':
            ensure => present,
            proto => tcp,
            port   => '586',
            action => accept,
            chain  => 'PREROUTING',
            table  => 'nat',
            socket => false,
          }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      it 'should contain the rule' do
        shell('iptables-save -t nat') do |r|
          expect(r.stdout).to match(/-A PREROUTING -p tcp -m multiport --ports 586 -m comment --comment "586 - test" -j ACCEPT/)
        end
      end
    end
  end

  describe 'ipsec_policy' do
    context 'ipsec' do
      it 'applies' do
        pp = <<-EOS
          class { '::firewall': }
          firewall { '593 - test':
            ensure       => 'present',
            action       => 'reject',
            chain        => 'OUTPUT',
            destination  => '20.0.0.0/8',
            ipsec_dir    => 'out',
            ipsec_policy => 'ipsec',
            proto        => 'all',
            reject       => 'icmp-net-unreachable',
            table        => 'filter',
          }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      it 'should contain the rule' do
        shell('iptables-save') do |r|
          expect(r.stdout).to match(/-A OUTPUT -d 20.0.0.0\/(8|255\.0\.0\.0) -m comment --comment "593 - test" -m policy --dir out --pol ipsec -j REJECT --reject-with icmp-net-unreachable/)
        end
      end
    end

    context 'none' do
      it 'applies' do
        pp = <<-EOS
          class { '::firewall': }
          firewall { '594 - test':
            ensure       => 'present',
            action       => 'reject',
            chain        => 'OUTPUT',
            destination  => '20.0.0.0/8',
            ipsec_dir    => 'out',
            ipsec_policy => 'none',
            proto        => 'all',
            reject       => 'icmp-net-unreachable',
            table        => 'filter',
          }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      it 'should contain the rule' do
        shell('iptables-save') do |r|
          expect(r.stdout).to match(/-A OUTPUT -d 20.0.0.0\/(8|255\.0\.0\.0) -m comment --comment "594 - test" -m policy --dir out --pol none -j REJECT --reject-with icmp-net-unreachable/)
        end
      end
    end
  end

  describe 'ipsec_dir' do
    context 'out' do
      it 'applies' do
        pp = <<-EOS
          class { '::firewall': }
          firewall { '595 - test':
            ensure       => 'present',
            action       => 'reject',
            chain        => 'OUTPUT',
            destination  => '20.0.0.0/8',
            ipsec_dir    => 'out',
            ipsec_policy => 'ipsec',
            proto        => 'all',
            reject       => 'icmp-net-unreachable',
            table        => 'filter',
          }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      it 'should contain the rule' do
        shell('iptables-save') do |r|
          expect(r.stdout).to match(/-A OUTPUT -d 20.0.0.0\/(8|255\.0\.0\.0) -m comment --comment "595 - test" -m policy --dir out --pol ipsec -j REJECT --reject-with icmp-net-unreachable/)
        end
      end
    end

    context 'in' do
      it 'applies' do
        pp = <<-EOS
          class { '::firewall': }
          firewall { '596 - test':
            ensure       => 'present',
            action       => 'reject',
            chain        => 'INPUT',
            destination  => '20.0.0.0/8',
            ipsec_dir    => 'in',
            ipsec_policy => 'none',
            proto        => 'all',
            reject       => 'icmp-net-unreachable',
            table        => 'filter',
          }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      it 'should contain the rule' do
        shell('iptables-save') do |r|
          expect(r.stdout).to match(/-A INPUT -d 20.0.0.0\/(8|255\.0\.0\.0) -m comment --comment "596 - test" -m policy --dir in --pol none -j REJECT --reject-with icmp-net-unreachable/)
        end
      end
    end
  end

  describe 'recent' do
    context 'set' do
      it 'applies' do
        pp = <<-EOS
          class { '::firewall': }
          firewall { '597 - test':
            ensure       => 'present',
            chain        => 'INPUT',
            destination  => '30.0.0.0/8',
            proto        => 'all',
            table        => 'filter',
            recent       => 'set',
            rdest        => true,
            rname        => 'list1',
          }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      it 'should contain the rule' do
        shell('iptables-save') do |r|
          # Mask added as of Ubuntu 14.04.
          expect(r.stdout).to match(/-A INPUT -d 30.0.0.0\/(8|255\.0\.0\.0) -m comment --comment "597 - test" -m recent --set --name list1 (--mask 255.255.255.255 )?--rdest/)
        end
      end
    end

    context 'rcheck' do
      it 'applies' do
        pp = <<-EOS
          class { '::firewall': }
          firewall { '598 - test':
            ensure       => 'present',
            chain        => 'INPUT',
            destination  => '30.0.0.0/8',
            proto        => 'all',
            table        => 'filter',
            recent       => 'rcheck',
            rsource      => true,
            rname        => 'list1',
            rseconds     => 60,
            rhitcount    => 5,
            rttl         => true,
          }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      it 'should contain the rule' do
        shell('iptables-save') do |r|
          expect(r.stdout).to match(/-A INPUT -d 30.0.0.0\/(8|255\.0\.0\.0) -m comment --comment "598 - test" -m recent --rcheck --seconds 60 --hitcount 5 --rttl --name list1 (--mask 255.255.255.255 )?--rsource/)
        end
      end
    end

    context 'update' do
      it 'applies' do
        pp = <<-EOS
          class { '::firewall': }
          firewall { '599 - test':
            ensure       => 'present',
            chain        => 'INPUT',
            destination  => '30.0.0.0/8',
            proto        => 'all',
            table        => 'filter',
            recent       => 'update',
          }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      it 'should contain the rule' do
        shell('iptables-save') do |r|
          expect(r.stdout).to match(/-A INPUT -d 30.0.0.0\/(8|255\.0\.0\.0) -m comment --comment "599 - test" -m recent --update/)
        end
      end
    end

    context 'remove' do
      it 'applies' do
        pp = <<-EOS
          class { '::firewall': }
          firewall { '600 - test':
            ensure       => 'present',
            chain        => 'INPUT',
            destination  => '30.0.0.0/8',
            proto        => 'all',
            table        => 'filter',
            recent       => 'remove',
          }
        EOS

        apply_manifest(pp, :catch_failures => true)
      end

      it 'should contain the rule' do
        shell('iptables-save') do |r|
          expect(r.stdout).to match(/-A INPUT -d 30.0.0.0\/(8|255\.0\.0\.0) -m comment --comment "600 - test" -m recent --remove/)
        end
      end
    end
  end

  describe 'reset' do
    it 'deletes all rules' do
      shell('ip6tables --flush')
      shell('iptables --flush; iptables -t nat --flush; iptables -t mangle --flush')
    end
  end

end
require 'spec_helper_acceptance'

describe 'puppet resource firewallchain command:' do
  before :all do
    iptables_flush_all_tables
  end
  describe 'ensure' do
    context 'present' do
      it 'applies cleanly' do
        pp = <<-EOS
          firewallchain { 'MY_CHAIN:filter:IPv4':
            ensure  => present,
          }
        EOS
        # Run it twice and test for idempotency
        apply_manifest(pp, :catch_failures => true)
        apply_manifest(pp, :catch_changes => true)
      end

      it 'finds the chain' do
        shell('iptables-save') do |r|
          expect(r.stdout).to match(/MY_CHAIN/)
        end
      end
    end

    context 'absent' do
      it 'applies cleanly' do
        pp = <<-EOS
          firewallchain { 'MY_CHAIN:filter:IPv4':
            ensure  => absent,
          }
        EOS
        # Run it twice and test for idempotency
        apply_manifest(pp, :catch_failures => true)
        apply_manifest(pp, :catch_changes => true)
      end

      it 'fails to find the chain' do
        shell('iptables-save') do |r|
          expect(r.stdout).to_not match(/MY_CHAIN/)
        end
      end
    end
  end

  # XXX purge => false is not yet implemented
  #context 'adding a firewall rule to a chain:' do
  #  it 'applies cleanly' do
  #    pp = <<-EOS
  #      firewallchain { 'MY_CHAIN:filter:IPv4':
  #        ensure  => present,
  #      }
  #      firewall { '100 my rule':
  #        chain   => 'MY_CHAIN',
  #        action  => 'accept',
  #        proto   => 'tcp',
  #        dport   => 5000,
  #      }
  #    EOS
  #    # Run it twice and test for idempotency
  #    apply_manifest(pp, :catch_failures => true)
  #    apply_manifest(pp, :catch_changes => true)
  #  end
  #end

  #context 'not purge firewallchain chains:' do
  #  it 'does not purge the rule' do
  #    pp = <<-EOS
  #      firewallchain { 'MY_CHAIN:filter:IPv4':
  #        ensure  => present,
  #        purge   => false,
  #        before  => Resources['firewall'],
  #      }
  #      resources { 'firewall':
  #        purge => true,
  #      }
  #    EOS
  #    # Run it twice and test for idempotency
  #    apply_manifest(pp, :catch_failures => true) do |r|
  #      expect(r.stdout).to_not match(/removed/)
  #      expect(r.stderr).to eq('')
  #    end
  #    apply_manifest(pp, :catch_changes => true)
  #  end

  #  it 'still has the rule' do
  #    pp = <<-EOS
  #      firewall { '100 my rule':
  #        chain   => 'MY_CHAIN',
  #        action  => 'accept',
  #        proto   => 'tcp',
  #        dport   => 5000,
  #      }
  #    EOS
  #    # Run it twice and test for idempotency
  #    apply_manifest(pp, :catch_changes => true)
  #  end
  #end

  describe 'policy' do
    after :all do
      shell('iptables -t filter -P FORWARD ACCEPT')
    end

    context 'DROP' do
      it 'applies cleanly' do
        pp = <<-EOS
          firewallchain { 'FORWARD:filter:IPv4':
            policy  => 'drop',
          }
        EOS
        # Run it twice and test for idempotency
        apply_manifest(pp, :catch_failures => true)
        apply_manifest(pp, :catch_changes => true)
      end

      it 'finds the chain' do
        shell('iptables-save') do |r|
          expect(r.stdout).to match(/FORWARD DROP/)
        end
      end
    end
  end
end
require 'spec_helper_acceptance'

if default['platform'] =~ /el-5/
  describe "firewall ip6tables doesn't work on 1.3.5 because --comment is missing" do
    before :all do
      ip6tables_flush_all_tables
    end

    it "can't use ip6tables" do
      pp = <<-EOS
        class { '::firewall': }
        firewall { '599 - test':
          ensure   => present,
          proto    => 'tcp',
          provider => 'ip6tables',
        }
      EOS
      expect(apply_manifest(pp, :expect_failures => true).stderr).to match(/ip6tables provider is not supported/)
    end
  end
else
  describe 'firewall ishasmorefrags/islastfrag/isfirstfrag properties' do
    before :all do
      ip6tables_flush_all_tables
    end

    shared_examples "is idempotent" do |values, line_match|
      it "changes the values to #{values}" do
        pp = <<-EOS
            class { '::firewall': }
            firewall { '599 - test':
              ensure   => present,
              proto    => 'tcp',
              provider => 'ip6tables',
              #{values}
            }
        EOS

        apply_manifest(pp, :catch_failures => true)
        apply_manifest(pp, :catch_changes => true)

        shell('ip6tables-save') do |r|
          expect(r.stdout).to match(/#{line_match}/)
        end
      end
    end
    shared_examples "doesn't change" do |values, line_match|
      it "doesn't change the values to #{values}" do
        pp = <<-EOS
            class { '::firewall': }
            firewall { '599 - test':
              ensure   => present,
              proto    => 'tcp',
              provider => 'ip6tables',
              #{values}
            }
        EOS

        apply_manifest(pp, :catch_changes => true)

        shell('ip6tables-save') do |r|
          expect(r.stdout).to match(/#{line_match}/)
        end
      end
    end

    describe 'adding a rule' do
      context 'when unset' do
        before :all do
          ip6tables_flush_all_tables
        end
        it_behaves_like 'is idempotent', '', /-A INPUT -p tcp -m comment --comment "599 - test"/
      end
      context 'when set to true' do
        before :all do
          ip6tables_flush_all_tables
        end
        it_behaves_like "is idempotent", 'ishasmorefrags => true, islastfrag => true, isfirstfrag => true', /-A INPUT -p tcp -m frag --fragid 0 --fragmore -m frag --fragid 0 --fraglast -m frag --fragid 0 --fragfirst -m comment --comment "599 - test"/
      end
      context 'when set to false' do
        before :all do
          ip6tables_flush_all_tables
        end
        it_behaves_like "is idempotent", 'ishasmorefrags => false, islastfrag => false, isfirstfrag => false', /-A INPUT -p tcp -m comment --comment "599 - test"/
      end
    end
    describe 'editing a rule' do
      context 'when unset or false' do
        before :each do
          ip6tables_flush_all_tables
          shell('ip6tables -A INPUT -p tcp -m comment --comment "599 - test"')
        end
        context 'and current value is false' do
          it_behaves_like "doesn't change", 'ishasmorefrags => false, islastfrag => false, isfirstfrag => false', /-A INPUT -p tcp -m comment --comment "599 - test"/
        end
        context 'and current value is true' do
          it_behaves_like "is idempotent", 'ishasmorefrags => true, islastfrag => true, isfirstfrag => true', /-A INPUT -p tcp -m frag --fragid 0 --fragmore -m frag --fragid 0 --fraglast -m frag --fragid 0 --fragfirst -m comment --comment "599 - test"/
        end
      end
      context 'when set to true' do
        before :each do
          ip6tables_flush_all_tables
          shell('ip6tables -A INPUT -p tcp -m frag --fragid 0 --fragmore -m frag --fragid 0 --fraglast -m frag --fragid 0 --fragfirst -m comment --comment "599 - test"')
        end
        context 'and current value is false' do
          it_behaves_like "is idempotent", 'ishasmorefrags => false, islastfrag => false, isfirstfrag => false', /-A INPUT -p tcp -m comment --comment "599 - test"/
        end
        context 'and current value is true' do
          it_behaves_like "doesn't change", 'ishasmorefrags => true, islastfrag => true, isfirstfrag => true', /-A INPUT -p tcp -m frag --fragid 0 --fragmore -m frag --fragid 0 --fraglast -m frag --fragid 0 --fragfirst -m comment --comment "599 - test"/
        end
      end
    end
  end
end
require 'spec_helper_acceptance'

describe 'firewall isfragment property' do
  before :all do
    iptables_flush_all_tables
  end

  shared_examples "is idempotent" do |value, line_match|
    it "changes the value to #{value}" do
      pp = <<-EOS
          class { '::firewall': }
          firewall { '597 - test':
            ensure => present,
            proto  => 'tcp',
            #{value}
          }
      EOS

      apply_manifest(pp, :catch_failures => true)
      apply_manifest(pp, :catch_changes => true)

      shell('iptables-save') do |r|
        expect(r.stdout).to match(/#{line_match}/)
      end
    end
  end
  shared_examples "doesn't change" do |value, line_match|
    it "doesn't change the value to #{value}" do
      pp = <<-EOS
          class { '::firewall': }
          firewall { '597 - test':
            ensure => present,
            proto  => 'tcp',
            #{value}
          }
      EOS

      apply_manifest(pp, :catch_changes => true)

      shell('iptables-save') do |r|
        expect(r.stdout).to match(/#{line_match}/)
      end
    end
  end

  describe 'adding a rule' do
    context 'when unset' do
      before :all do
        iptables_flush_all_tables
      end
      it_behaves_like 'is idempotent', '', /-A INPUT -p tcp -m comment --comment "597 - test"/
    end
    context 'when set to true' do
      before :all do
        iptables_flush_all_tables
      end
      it_behaves_like 'is idempotent', 'isfragment => true,', /-A INPUT -p tcp -f -m comment --comment "597 - test"/
    end
    context 'when set to false' do
      before :all do
        iptables_flush_all_tables
      end
      it_behaves_like "is idempotent", 'isfragment => false,', /-A INPUT -p tcp -m comment --comment "597 - test"/
    end
  end
  describe 'editing a rule' do
    context 'when unset or false' do
      before :each do
        iptables_flush_all_tables
        shell('iptables -A INPUT -p tcp -m comment --comment "597 - test"')
      end
      context 'and current value is false' do
        it_behaves_like "doesn't change", 'isfragment => false,', /-A INPUT -p tcp -m comment --comment "597 - test"/
      end
      context 'and current value is true' do
        it_behaves_like "is idempotent", 'isfragment => true,', /-A INPUT -p tcp -f -m comment --comment "597 - test"/
      end
    end
    context 'when set to true' do
      before :each do
        iptables_flush_all_tables
        shell('iptables -A INPUT -p tcp -f -m comment --comment "597 - test"')
      end
      context 'and current value is false' do
        it_behaves_like "is idempotent", 'isfragment => false,', /-A INPUT -p tcp -m comment --comment "597 - test"/
      end
      context 'and current value is true' do
        it_behaves_like "doesn't change", 'isfragment => true,', /-A INPUT -p tcp -f -m comment --comment "597 - test"/
      end
    end
  end
end
HOSTS:
  centos-59-x64:
    roles:
      - master
      - database
      - console
    platform: el-5-x86_64
    box : centos-59-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-59-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: pe
HOSTS:
  centos-59-x64:
    roles:
      - master
    platform: el-5-x86_64
    box : centos-59-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-59-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: foss
HOSTS:
  centos-64-x64:
    roles:
      - master
    platform: el-6-x86_64
    box : centos-64-x64-fusion503-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x64-fusion503-nocm.box
    hypervisor : fusion
CONFIG:
  type: foss
HOSTS:
  centos-64-x64:
    roles:
      - master
      - database
      - dashboard
    platform: el-6-x86_64
    box : centos-64-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: pe
HOSTS:
  centos-64-x64:
    roles:
      - master
    platform: el-6-x86_64
    box : centos-64-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: foss
HOSTS:
  debian-607-x64:
    roles:
      - master
    platform: debian-6-amd64
    box : debian-607-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/debian-607-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: git
HOSTS:
  debian-70rc1-x64:
    roles:
      - master
    platform: debian-7-amd64
    box : debian-70rc1-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/debian-70rc1-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: git
HOSTS:
  centos-64-x64:
    roles:
      - master
    platform: el-6-x86_64
    box : centos-64-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: foss
HOSTS:
  fedora-18-x64:
    roles:
      - master
    platform: fedora-18-x86_64
    box : fedora-18-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/fedora-18-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: git
HOSTS:
  sles-11sp1-x64:
    roles:
      - master
    platform: sles-11-x86_64
    box : sles-11sp1-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/sles-11sp1-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: git
HOSTS:
  ubuntu-server-10044-x64:
    roles:
      - master
    platform: ubuntu-10.04-amd64
    box : ubuntu-server-10044-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/ubuntu-server-10044-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: git
HOSTS:
  ubuntu-server-12042-x64:
    roles:
      - master
    platform: ubuntu-12.04-amd64
    box : ubuntu-server-12042-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/ubuntu-server-12042-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: foss
HOSTS:
  ubuntu-server-1404-x64:
    roles:
      - master
    platform: ubuntu-14.04-64
    box: puppetlabs/ubuntu-14.04-64-nocm
    hypervisor : vagrant
CONFIG:
  type: foss
require 'spec_helper_acceptance'

describe "param based tests:" do
  # Takes a hash and converts it into a firewall resource
  def pp(params)
    name = params.delete('name') || '100 test'
    pm = <<-EOS
firewall { '#{name}':
    EOS

    params.each do |k,v|
      pm += <<-EOS
  #{k} => #{v},
      EOS
    end

    pm += <<-EOS
}
    EOS
    pm
  end

  it 'test various params', :unless => (default['platform'].match(/el-5/) || fact('operatingsystem') == 'SLES') do
    iptables_flush_all_tables

    ppm = pp({
      'table' => "'raw'",
      'socket' => 'true',
      'chain' => "'PREROUTING'",
      'jump' => 'LOG',
      'log_level' => 'debug',
    })

    expect(apply_manifest(ppm, :catch_failures => true).exit_code).to eq(2)
    expect(apply_manifest(ppm, :catch_failures => true).exit_code).to be_zero
  end

  it 'test log rule' do
    iptables_flush_all_tables

    ppm = pp({
      'name' => '998 log all',
      'proto' => 'all',
      'jump' => 'LOG',
      'log_level' => 'debug',
    })
    expect(apply_manifest(ppm, :catch_failures => true).exit_code).to eq(2)
    expect(apply_manifest(ppm, :catch_failures => true).exit_code).to be_zero
  end

  it 'test log rule - changing names' do
    iptables_flush_all_tables

    ppm1 = pp({
      'name' => '004 log all INVALID packets',
      'chain' => 'INPUT',
      'proto' => 'all',
      'ctstate' => 'INVALID',
      'jump' => 'LOG',
      'log_level' => '3',
      'log_prefix' => '"IPTABLES dropped invalid: "',
    })

    ppm2 = pp({
      'name' => '003 log all INVALID packets',
      'chain' => 'INPUT',
      'proto' => 'all',
      'ctstate' => 'INVALID',
      'jump' => 'LOG',
      'log_level' => '3',
      'log_prefix' => '"IPTABLES dropped invalid: "',
    })

    expect(apply_manifest(ppm1, :catch_failures => true).exit_code).to eq(2)

    ppm = <<-EOS + "\n" + ppm2
      resources { 'firewall':
        purge => true,
      }
    EOS
    expect(apply_manifest(ppm, :catch_failures => true).exit_code).to eq(2)
  end

  it 'test chain - changing names' do
    iptables_flush_all_tables

    ppm1 = pp({
      'name'  => '004 with a chain',
      'chain' => 'INPUT',
      'proto' => 'all',
    })

    ppm2 = pp({
      'name'  => '004 with a chain',
      'chain' => 'OUTPUT',
      'proto' => 'all',
    })

    apply_manifest(ppm1, :expect_changes => true)

    ppm = <<-EOS + "\n" + ppm2
      resources { 'firewall':
        purge => true,
      }
    EOS
    expect(apply_manifest(ppm2, :expect_failures => true).stderr).to match(/is not supported/)
  end

  it 'test log rule - idempotent' do
    iptables_flush_all_tables

    ppm1 = pp({
      'name' => '004 log all INVALID packets',
      'chain' => 'INPUT',
      'proto' => 'all',
      'ctstate' => 'INVALID',
      'jump' => 'LOG',
      'log_level' => '3',
      'log_prefix' => '"IPTABLES dropped invalid: "',
    })

    expect(apply_manifest(ppm1, :catch_failures => true).exit_code).to eq(2)
    expect(apply_manifest(ppm1, :catch_failures => true).exit_code).to be_zero
  end

  it 'test src_range rule' do
    iptables_flush_all_tables

    ppm = pp({
      'name'      => '997 block src ip range',
      'chain'     => 'INPUT',
      'proto'     => 'all',
      'action'    => 'drop',
      'src_range' => '"10.0.0.1-10.0.0.10"',
    })
    expect(apply_manifest(ppm, :catch_failures => true).exit_code).to eq(2)
    expect(apply_manifest(ppm, :catch_failures => true).exit_code).to be_zero
  end

  it 'test dst_range rule' do
    iptables_flush_all_tables

    ppm = pp({
      'name'      => '998 block dst ip range',
      'chain'     => 'INPUT',
      'proto'     => 'all',
      'action'    => 'drop',
      'dst_range' => '"10.0.0.2-10.0.0.20"',
    })
    expect(apply_manifest(ppm, :catch_failures => true).exit_code).to eq(2)
    expect(apply_manifest(ppm, :catch_failures => true).exit_code).to be_zero
  end

end
require 'spec_helper_acceptance'

describe "purge tests:" do
  context('resources purge') do
    before(:all) do
      iptables_flush_all_tables

      shell('iptables -A INPUT -s 1.2.1.2')
      shell('iptables -A INPUT -s 1.2.1.2')
    end

    it 'make sure duplicate existing rules get purged' do

      pp = <<-EOS
        class { 'firewall': }
        resources { 'firewall':
          purge => true,
        }
      EOS

      apply_manifest(pp, :expect_changes => true)
    end

    it 'saves' do
      shell('iptables-save') do |r|
        expect(r.stdout).to_not match(/1\.2\.1\.2/)
        expect(r.stderr).to eq("")
      end
    end
  end

  context('chain purge') do
    before(:each) do
      iptables_flush_all_tables

      shell('iptables -A INPUT -p tcp -s 1.2.1.1')
      shell('iptables -A INPUT -p udp -s 1.2.1.1')
      shell('iptables -A OUTPUT -s 1.2.1.2 -m comment --comment "010 output-1.2.1.2"')
    end

    it 'purges only the specified chain' do
      pp = <<-EOS
        class { 'firewall': }
        firewallchain { 'INPUT:filter:IPv4':
          purge => true,
        }
      EOS

      apply_manifest(pp, :expect_changes => true)

      shell('iptables-save') do |r|
        expect(r.stdout).to match(/010 output-1\.2\.1\.2/)
        expect(r.stdout).to_not match(/1\.2\.1\.1/)
        expect(r.stderr).to eq("")
      end
    end

    it 'ignores managed rules' do
      pp = <<-EOS
        class { 'firewall': }
        firewallchain { 'OUTPUT:filter:IPv4':
          purge => true,
        }
        firewall { '010 output-1.2.1.2':
          chain  => 'OUTPUT',
          proto  => 'all',
          source => '1.2.1.2',
        }
      EOS

      apply_manifest(pp, :catch_changes => true)
    end

    it 'ignores specified rules' do
      pp = <<-EOS
        class { 'firewall': }
        firewallchain { 'INPUT:filter:IPv4':
          purge => true,
          ignore => [
            '-s 1\.2\.1\.1',
          ],
        }
      EOS

      apply_manifest(pp, :catch_changes => true)
    end

    it 'adds managed rules with ignored rules' do
      pp = <<-EOS
        class { 'firewall': }
        firewallchain { 'INPUT:filter:IPv4':
          purge => true,
          ignore => [
            '-s 1\.2\.1\.1',
          ],
        }
        firewall { '014 input-1.2.1.6':
          chain  => 'INPUT',
          proto  => 'all',
          source => '1.2.1.6',
        }
        -> firewall { '013 input-1.2.1.5':
          chain  => 'INPUT',
          proto  => 'all',
          source => '1.2.1.5',
        }
        -> firewall { '012 input-1.2.1.4':
          chain  => 'INPUT',
          proto  => 'all',
          source => '1.2.1.4',
        }
        -> firewall { '011 input-1.2.1.3':
          chain  => 'INPUT',
          proto  => 'all',
          source => '1.2.1.3',
        }
      EOS

      apply_manifest(pp, :catch_failures => true)

      expect(shell('iptables-save').stdout).to match(/-A INPUT -s 1\.2\.1\.1(\/32)? -p tcp\s?\n-A INPUT -s 1\.2\.1\.1(\/32)? -p udp/)
    end
  end
end
require 'spec_helper_acceptance'

# Here we want to test the the resource commands ability to work with different
# existing ruleset scenarios. This will give the parsing capabilities of the
# code a good work out.
describe 'puppet resource firewall command:' do
  context 'make sure it returns no errors when executed on a clean machine' do
    it do
      shell('puppet resource firewall') do |r|
        r.exit_code.should be_zero
        # don't check stdout, some boxes come with rules, that is normal
        r.stderr.should be_empty
      end
    end
  end

  context 'flush iptables and make sure it returns nothing afterwards' do
    before(:all) do
      iptables_flush_all_tables
    end

    # No rules, means no output thanks. And no errors as well.
    it do
      shell('puppet resource firewall') do |r|
        r.exit_code.should be_zero
        r.stderr.should be_empty
        r.stdout.should == "\n"
      end
    end
  end

  context 'accepts rules without comments' do
    before(:all) do
      iptables_flush_all_tables
      shell('iptables -A INPUT -j ACCEPT -p tcp --dport 80')
    end

    it do
      shell('puppet resource firewall') do |r|
        r.exit_code.should be_zero
        # don't check stdout, testing preexisting rules, output is normal
        r.stderr.should be_empty
      end
    end
  end

  context 'accepts rules with invalid comments' do
    before(:all) do
      iptables_flush_all_tables
      shell('iptables -A INPUT -j ACCEPT -p tcp --dport 80 -m comment --comment "http"')
    end

    it do
      shell('puppet resource firewall') do |r|
        r.exit_code.should be_zero
        # don't check stdout, testing preexisting rules, output is normal
        r.stderr.should be_empty
      end
    end
  end

  context 'accepts rules with negation' do
    before :all do
      iptables_flush_all_tables
      shell('iptables -t nat -A POSTROUTING -s 192.168.122.0/24 ! -d 192.168.122.0/24 -p tcp -j MASQUERADE --to-ports 1024-65535')
      shell('iptables -t nat -A POSTROUTING -s 192.168.122.0/24 ! -d 192.168.122.0/24 -p udp -j MASQUERADE --to-ports 1024-65535')
      shell('iptables -t nat -A POSTROUTING -s 192.168.122.0/24 ! -d 192.168.122.0/24 -j MASQUERADE')
    end

    it do
      shell('puppet resource firewall') do |r|
        r.exit_code.should be_zero
        # don't check stdout, testing preexisting rules, output is normal
        r.stderr.should be_empty
      end
    end
  end

  context 'accepts rules with match extension tcp flag' do
    before :all do
      iptables_flush_all_tables
      shell('iptables -t mangle -A PREROUTING -d 1.2.3.4 -p tcp -m tcp -m multiport --dports 80,443,8140 -j MARK --set-mark 42')
    end

    it do
      shell('puppet resource firewall') do |r|
        r.exit_code.should be_zero
        # don't check stdout, testing preexisting rules, output is normal
        r.stderr.should be_empty
      end
    end
  end
end
require 'spec_helper_acceptance'

describe 'complex ruleset 1' do
  before :all do
    iptables_flush_all_tables
  end

  after :all do
    shell('iptables -t filter -P INPUT ACCEPT')
    shell('iptables -t filter -P FORWARD ACCEPT')
    shell('iptables -t filter -P OUTPUT ACCEPT')
    shell('iptables -t filter --flush')
  end

  it 'applies cleanly' do
    pp = <<-EOS
      firewall { '090 forward allow local':
        chain       => 'FORWARD',
        proto       => 'all',
        source      => '10.0.0.0/8',
        destination => '10.0.0.0/8',
        action      => 'accept',
      }
      firewall { '100 forward standard allow tcp':
        chain       => 'FORWARD',
        source      => '10.0.0.0/8',
        destination => '!10.0.0.0/8',
        proto       => 'tcp',
        state       => 'NEW',
        port        => [80,443,21,20,22,53,123,43,873,25,465],
        action      => 'accept',
      }
      firewall { '100 forward standard allow udp':
        chain       => 'FORWARD',
        source      => '10.0.0.0/8',
        destination => '!10.0.0.0/8',
        proto       => 'udp',
        port        => [53,123],
        action      => 'accept',
      }
      firewall { '100 forward standard allow icmp':
        chain       => 'FORWARD',
        source      => '10.0.0.0/8',
        destination => '!10.0.0.0/8',
        proto       => 'icmp',
        action      => 'accept',
      }

      firewall { '090 ignore ipsec':
        table        => 'nat',
        chain        => 'POSTROUTING',
        outiface     => 'eth0',
        ipsec_policy => 'ipsec',
        ipsec_dir    => 'out',
        action       => 'accept',
      }
      firewall { '093 ignore 10.0.0.0/8':
        table       => 'nat',
        chain       => 'POSTROUTING',
        outiface    => 'eth0',
        destination => '10.0.0.0/8',
        action      => 'accept',
      }
      firewall { '093 ignore 172.16.0.0/12':
        table       => 'nat',
        chain       => 'POSTROUTING',
        outiface    => 'eth0',
        destination => '172.16.0.0/12',
        action      => 'accept',
      }
      firewall { '093 ignore 192.168.0.0/16':
        table       => 'nat',
        chain       => 'POSTROUTING',
        outiface    => 'eth0',
        destination => '192.168.0.0/16',
        action      => 'accept',
      }
      firewall { '100 masq outbound':
        table    => 'nat',
        chain    => 'POSTROUTING',
        outiface => 'eth0',
        jump     => 'MASQUERADE',
      }
      firewall { '101 redirect port 1':
        table   => 'nat',
        chain   => 'PREROUTING',
        iniface => 'eth0',
        proto   => 'tcp',
        dport   => '1',
        toports => '22',
        jump    => 'REDIRECT',
      }
    EOS

    # Run it twice and test for idempotency
    apply_manifest(pp, :catch_failures => true)
    expect(apply_manifest(pp, :catch_failures => true).exit_code).to be_zero
  end

  it 'contains appropriate rules' do
    shell('iptables-save') do |r|
      [
        /INPUT ACCEPT/,
        /FORWARD ACCEPT/,
        /OUTPUT ACCEPT/,
        /-A FORWARD -s 10.0.0.0\/(8|255\.0\.0\.0) -d 10.0.0.0\/(8|255\.0\.0\.0) -m comment --comment \"090 forward allow local\" -j ACCEPT/,
        /-A FORWARD -s 10.0.0.0\/(8|255\.0\.0\.0) (! -d|-d !) 10.0.0.0\/(8|255\.0\.0\.0) -p icmp -m comment --comment \"100 forward standard allow icmp\" -j ACCEPT/,
        /-A FORWARD -s 10.0.0.0\/(8|255\.0\.0\.0) (! -d|-d !) 10.0.0.0\/(8|255\.0\.0\.0) -p tcp -m multiport --ports 80,443,21,20,22,53,123,43,873,25,465 -m comment --comment \"100 forward standard allow tcp\" -m state --state NEW -j ACCEPT/,
        /-A FORWARD -s 10.0.0.0\/(8|255\.0\.0\.0) (! -d|-d !) 10.0.0.0\/(8|255\.0\.0\.0) -p udp -m multiport --ports 53,123 -m comment --comment \"100 forward standard allow udp\" -j ACCEPT/
      ].each do |line|
        expect(r.stdout).to match(line)
      end
    end
  end
end

describe 'complex ruleset 2' do
  after :all do
    shell('iptables -t filter -P INPUT ACCEPT')
    shell('iptables -t filter -P FORWARD ACCEPT')
    shell('iptables -t filter -P OUTPUT ACCEPT')
    shell('iptables -t filter --flush')
    expect(shell('iptables -t filter -X LOCAL_INPUT').stderr).to eq("")
    expect(shell('iptables -t filter -X LOCAL_INPUT_PRE').stderr).to eq("")
  end

  it 'applies cleanly' do
    pp = <<-EOS
      class { '::firewall': }
      
      Firewall {
        proto => 'all',
        stage => 'pre',
      }
      Firewallchain {
        stage  => 'pre',
        purge  => 'true',
        ignore => [
          '--comment "[^"]*(?i:ignore)[^"]*"',
        ],
      }

      firewall { '010 INPUT allow established and related':
        proto  => 'all',
        state  => ['ESTABLISHED', 'RELATED'],
        action => 'accept',
        before => Firewallchain['INPUT:filter:IPv4'],
      }
      firewall { '012 accept loopback':
        iniface => 'lo',
        action  => 'accept',
        before => Firewallchain['INPUT:filter:IPv4'],
      }
      firewall { '020 ssh':
        proto  => 'tcp',
        dport  => '22',
        state  => 'NEW',
        action => 'accept',
        before => Firewallchain['INPUT:filter:IPv4'],
      }

      firewall { '013 icmp echo-request':
        proto  => 'icmp',
        icmp   => 'echo-request',
        action => 'accept',
        source => '10.0.0.0/8',
      }
      firewall { '013 icmp destination-unreachable':
        proto  => 'icmp',
        icmp   => 'destination-unreachable',
        action => 'accept',
      }
      firewall { '013 icmp time-exceeded':
        proto  => 'icmp',
        icmp   => 'time-exceeded',
        action => 'accept',
      }
      firewall { '999 reject':
        action => 'reject',
        reject => 'icmp-host-prohibited',
      }


      firewallchain { 'LOCAL_INPUT_PRE:filter:IPv4': }
      firewall { '001 LOCAL_INPUT_PRE':
        jump    => 'LOCAL_INPUT_PRE',
        require => Firewallchain['LOCAL_INPUT_PRE:filter:IPv4'],
      }
      firewallchain { 'LOCAL_INPUT:filter:IPv4': }
      firewall { '900 LOCAL_INPUT':
        jump    => 'LOCAL_INPUT',
        require => Firewallchain['LOCAL_INPUT:filter:IPv4'],
      }
      firewallchain { 'INPUT:filter:IPv4':
        policy => 'drop',
        ignore => [
          '-j fail2ban-ssh',
          '--comment "[^"]*(?i:ignore)[^"]*"',
        ],
      }


      firewall { '010 allow established and related':
        chain  => 'FORWARD',
        proto  => 'all',
        state  => ['ESTABLISHED','RELATED'],
        action => 'accept',
        before => Firewallchain['FORWARD:filter:IPv4'],
      }
      firewallchain { 'FORWARD:filter:IPv4':
        policy => 'drop',
      }

      firewallchain { 'OUTPUT:filter:IPv4': }


      # purge unknown rules from mangle table
      firewallchain { ['PREROUTING:mangle:IPv4', 'INPUT:mangle:IPv4', 'FORWARD:mangle:IPv4', 'OUTPUT:mangle:IPv4', 'POSTROUTING:mangle:IPv4']: }

      # and the nat table
      firewallchain { ['PREROUTING:nat:IPv4', 'INPUT:nat:IPv4', 'OUTPUT:nat:IPv4', 'POSTROUTING:nat:IPv4']: }
    EOS

    # Run it twice and test for idempotency
    apply_manifest(pp, :catch_failures => true)
    apply_manifest(pp, :catch_changes => true)
  end

  it 'contains appropriate rules' do
    shell('iptables-save') do |r|
      [
        /INPUT DROP/,
        /FORWARD DROP/,
        /OUTPUT ACCEPT/,
        /LOCAL_INPUT/,
        /LOCAL_INPUT_PRE/,
        /-A INPUT -m comment --comment \"001 LOCAL_INPUT_PRE\" -j LOCAL_INPUT_PRE/,
        /-A INPUT -m comment --comment \"010 INPUT allow established and related\" -m state --state RELATED,ESTABLISHED -j ACCEPT/,
        /-A INPUT -i lo -m comment --comment \"012 accept loopback\" -j ACCEPT/,
        /-A INPUT -p icmp -m comment --comment \"013 icmp destination-unreachable\" -m icmp --icmp-type 3 -j ACCEPT/,
        /-A INPUT -s 10.0.0.0\/(8|255\.0\.0\.0) -p icmp -m comment --comment \"013 icmp echo-request\" -m icmp --icmp-type 8 -j ACCEPT/,
        /-A INPUT -p icmp -m comment --comment \"013 icmp time-exceeded\" -m icmp --icmp-type 11 -j ACCEPT/,
        /-A INPUT -p tcp -m multiport --dports 22 -m comment --comment \"020 ssh\" -m state --state NEW -j ACCEPT/,
        /-A INPUT -m comment --comment \"900 LOCAL_INPUT\" -j LOCAL_INPUT/,
        /-A INPUT -m comment --comment \"999 reject\" -j REJECT --reject-with icmp-host-prohibited/,
        /-A FORWARD -m comment --comment \"010 allow established and related\" -m state --state RELATED,ESTABLISHED -j ACCEPT/
      ].each do |line|
        expect(r.stdout).to match(line)
      end
    end
  end
end
require 'spec_helper_acceptance'

# RHEL5 does not support -m socket
describe 'firewall socket property', :unless => (default['platform'] =~ /el-5/ || fact('operatingsystem') == 'SLES') do
  before :all do
    iptables_flush_all_tables
  end

  shared_examples "is idempotent" do |value, line_match|
    it "changes the value to #{value}" do
      pp = <<-EOS
          class { '::firewall': }
          firewall { '598 - test':
            ensure => present,
            proto  => 'tcp',
            chain  => 'PREROUTING',
            table  => 'raw',
            #{value}
          }
      EOS

      apply_manifest(pp, :catch_failures => true)
      apply_manifest(pp, :catch_changes => true)

      shell('iptables-save -t raw') do |r|
        expect(r.stdout).to match(/#{line_match}/)
      end
    end
  end
  shared_examples "doesn't change" do |value, line_match|
    it "doesn't change the value to #{value}" do
      pp = <<-EOS
          class { '::firewall': }
          firewall { '598 - test':
            ensure => present,
            proto  => 'tcp',
            chain  => 'PREROUTING',
            table  => 'raw',
            #{value}
          }
      EOS

      apply_manifest(pp, :catch_changes => true)

      shell('iptables-save -t raw') do |r|
        expect(r.stdout).to match(/#{line_match}/)
      end
    end
  end

  describe 'adding a rule' do
    context 'when unset' do
      before :all do
        iptables_flush_all_tables
      end
      it_behaves_like 'is idempotent', '', /-A PREROUTING -p tcp -m comment --comment "598 - test"/
    end
    context 'when set to true' do
      before :all do
        iptables_flush_all_tables
      end
      it_behaves_like 'is idempotent', 'socket => true,', /-A PREROUTING -p tcp -m socket -m comment --comment "598 - test"/
    end
    context 'when set to false' do
      before :all do
        iptables_flush_all_tables
      end
      it_behaves_like "is idempotent", 'socket => false,', /-A PREROUTING -p tcp -m comment --comment "598 - test"/
    end
  end
  describe 'editing a rule' do
    context 'when unset or false' do
      before :each do
        iptables_flush_all_tables
        shell('iptables -t raw -A PREROUTING -p tcp -m comment --comment "598 - test"')
      end
      context 'and current value is false' do
        it_behaves_like "doesn't change", 'socket => false,', /-A PREROUTING -p tcp -m comment --comment "598 - test"/
      end
      context 'and current value is true' do
        it_behaves_like "is idempotent", 'socket => true,', /-A PREROUTING -p tcp -m socket -m comment --comment "598 - test"/
      end
    end
    context 'when set to true' do
      before :each do
        iptables_flush_all_tables
        shell('iptables -t raw -A PREROUTING -p tcp -m socket -m comment --comment "598 - test"')
      end
      context 'and current value is false' do
        it_behaves_like "is idempotent", 'socket => false,', /-A PREROUTING -p tcp -m comment --comment "598 - test"/
      end
      context 'and current value is true' do
        it_behaves_like "doesn't change", 'socket => true,', /-A PREROUTING -p tcp -m socket -m comment --comment "598 - test"/
      end
    end
  end
end
require 'spec_helper_acceptance'

# Some tests for the standard recommended usage
describe 'standard usage tests:' do
  it 'applies twice' do
    pp = <<-EOS
      class my_fw::pre {
        Firewall {
          require => undef,
        }

        # Default firewall rules
        firewall { '000 accept all icmp':
          proto   => 'icmp',
          action  => 'accept',
        }->
        firewall { '001 accept all to lo interface':
          proto   => 'all',
          iniface => 'lo',
          action  => 'accept',
        }->
        firewall { '002 accept related established rules':
          proto   => 'all',
          ctstate => ['RELATED', 'ESTABLISHED'],
          action  => 'accept',
        }
      }
      class my_fw::post {
        firewall { '999 drop all':
          proto   => 'all',
          action  => 'drop',
          before  => undef,
        }
      }
      resources { "firewall":
        purge => true
      }
      Firewall {
        before  => Class['my_fw::post'],
        require => Class['my_fw::pre'],
      }
      class { ['my_fw::pre', 'my_fw::post']: }
      class { 'firewall': }
      firewall { '500 open up port 22':
        action => 'accept',
        proto => 'tcp',
        dport => 22,
      }
    EOS

    # Run it twice and test for idempotency
    apply_manifest(pp, :catch_failures => true)
    expect(apply_manifest(pp, :catch_failures => true).exit_code).to be_zero
  end
end
# These hashes allow us to iterate across a series of test data
# creating rspec examples for each parameter to ensure the input :line
# extrapolates to the desired value for the parameter in question. And
# vice-versa

# This hash is for testing a line conversion to a hash of parameters
# which will be used to create a resource.
ARGS_TO_HASH6 = {
  'source_destination_ipv6_no_cidr' => {
    :line => '-A INPUT -s 2001:db8:85a3::8a2e:370:7334 -d 2001:db8:85a3::8a2e:370:7334 -m comment --comment "000 source destination ipv6 no cidr"',
    :table => 'filter',
    :provider => 'ip6tables',
    :params => {
      :source => '2001:db8:85a3::8a2e:370:7334/128',
      :destination => '2001:db8:85a3::8a2e:370:7334/128',
    },
  },
  'source_destination_ipv6_netmask' => {
    :line => '-A INPUT -s 2001:db8:1234::/ffff:ffff:ffff:0000:0000:0000:0000:0000 -d 2001:db8:4321::/ffff:ffff:ffff:0000:0000:0000:0000:0000 -m comment --comment "000 source destination ipv6 netmask"',
    :table => 'filter',
    :provider => 'ip6tables',
    :params => {
      :source => '2001:db8:1234::/48',
      :destination => '2001:db8:4321::/48',
    },
  },
}

# This hash is for testing converting a hash to an argument line.
HASH_TO_ARGS6 = {
  'zero_prefixlen_ipv6' => {
    :params => {
      :name => '100 zero prefix length ipv6',
      :table => 'filter',
      :provider => 'ip6tables',
      :source => '::/0',
      :destination => '::/0',
    },
    :args => ['-t', :filter, '-p', :tcp, '-m', 'comment', '--comment', '100 zero prefix length ipv6'],
  },
  'source_destination_ipv4_no_cidr' => {
    :params => {
      :name => '000 source destination ipv4 no cidr',
      :table => 'filter',
      :provider => 'ip6tables',
      :source => '1.1.1.1',
      :destination => '2.2.2.2',
    },
    :args => ['-t', :filter, '-s', '1.1.1.1/32', '-d', '2.2.2.2/32', '-p', :tcp, '-m', 'comment', '--comment', '000 source destination ipv4 no cidr'],
  },
 'source_destination_ipv6_no_cidr' => {
    :params => {
      :name => '000 source destination ipv6 no cidr',
      :table => 'filter',
      :provider => 'ip6tables',
      :source => '2001:db8:1234::',
      :destination => '2001:db8:4321::',
    },
    :args => ['-t', :filter, '-s', '2001:db8:1234::/128', '-d', '2001:db8:4321::/128', '-p', :tcp, '-m', 'comment', '--comment', '000 source destination ipv6 no cidr'],
  },
 'source_destination_ipv6_netmask' => {
    :params => {
      :name => '000 source destination ipv6 netmask',
      :table => 'filter',
      :provider => 'ip6tables',
      :source => '2001:db8:1234::/ffff:ffff:ffff:0000:0000:0000:0000:0000',
      :destination => '2001:db8:4321::/ffff:ffff:ffff:0000:0000:0000:0000:0000',
    },
    :args => ['-t', :filter, '-s', '2001:db8:1234::/48', '-d', '2001:db8:4321::/48', '-p', :tcp, '-m', 'comment', '--comment', '000 source destination ipv6 netmask'],
  },
  'frag_ishasmorefrags' => {
    :params => {
      :name => "100 has more fragments",
      :ishasmorefrags => true,
      :provider => 'ip6tables',
      :table => "filter",
    },
    :args => ["-t", :filter, "-p", :tcp, "-m", "frag", "--fragid", "0", "--fragmore", "-m", "comment", "--comment", "100 has more fragments"],
  },
  'frag_islastfrag' => {
    :params => {
      :name => "100 last fragment",
      :islastfrag => true,
      :provider => 'ip6tables',
      :table => "filter",
    },
    :args => ["-t", :filter, "-p", :tcp, "-m", "frag", "--fragid", "0", "--fraglast", "-m", "comment", "--comment", "100 last fragment"],
  },
  'frag_isfirstfrags' => {
    :params => {
      :name => "100 first fragment",
      :isfirstfrag => true,
      :provider => 'ip6tables',
      :table => "filter",
    },
    :args => ["-t", :filter, "-p", :tcp, "-m", "frag", "--fragid", "0", "--fragfirst", "-m", "comment", "--comment", "100 first fragment"],
  },
  'hop_limit' => {
    :params => {
      :name => "100 hop limit",
      :hop_limit => 255,
      :provider => 'ip6tables',
      :table => "filter",
    },
    :args => ["-t", :filter, "-p", :tcp, "-m", "comment", "--comment", "100 hop limit", "-m", "hl", "--hl-eq", 255],
  },
}
# These hashes allow us to iterate across a series of test data
# creating rspec examples for each parameter to ensure the input :line
# extrapolates to the desired value for the parameter in question. And
# vice-versa

# This hash is for testing a line conversion to a hash of parameters
# which will be used to create a resource.
ARGS_TO_HASH = {
  'dport_and_sport' => {
    :line => '-A nova-compute-FORWARD -s 0.0.0.0/32 -d 255.255.255.255/32 -p udp -m udp --sport 68 --dport 67 -j ACCEPT',
    :table => 'filter',
    :params => {
      :action => 'accept',
      :chain => 'nova-compute-FORWARD',
      :source => '0.0.0.0/32',
      :destination => '255.255.255.255/32',
      :sport => ['68'],
      :dport => ['67'],
      :proto => 'udp',
    },
  },
  'long_rule_1' => {
    :line => '-A INPUT -s 1.1.1.1/32 -d 1.1.1.1/32 -p tcp -m multiport --dports 7061,7062 -m multiport --sports 7061,7062 -m comment --comment "000 allow foo" -j ACCEPT',
    :table => 'filter',
    :compare_all => true,
    :params => {
      :action => "accept",
      :chain => "INPUT",
      :destination => "1.1.1.1/32",
      :dport => ["7061","7062"],
      :ensure => :present,
      :line => '-A INPUT -s 1.1.1.1/32 -d 1.1.1.1/32 -p tcp -m multiport --dports 7061,7062 -m multiport --sports 7061,7062 -m comment --comment "000 allow foo" -j ACCEPT',
      :name => "000 allow foo",
      :proto => "tcp",
      :provider => "iptables",
      :source => "1.1.1.1/32",
      :sport => ["7061","7062"],
      :table => "filter",
    },
  },
  'action_drop_1' => {
    :line => '-A INPUT -m comment --comment "000 allow foo" -j DROP',
    :table => 'filter',
    :params => {
      :jump => nil,
      :action => "drop",
    },
  },
  'action_reject_1' => {
    :line => '-A INPUT -m comment --comment "000 allow foo" -j REJECT',
    :table => 'filter',
    :params => {
      :jump => nil,
      :action => "reject",
    },
  },
  'action_nil_1' => {
    :line => '-A INPUT -m comment --comment "000 allow foo"',
    :table => 'filter',
    :params => {
      :jump => nil,
      :action => nil,
    },
  },
  'jump_custom_chain_1' => {
    :line => '-A INPUT -m comment --comment "000 allow foo" -j custom_chain',
    :table => 'filter',
    :params => {
      :jump => "custom_chain",
      :action => nil,
    },
  },
  'source_destination_ipv4_no_cidr' => {
    :line => '-A INPUT -s 1.1.1.1 -d 2.2.2.2 -m comment --comment "000 source destination ipv4 no cidr"',
    :table => 'filter',
    :params => {
      :source => '1.1.1.1/32',
      :destination => '2.2.2.2/32',
    },
  },
  'source_destination_ipv6_no_cidr' => {
    :line => '-A INPUT -s 2001:db8:85a3::8a2e:370:7334 -d 2001:db8:85a3::8a2e:370:7334 -m comment --comment "000 source destination ipv6 no cidr"',
    :table => 'filter',
    :params => {
      :source => '2001:db8:85a3::8a2e:370:7334/128',
      :destination => '2001:db8:85a3::8a2e:370:7334/128',
    },
  },
  'source_destination_ipv4_netmask' => {
    :line => '-A INPUT -s 1.1.1.0/255.255.255.0 -d 2.2.0.0/255.255.0.0 -m comment --comment "000 source destination ipv4 netmask"',
    :table => 'filter',
    :params => {
      :source => '1.1.1.0/24',
      :destination => '2.2.0.0/16',
    },
  },
  'source_destination_ipv6_netmask' => {
    :line => '-A INPUT -s 2001:db8:1234::/ffff:ffff:ffff:0000:0000:0000:0000:0000 -d 2001:db8:4321::/ffff:ffff:ffff:0000:0000:0000:0000:0000 -m comment --comment "000 source destination ipv6 netmask"',
    :table => 'filter',
    :params => {
      :source => '2001:db8:1234::/48',
      :destination => '2001:db8:4321::/48',
    },
  },
  'source_destination_negate_source' => {
    :line => '-A INPUT ! -s 1.1.1.1 -d 2.2.2.2 -m comment --comment "000 negated source address"',
    :table => 'filter',
    :params => {
      :source => '! 1.1.1.1/32',
      :destination => '2.2.2.2/32',
    },
  },
  'source_destination_negate_destination' => {
    :line => '-A INPUT -s 1.1.1.1 ! -d 2.2.2.2 -m comment --comment "000 negated destination address"',
    :table => 'filter',
    :params => {
      :source => '1.1.1.1/32',
      :destination => '! 2.2.2.2/32',
    },
  },
  'source_destination_negate_destination_alternative' => {
    :line => '-A INPUT -s 1.1.1.1 -d ! 2.2.2.2 -m comment --comment "000 negated destination address alternative"',
    :table => 'filter',
    :params => {
      :source => '1.1.1.1/32',
      :destination => '! 2.2.2.2/32',
    },
  },
  'dport_range_1' => {
    :line => '-A INPUT -m multiport --dports 1:1024 -m comment --comment "000 allow foo"',
    :table => 'filter',
    :params => {
      :dport => ["1-1024"],
    },
  },
  'dport_range_2' => {
    :line => '-A INPUT -m multiport --dports 15,512:1024 -m comment --comment "000 allow foo"',
    :table => 'filter',
    :params => {
      :dport => ["15","512-1024"],
    },
  },
  'sport_range_1' => {
    :line => '-A INPUT -m multiport --sports 1:1024 -m comment --comment "000 allow foo"',
    :table => 'filter',
    :params => {
      :sport => ["1-1024"],
    },
  },
  'sport_range_2' => {
    :line => '-A INPUT -m multiport --sports 15,512:1024 -m comment --comment "000 allow foo"',
    :table => 'filter',
    :params => {
      :sport => ["15","512-1024"],
    },
  },
  'dst_type_1' => {
    :line => '-A INPUT -m addrtype --dst-type LOCAL',
    :table => 'filter',
    :params => {
      :dst_type => 'LOCAL',
    },
  },
  'src_type_1' => {
    :line => '-A INPUT -m addrtype --src-type LOCAL',
    :table => 'filter',
    :params => {
      :src_type => 'LOCAL',
    },
  },
  'dst_range_1' => {
    :line => '-A INPUT -m iprange --dst-range 10.0.0.2-10.0.0.20',
    :table => 'filter',
    :params => {
      :dst_range => '10.0.0.2-10.0.0.20',
    },
  },
  'src_range_1' => {
    :line => '-A INPUT -m iprange --src-range 10.0.0.2-10.0.0.20',
    :table => 'filter',
    :params => {
      :src_range => '10.0.0.2-10.0.0.20',
    },
  },
  'tcp_flags_1' => {
    :line => '-A INPUT -p tcp -m tcp --tcp-flags SYN,RST,ACK,FIN SYN -m comment --comment "000 initiation"',
    :table => 'filter',
    :compare_all => true,
    :chain => 'INPUT',
    :proto => 'tcp',
    :params => {
      :chain => "INPUT",
      :ensure => :present,
      :line => '-A INPUT -p tcp -m tcp --tcp-flags SYN,RST,ACK,FIN SYN -m comment --comment "000 initiation"',
      :name => "000 initiation",
      :proto => "tcp",
      :provider => "iptables",
      :table => "filter",
      :tcp_flags => "SYN,RST,ACK,FIN SYN",
    },
  },
  'state_returns_sorted_values' => {
    :line => '-A INPUT -m state --state INVALID,RELATED,ESTABLISHED',
    :table => 'filter',
    :params => {
      :state => ['ESTABLISHED', 'INVALID', 'RELATED'],
      :action => nil,
    },
  },
  'ctstate_returns_sorted_values' => {
    :line => '-A INPUT -m conntrack --ctstate INVALID,RELATED,ESTABLISHED',
    :table => 'filter',
    :params => {
      :ctstate => ['ESTABLISHED', 'INVALID', 'RELATED'],
      :action => nil,
    },
  },
  'comment_string_character_validation' => {
    :line => '-A INPUT -s 192.168.0.1/32 -m comment --comment "000 allow from 192.168.0.1, please"',
    :table => 'filter',
    :params => {
      :source => '192.168.0.1/32',
    },
  },
  'log_level_debug' => {
    :line => '-A INPUT -m comment --comment "956 INPUT log-level" -m state --state NEW -j LOG --log-level 7',
    :table => 'filter',
    :params => {
      :state => ['NEW'],
      :log_level => '7',
      :jump => 'LOG'
    },
  },
  'log_level_warn' => {
    :line => '-A INPUT -m comment --comment "956 INPUT log-level" -m state --state NEW -j LOG',
    :table => 'filter',
    :params => {
      :state => ['NEW'],
      :log_level => '4',
      :jump => 'LOG'
    },
  },
  'load_limit_module_and_implicit_burst' => {
    :line => '-A INPUT -m multiport --dports 123 -m comment --comment "057 INPUT limit NTP" -m limit --limit 15/hour',
    :table => 'filter',
    :params => {
      :dport => ['123'],
      :limit => '15/hour',
      :burst => '5'
    },
  },
  'limit_with_explicit_burst' => {
    :line => '-A INPUT -m multiport --dports 123 -m comment --comment "057 INPUT limit NTP" -m limit --limit 30/hour --limit-burst 10',
    :table => 'filter',
    :params => {
      :dport => ['123'],
      :limit => '30/hour',
      :burst => '10'
    },
  },
  'proto_ipencap' => {
    :line => '-A INPUT -p ipencap -m comment --comment "0100 INPUT accept ipencap"',
    :table => 'filter',
    :params => {
      :proto => 'ipencap',
    }
  },
  'load_uid_owner_filter_module' => {
    :line => '-A OUTPUT -m owner --uid-owner root -m comment --comment "057 OUTPUT uid root only" -j ACCEPT',
    :table => 'filter',
    :params => {
      :action => 'accept',
      :uid => 'root',
      :chain => 'OUTPUT',
    },
  },
  'load_uid_owner_postrouting_module' => {
    :line => '-t mangle -A POSTROUTING -m owner --uid-owner root -m comment --comment "057 POSTROUTING uid root only" -j ACCEPT',
    :table => 'mangle',
    :params => {
      :action => 'accept',
      :chain => 'POSTROUTING',
      :uid => 'root',
    },
  },
  'load_gid_owner_filter_module' => {
    :line => '-A OUTPUT -m owner --gid-owner root -m comment --comment "057 OUTPUT gid root only" -j ACCEPT',
    :table => 'filter',
    :params => {
      :action => 'accept',
      :chain => 'OUTPUT',
      :gid => 'root',
    },
  },
  'load_gid_owner_postrouting_module' => {
    :line => '-t mangle -A POSTROUTING -m owner --gid-owner root -m comment --comment "057 POSTROUTING gid root only" -j ACCEPT',
    :table => 'mangle',
    :params => {
      :action => 'accept',
      :chain => 'POSTROUTING',
      :gid => 'root',
    },
  },
  'mark_set-mark' => {
    :line => '-t mangle -A PREROUTING -j MARK --set-xmark 0x3e8/0xffffffff',
    :table => 'mangle',
    :params => {
      :jump     => 'MARK',
      :chain    => 'PREROUTING',
      :set_mark => '0x3e8/0xffffffff',
    }
  },
  'iniface_1' => {
    :line => '-A INPUT -i eth0 -m comment --comment "060 iniface" -j DROP',
    :table => 'filter',
    :params => {
      :action => 'drop',
      :chain => 'INPUT',
      :iniface => 'eth0',
    },
  },
  'iniface_with_vlans_1' => {
    :line => '-A INPUT -i eth0.234 -m comment --comment "060 iniface" -j DROP',
    :table => 'filter',
    :params => {
      :action => 'drop',
      :chain => 'INPUT',
      :iniface => 'eth0.234',
    },
  },
  'iniface_with_plus_1' => {
    :line => '-A INPUT -i eth+ -m comment --comment "060 iniface" -j DROP',
    :table => 'filter',
    :params => {
      :action => 'drop',
      :chain => 'INPUT',
      :iniface => 'eth+',
    },
  },
  'outiface_1' => {
    :line => '-A OUTPUT -o eth0 -m comment --comment "060 outiface" -j DROP',
    :table => 'filter',
    :params => {
      :action => 'drop',
      :chain => 'OUTPUT',
      :outiface => 'eth0',
    },
  },
  'outiface_with_vlans_1' => {
    :line => '-A OUTPUT -o eth0.234 -m comment --comment "060 outiface" -j DROP',
    :table => 'filter',
    :params => {
      :action => 'drop',
      :chain => 'OUTPUT',
      :outiface => 'eth0.234',
    },
  },
  'outiface_with_plus_1' => {
    :line => '-A OUTPUT -o eth+ -m comment --comment "060 outiface" -j DROP',
    :table => 'filter',
    :params => {
      :action => 'drop',
      :chain => 'OUTPUT',
      :outiface => 'eth+',
    },
  },
  'pkttype multicast' => {
    :line => '-A INPUT -m pkttype --pkt-type multicast -j ACCEPT',
    :table => 'filter',
    :params => {
      :action => 'accept',
      :pkttype => 'multicast',
    },
  },
  'socket_option' => {
    :line => '-A PREROUTING -m socket -j ACCEPT',
    :table => 'mangle',
    :params => {
      :action => 'accept',
      :chain => 'PREROUTING',
      :socket => true,
    },
  },
  'isfragment_option' => {
    :line => '-A INPUT -f -m comment --comment "010 a-f comment with dashf" -j ACCEPT',
    :table => 'filter',
    :params => {
      :name => '010 a-f comment with dashf',
      :action => 'accept',
      :isfragment => true,
    },
  },
  'single_tcp_sport' => {
    :line => '-A OUTPUT -s 10.94.100.46/32 -p tcp -m tcp --sport 20443 -j ACCEPT',
    :table => 'mangle',
    :params => {
      :action => 'accept',
      :chain => 'OUTPUT',
      :source => "10.94.100.46/32",
      :proto => "tcp",
      :sport => ["20443"],
    },
  },
  'single_udp_sport' => {
    :line => '-A OUTPUT -s 10.94.100.46/32 -p udp -m udp --sport 20443 -j ACCEPT',
    :table => 'mangle',
    :params => {
      :action => 'accept',
      :chain => 'OUTPUT',
      :source => "10.94.100.46/32",
      :proto => "udp",
      :sport => ["20443"],
    },
  },
  'single_tcp_dport' => {
    :line => '-A OUTPUT -s 10.94.100.46/32 -p tcp -m tcp --dport 20443 -j ACCEPT',
    :table => 'mangle',
    :params => {
      :action => 'accept',
      :chain => 'OUTPUT',
      :source => "10.94.100.46/32",
      :proto => "tcp",
      :dport => ["20443"],
    },
  },
  'single_udp_dport' => {
    :line => '-A OUTPUT -s 10.94.100.46/32 -p udp -m udp --dport 20443 -j ACCEPT',
    :table => 'mangle',
    :params => {
      :action => 'accept',
      :chain => 'OUTPUT',
      :source => "10.94.100.46/32",
      :proto => "udp",
      :dport => ["20443"],
    },
  },
  'connlimit_above' => {
    :line => '-A INPUT -p tcp -m multiport --dports 22 -m comment --comment "061 REJECT connlimit_above 10" -m connlimit --connlimit-above 10 --connlimit-mask 32 -j REJECT --reject-with icmp-port-unreachable',
    :table => 'filter',
    :params => {
      :proto => 'tcp',
      :dport => ["22"],
      :connlimit_above => '10',
      :action => 'reject',
    },
  },
  'connlimit_above_with_connlimit_mask' => {
    :line => '-A INPUT -p tcp -m multiport --dports 22 -m comment --comment "061 REJECT connlimit_above 10 with mask 24" -m connlimit --connlimit-above 10 --connlimit-mask 24 -j REJECT --reject-with icmp-port-unreachable',
    :table => 'filter',
    :params => {
      :proto => 'tcp',
      :dport => ["22"],
      :connlimit_above => '10',
      :connlimit_mask => '24',
      :action => 'reject',
    },
  },
  'connmark' => {
    :line => '-A INPUT -m comment --comment "062 REJECT connmark" -m connmark --mark 0x1 -j REJECT --reject-with icmp-port-unreachable',
    :table => 'filter',
    :params => {
      :proto => 'all',
      :connmark => '0x1',
      :action => 'reject',
    },
  },
}

# This hash is for testing converting a hash to an argument line.
HASH_TO_ARGS = {
  'long_rule_1' => {
    :params => {
      :action => "accept",
      :chain => "INPUT",
      :destination => "1.1.1.1",
      :dport => ["7061","7062"],
      :ensure => :present,
      :name => "000 allow foo",
      :proto => "tcp",
      :source => "1.1.1.1",
      :sport => ["7061","7062"],
      :table => "filter",
    },
    :args => ["-t", :filter, "-s", "1.1.1.1/32", "-d", "1.1.1.1/32", "-p", :tcp, "-m", "multiport", "--sports", "7061,7062", "-m", "multiport", "--dports", "7061,7062", "-m", "comment", "--comment", "000 allow foo", "-j", "ACCEPT"],
  },
  'long_rule_2' => {
    :params => {
      :chain => "INPUT",
      :destination => "2.10.13.3/24",
      :dport => ["7061"],
      :ensure => :present,
      :jump => "my_custom_chain",
      :name => "700 allow bar",
      :proto => "udp",
      :source => "1.1.1.1",
      :sport => ["7061","7062"],
      :table => "filter",
    },
    :args => ["-t", :filter, "-s", "1.1.1.1/32", "-d", "2.10.13.0/24", "-p", :udp, "-m", "multiport", "--sports", "7061,7062", "-m", "multiport", "--dports", "7061", "-m", "comment", "--comment", "700 allow bar", "-j", "my_custom_chain"],
  },
  'no_action' => {
    :params => {
      :name => "100 no action",
      :table => "filter",
    },
    :args => ["-t", :filter, "-p", :tcp, "-m", "comment", "--comment",
      "100 no action"],
  },
  'zero_prefixlen_ipv4' => {
    :params => {
      :name => '100 zero prefix length ipv4',
      :table => 'filter',
      :source => '0.0.0.0/0',
      :destination => '0.0.0.0/0',
    },
    :args => ['-t', :filter, '-p', :tcp, '-m', 'comment', '--comment', '100 zero prefix length ipv4'],
  },
  'zero_prefixlen_ipv6' => {
    :params => {
      :name => '100 zero prefix length ipv6',
      :table => 'filter',
      :source => '::/0',
      :destination => '::/0',
    },
    :args => ['-t', :filter, '-p', :tcp, '-m', 'comment', '--comment', '100 zero prefix length ipv6'],
  },
  'source_destination_ipv4_no_cidr' => {
    :params => {
      :name => '000 source destination ipv4 no cidr',
      :table => 'filter',
      :source => '1.1.1.1',
      :destination => '2.2.2.2',
    },
    :args => ['-t', :filter, '-s', '1.1.1.1/32', '-d', '2.2.2.2/32', '-p', :tcp, '-m', 'comment', '--comment', '000 source destination ipv4 no cidr'],
  },
 'source_destination_ipv6_no_cidr' => {
    :params => {
      :name => '000 source destination ipv6 no cidr',
      :table => 'filter',
      :source => '2001:db8:1234::',
      :destination => '2001:db8:4321::',
    },
    :args => ['-t', :filter, '-s', '2001:db8:1234::/128', '-d', '2001:db8:4321::/128', '-p', :tcp, '-m', 'comment', '--comment', '000 source destination ipv6 no cidr'],
  },
  'source_destination_ipv4_netmask' => {
    :params => {
      :name => '000 source destination ipv4 netmask',
      :table => 'filter',
      :source => '1.1.1.0/255.255.255.0',
      :destination => '2.2.0.0/255.255.0.0',
    },
    :args => ['-t', :filter, '-s', '1.1.1.0/24', '-d', '2.2.0.0/16', '-p', :tcp, '-m', 'comment', '--comment', '000 source destination ipv4 netmask'],
  },
 'source_destination_ipv6_netmask' => {
    :params => {
      :name => '000 source destination ipv6 netmask',
      :table => 'filter',
      :source => '2001:db8:1234::/ffff:ffff:ffff:0000:0000:0000:0000:0000',
      :destination => '2001:db8:4321::/ffff:ffff:ffff:0000:0000:0000:0000:0000',
    },
    :args => ['-t', :filter, '-s', '2001:db8:1234::/48', '-d', '2001:db8:4321::/48', '-p', :tcp, '-m', 'comment', '--comment', '000 source destination ipv6 netmask'],
  },
  'sport_range_1' => {
    :params => {
      :name => "100 sport range",
      :sport => ["1-1024"],
      :table => "filter",
    },
    :args => ["-t", :filter, "-p", :tcp, "-m", "multiport", "--sports", "1:1024", "-m", "comment", "--comment", "100 sport range"],
  },
  'sport_range_2' => {
    :params => {
      :name => "100 sport range",
      :sport => ["15","512-1024"],
      :table => "filter",
    },
    :args => ["-t", :filter, "-p", :tcp, "-m", "multiport", "--sports", "15,512:1024", "-m", "comment", "--comment", "100 sport range"],
  },
  'dport_range_1' => {
    :params => {
      :name => "100 sport range",
      :dport => ["1-1024"],
      :table => "filter",
    },
    :args => ["-t", :filter, "-p", :tcp, "-m", "multiport", "--dports", "1:1024", "-m", "comment", "--comment", "100 sport range"],
  },
  'dport_range_2' => {
    :params => {
      :name => "100 sport range",
      :dport => ["15","512-1024"],
      :table => "filter",
    },
    :args => ["-t", :filter, "-p", :tcp, "-m", "multiport", "--dports", "15,512:1024", "-m", "comment", "--comment", "100 sport range"],
  },
  'dst_type_1' => {
    :params => {
      :name => '000 dst_type',
      :table => 'filter',
      :dst_type => 'LOCAL',
    },
    :args => ['-t', :filter, '-p', :tcp, '-m', 'addrtype', '--dst-type', :LOCAL, '-m', 'comment', '--comment', '000 dst_type'],
  },
  'src_type_1' => {
    :params => {
      :name => '000 src_type',
      :table => 'filter',
      :src_type => 'LOCAL',
    },
    :args => ['-t', :filter, '-p', :tcp, '-m', 'addrtype', '--src-type', :LOCAL, '-m', 'comment', '--comment', '000 src_type'],
  },
  'dst_range_1' => {
    :params => {
      :name => '000 dst_range',
      :table => 'filter',
      :dst_range => '10.0.0.1-10.0.0.10',
    },
    :args => ['-t', :filter, '-p', :tcp, '-m', 'iprange', '--dst-range', '10.0.0.1-10.0.0.10', '-m', 'comment', '--comment', '000 dst_range'],
  },
  'src_range_1' => {
    :params => {
      :name => '000 src_range',
      :table => 'filter',
      :dst_range => '10.0.0.1-10.0.0.10',
    },
    :args => ['-t', :filter, '-p', :tcp, '-m', 'iprange', '--dst-range', '10.0.0.1-10.0.0.10', '-m', 'comment', '--comment', '000 src_range'],
  },
  'tcp_flags_1' => {
    :params => {
      :name => "000 initiation",
      :tcp_flags => "SYN,RST,ACK,FIN SYN",
      :table => "filter",
    },

    :args => ["-t", :filter, "-p", :tcp, "-m", "tcp", "--tcp-flags", "SYN,RST,ACK,FIN", "SYN", "-m", "comment", "--comment", "000 initiation",]
  },
  'states_set_from_array' => {
    :params => {
      :name => "100 states_set_from_array",
      :table => "filter",
      :state => ['ESTABLISHED', 'INVALID']
    },
    :args => ["-t", :filter, "-p", :tcp, "-m", "comment", "--comment", "100 states_set_from_array",
      "-m", "state", "--state", "ESTABLISHED,INVALID"],
  },
  'ctstates_set_from_array' => {
    :params => {
      :name => "100 ctstates_set_from_array",
      :table => "filter",
      :ctstate => ['ESTABLISHED', 'INVALID']
    },
    :args => ["-t", :filter, "-p", :tcp, "-m", "comment", "--comment", "100 ctstates_set_from_array",
      "-m", "conntrack", "--ctstate", "ESTABLISHED,INVALID"],
  },
  'comment_string_character_validation' => {
    :params => {
      :name => "000 allow from 192.168.0.1, please",
      :table => 'filter',
      :source => '192.168.0.1'
    },
    :args => ['-t', :filter, '-s', '192.168.0.1/32', '-p', :tcp, '-m', 'comment', '--comment', '000 allow from 192.168.0.1, please'],
  },
  'port_property' => {
    :params => {
      :name => '001 port property',
      :table => 'filter',
      :port => '80',
    },
    :args => ['-t', :filter, '-p', :tcp, '-m', 'multiport', '--ports', '80', '-m', 'comment', '--comment', '001 port property'],
  },
  'log_level_debug' => {
    :params => {
      :name => '956 INPUT log-level',
      :table => 'filter',
      :state => 'NEW',
      :jump => 'LOG',
      :log_level => 'debug'
    },
    :args => ['-t', :filter, '-p', :tcp, '-m', 'comment', '--comment', '956 INPUT log-level', '-m', 'state', '--state', 'NEW', '-j', 'LOG', '--log-level', '7'],
  },
  'log_level_warn' => {
    :params => {
      :name => '956 INPUT log-level',
      :table => 'filter',
      :state => 'NEW',
      :jump => 'LOG',
      :log_level => 'warn'
    },
    :args => ['-t', :filter, '-p', :tcp, '-m', 'comment', '--comment', '956 INPUT log-level', '-m', 'state', '--state', 'NEW', '-j', 'LOG', '--log-level', '4'],
  },
  'load_limit_module_and_implicit_burst' => {
    :params => {
      :name => '057 INPUT limit NTP',
      :table => 'filter',
      :dport => '123',
      :limit => '15/hour'
    },
    :args => ['-t', :filter, '-p', :tcp, '-m', 'multiport', '--dports', '123', '-m', 'comment', '--comment', '057 INPUT limit NTP', '-m', 'limit', '--limit', '15/hour'],
  },
  'limit_with_explicit_burst' => {
    :params => {
      :name => '057 INPUT limit NTP',
      :table => 'filter',
      :dport => '123',
      :limit => '30/hour',
      :burst => '10'
    },
    :args => ['-t', :filter, '-p', :tcp, '-m', 'multiport', '--dports', '123', '-m', 'comment', '--comment', '057 INPUT limit NTP', '-m', 'limit', '--limit', '30/hour', '--limit-burst', '10'],
  },
  'proto_ipencap' => {
    :params => {
      :name => '0100 INPUT accept ipencap',
      :table => 'filter',
      :proto => 'ipencap',
    },
    :args => ['-t', :filter, '-p', :ipencap, '-m', 'comment', '--comment', '0100 INPUT accept ipencap'],
  },
  'load_uid_owner_filter_module' => {
    :params => {
      :name => '057 OUTPUT uid root only',
      :table => 'filter',
      :uid => 'root',
      :action => 'accept',
      :chain => 'OUTPUT',
      :proto => 'all',
    },
    :args => ['-t', :filter, '-p', :all, '-m', 'owner', '--uid-owner', 'root', '-m', 'comment', '--comment', '057 OUTPUT uid root only', '-j', 'ACCEPT'],
  },
  'load_uid_owner_postrouting_module' => {
    :params => {
      :name => '057 POSTROUTING uid root only',
      :table => 'mangle',
      :uid => 'root',
      :action => 'accept',
      :chain => 'POSTROUTING',
      :proto => 'all',
    },
    :args => ['-t', :mangle, '-p', :all, '-m', 'owner', '--uid-owner', 'root', '-m', 'comment', '--comment', '057 POSTROUTING uid root only', '-j', 'ACCEPT'],
  },
  'load_gid_owner_filter_module' => {
    :params => {
      :name => '057 OUTPUT gid root only',
      :table => 'filter',
      :chain => 'OUTPUT',
      :gid => 'root',
      :action => 'accept',
      :proto => 'all',
    },
    :args => ['-t', :filter, '-p', :all, '-m', 'owner', '--gid-owner', 'root', '-m', 'comment', '--comment', '057 OUTPUT gid root only', '-j', 'ACCEPT'],
  },
  'load_gid_owner_postrouting_module' => {
    :params => {
      :name => '057 POSTROUTING gid root only',
      :table => 'mangle',
      :gid => 'root',
      :action => 'accept',
      :chain => 'POSTROUTING',
      :proto => 'all',
    },
    :args => ['-t', :mangle, '-p', :all, '-m', 'owner', '--gid-owner', 'root', '-m', 'comment', '--comment', '057 POSTROUTING gid root only', '-j', 'ACCEPT'],
  },
  'mark_set-mark_int' => {
    :params => {
      :name     => '058 set-mark 1000',
      :table    => 'mangle',
      :jump     => 'MARK',
      :chain    => 'PREROUTING',
      :set_mark => '1000',
    },
    :args => ['-t', :mangle, '-p', :tcp, '-m', 'comment', '--comment', '058 set-mark 1000', '-j', 'MARK', '--set-xmark', '0x3e8/0xffffffff'],
  },
  'mark_set-mark_hex' => {
    :params => {
      :name     => '058 set-mark 0x32',
      :table    => 'mangle',
      :jump     => 'MARK',
      :chain    => 'PREROUTING',
      :set_mark => '0x32',
    },
    :args => ['-t', :mangle, '-p', :tcp, '-m', 'comment', '--comment', '058 set-mark 0x32', '-j', 'MARK', '--set-xmark', '0x32/0xffffffff'],
  },
  'mark_set-mark_hex_with_hex_mask' => {
    :params => {
      :name     => '058 set-mark 0x32/0xffffffff',
      :table    => 'mangle',
      :jump     => 'MARK',
      :chain    => 'PREROUTING',
      :set_mark => '0x32/0xffffffff',
    },
    :args => ['-t', :mangle, '-p', :tcp, '-m', 'comment', '--comment', '058 set-mark 0x32/0xffffffff', '-j', 'MARK', '--set-xmark', '0x32/0xffffffff'],
    },
  'mark_set-mark_hex_with_mask' => {
    :params => {
      :name     => '058 set-mark 0x32/4',
      :table    => 'mangle',
      :jump     => 'MARK',
      :chain    => 'PREROUTING',
      :set_mark => '0x32/4',
    },
    :args => ['-t', :mangle, '-p', :tcp, '-m', 'comment', '--comment', '058 set-mark 0x32/4', '-j', 'MARK', '--set-xmark', '0x32/0x4'],
    },
    'iniface_1' => {
    :params => {
      :name => '060 iniface',
      :table => 'filter',
      :action => 'drop',
      :chain => 'INPUT',
      :iniface => 'eth0',
    },
    :args => ["-t", :filter, "-i", "eth0", "-p", :tcp, "-m", "comment", "--comment", "060 iniface", "-j", "DROP"],
  },
  'iniface_with_vlans_1' => {
    :params => {
      :name => '060 iniface',
      :table => 'filter',
      :action => 'drop',
      :chain => 'INPUT',
      :iniface => 'eth0.234',
    },
    :args => ["-t", :filter, "-i", "eth0.234", "-p", :tcp, "-m", "comment", "--comment", "060 iniface", "-j", "DROP"],
  },
  'iniface_with_plus_1' => {
    :params => {
      :name => '060 iniface',
      :table => 'filter',
      :action => 'drop',
      :chain => 'INPUT',
      :iniface => 'eth+',
    },
    :args => ["-t", :filter, "-i", "eth+", "-p", :tcp, "-m", "comment", "--comment", "060 iniface", "-j", "DROP"],
  },
  'outiface_1' => {
    :params => {
      :name => '060 outiface',
      :table => 'filter',
      :action => 'drop',
      :chain => 'OUTPUT',
      :outiface => 'eth0',
    },
    :args => ["-t", :filter, "-o", "eth0", "-p", :tcp, "-m", "comment", "--comment", "060 outiface", "-j", "DROP"],
  },
  'outiface_with_vlans_1' => {
    :params => {
      :name => '060 outiface',
      :table => 'filter',
      :action => 'drop',
      :chain => 'OUTPUT',
      :outiface => 'eth0.234',
    },
    :args => ["-t", :filter, "-o", "eth0.234", "-p", :tcp, "-m", "comment", "--comment", "060 outiface", "-j", "DROP"],
  },
  'outiface_with_plus_1' => {
    :params => {
      :name => '060 outiface',
      :table => 'filter',
      :action => 'drop',
      :chain => 'OUTPUT',
      :outiface => 'eth+',
    },
    :args => ["-t", :filter, "-o", "eth+", "-p", :tcp, "-m", "comment", "--comment", "060 outiface", "-j", "DROP"],
  },
  'pkttype multicast' => {
    :params => {
      :name => '062 pkttype multicast',
      :table => "filter",
      :action => 'accept',
      :chain => 'INPUT',
      :iniface => 'eth0',
      :pkttype => 'multicast',
    },
    :args => ["-t", :filter, "-i", "eth0", "-p", :tcp, "-m", "pkttype", "--pkt-type", :multicast, "-m", "comment", "--comment", "062 pkttype multicast", "-j", "ACCEPT"],
  },
  'socket_option' => {
    :params => {
      :name => '050 socket option',
      :table => 'mangle',
      :action => 'accept',
      :chain => 'PREROUTING',
      :socket => true,
    },
    :args => ['-t', :mangle, '-p', :tcp, '-m', 'socket', '-m', 'comment', '--comment', '050 socket option', '-j', 'ACCEPT'],
  },
  'isfragment_option' => {
    :params => {
      :name => '050 isfragment option',
      :table => 'filter',
      :proto => :all,
      :action => 'accept',
      :isfragment => true,
    },
    :args => ['-t', :filter, '-p', :all, '-f', '-m', 'comment', '--comment', '050 isfragment option', '-j', 'ACCEPT'],
  },
  'isfragment_option not changing -f in comment' => {
    :params => {
      :name => '050 testcomment-with-fdashf',
      :table => 'filter',
      :proto => :all,
      :action => 'accept',
    },
    :args => ['-t', :filter, '-p', :all, '-m', 'comment', '--comment', '050 testcomment-with-fdashf', '-j', 'ACCEPT'],
  },
  'connlimit_above' => {
    :params => {
      :name => '061 REJECT connlimit_above 10',
      :table => 'filter',
      :proto => 'tcp',
      :dport => ["22"],
      :connlimit_above => '10',
      :action => 'reject',
    },
    :args => ["-t", :filter, "-p", :tcp, "-m", "multiport", "--dports", "22", "-m", "comment", "--comment", "061 REJECT connlimit_above 10", "-j", "REJECT", "-m", "connlimit", "--connlimit-above", "10"],
  },
  'connlimit_above_with_connlimit_mask' => {
    :params => {
      :name => '061 REJECT connlimit_above 10 with mask 24',
      :table => 'filter',
      :proto => 'tcp',
      :dport => ["22"],
      :connlimit_above => '10',
      :connlimit_mask => '24',
      :action => 'reject',
    },
    :args => ["-t", :filter, "-p", :tcp, "-m", "multiport", "--dports", "22", "-m", "comment", "--comment", "061 REJECT connlimit_above 10 with mask 24", "-j", "REJECT", "-m", "connlimit", "--connlimit-above", "10", "--connlimit-mask", "24"],
  },
  'connmark' => {
    :params => {
      :name => '062 REJECT connmark',
      :table => 'filter',
      :proto => 'all',
      :connmark => '0x1',
      :action => 'reject',
    },
    :args => ["-t", :filter, "-p", :all, "-m", "comment", "--comment", "062 REJECT connmark", "-j", "REJECT", "-m", "connmark", "--mark", "0x1"],
  },
}
dir = File.expand_path(File.dirname(__FILE__))
$LOAD_PATH.unshift File.join(dir, 'lib')

# Don't want puppet getting the command line arguments for rake or autotest
ARGV.clear

require 'rubygems'
require 'bundler/setup'
require 'rspec-puppet'

Bundler.require :default, :test

require 'pathname'
require 'tmpdir'

Pathname.glob("#{dir}/shared_behaviours/**/*.rb") do |behaviour|
  require behaviour.relative_path_from(Pathname.new(dir))
end

fixture_path = File.expand_path(File.join(__FILE__, '..', 'fixtures'))

RSpec.configure do |config|
  config.tty = true
  config.mock_with :rspec do |c|
    c.syntax = :expect
  end
  config.module_path = File.join(fixture_path, 'modules')
  config.manifest_dir = File.join(fixture_path, 'manifests')
end
require 'beaker-rspec'

def iptables_flush_all_tables
  ['filter', 'nat', 'mangle', 'raw'].each do |t|
    expect(shell("iptables -t #{t} -F").stderr).to eq("")
  end
end

def ip6tables_flush_all_tables
  ['filter'].each do |t|
    expect(shell("ip6tables -t #{t} -F").stderr).to eq("")
  end
end

unless ENV['RS_PROVISION'] == 'no' or ENV['BEAKER_provision'] == 'no'
  if hosts.first.is_pe?
    install_pe
  else
    install_puppet
  end
  hosts.each do |host|
    on host, "mkdir -p #{host['distmoduledir']}"
  end
end

RSpec.configure do |c|
  # Project root
  proj_root = File.expand_path(File.join(File.dirname(__FILE__), '..'))

  # Readable test descriptions
  c.formatter = :documentation

  # Configure all nodes in nodeset
  c.before :suite do
    # Install module and dependencies
    puppet_module_install(:source => proj_root, :module_name => 'firewall')
    hosts.each do |host|
      shell('/bin/touch /etc/puppet/hiera.yaml')
      shell('puppet module install puppetlabs-stdlib --version 3.2.0', { :acceptable_exit_codes => [0,1] })
    end
  end
end
require 'spec_helper'

describe 'firewall::linux::archlinux', :type => :class do
  it { should contain_service('iptables').with(
    :ensure   => 'running',
    :enable   => 'true'
  )}
  it { should contain_service('ip6tables').with(
    :ensure   => 'running',
    :enable   => 'true'
  )}

  context 'ensure => stopped' do
    let(:params) {{ :ensure => 'stopped' }}
    it { should contain_service('iptables').with(
      :ensure   => 'stopped'
    )}
    it { should contain_service('ip6tables').with(
      :ensure   => 'stopped'
    )}
  end

  context 'enable => false' do
    let(:params) {{ :enable => 'false' }}
    it { should contain_service('iptables').with(
      :enable   => 'false'
    )}
    it { should contain_service('ip6tables').with(
      :enable   => 'false'
    )}
  end
end
require 'spec_helper'

describe 'firewall::linux::debian', :type => :class do
  it { should contain_package('iptables-persistent').with(
    :ensure => 'present'
  )}
  it { should contain_service('iptables-persistent').with(
    :ensure   => nil,
    :enable   => 'true',
    :require  => 'Package[iptables-persistent]'
  )}

  context 'enable => false' do
    let(:params) {{ :enable => 'false' }}
    it { should contain_service('iptables-persistent').with(
      :enable   => 'false'
    )}
  end
end
require 'spec_helper'

describe 'firewall::linux::redhat', :type => :class do
  it { should contain_service('iptables').with(
    :ensure => 'running',
    :enable => 'true'
  )}

  context 'ensure => stopped' do
    let(:params) {{ :ensure => 'stopped' }}
    it { should contain_service('iptables').with(
      :ensure => 'stopped'
    )}
  end

  context 'enable => false' do
    let(:params) {{ :enable => 'false' }}
    it { should contain_service('iptables').with(
      :enable => 'false'
    )}
  end
end
require 'spec_helper'

describe 'firewall::linux', :type => :class do
  let(:facts_default) {{ :kernel => 'Linux' }}
  it { should contain_package('iptables').with_ensure('present') }

  context 'RedHat like' do
    %w{RedHat CentOS Fedora}.each do |os|
      context "operatingsystem => #{os}" do
        releases = (os == 'Fedora' ? [14,15,'Rawhide'] : [6,7])
        releases.each do |osrel|
          context "operatingsystemrelease => #{osrel}" do
            let(:facts) { facts_default.merge({ :operatingsystem => os,
                                                :operatingsystemrelease => osrel}) }
            it { should contain_class('firewall::linux::redhat').with_require('Package[iptables]') }
          end
        end
      end
    end
  end

  context 'Debian like' do
    %w{Debian Ubuntu}.each do |os|
      context "operatingsystem => #{os}" do
        let(:facts) { facts_default.merge({ :operatingsystem => os }) }
        it { should contain_class('firewall::linux::debian').with_require('Package[iptables]') }
      end
    end
  end
end
require 'spec_helper'

describe 'firewall', :type => :class do
  context 'kernel => Linux' do
    let(:facts) {{ :kernel => 'Linux' }}
    it { should contain_class('firewall::linux').with_ensure('running') }
  end

  context 'kernel => Windows' do
    let(:facts) {{ :kernel => 'Windows' }}
    it { expect { should contain_class('firewall::linux') }.to raise_error(Puppet::Error) }
  end

  context 'ensure => stopped' do
    let(:facts) {{ :kernel => 'Linux' }}
    let(:params) {{ :ensure => 'stopped' }}
    it { should contain_class('firewall::linux').with_ensure('stopped') }
  end

  context 'ensure => test' do
    let(:facts) {{ :kernel => 'Linux' }}
    let(:params) {{ :ensure => 'test' }}
    it { expect { should contain_class('firewall::linux') }.to raise_error(Puppet::Error) }
  end
end
require 'spec_helper'

describe "Facter::Util::Fact iptables_persistent_version" do
  before { Facter.clear }
  let(:dpkg_cmd) { "dpkg-query -Wf '${Version}' iptables-persistent 2>/dev/null" }

  {
    "Debian" => "0.0.20090701",
    "Ubuntu" => "0.5.3ubuntu2",
  }.each do |os, ver|
    describe "#{os} package installed" do
      before {
        allow(Facter.fact(:operatingsystem)).to receive(:value).and_return(os)
        allow(Facter::Util::Resolution).to receive(:exec).with(dpkg_cmd).
          and_return(ver)
      }
      it { Facter.fact(:iptables_persistent_version).value.should == ver }
    end
  end

  describe 'Ubuntu package not installed' do
    before {
      allow(Facter.fact(:operatingsystem)).to receive(:value).and_return('Ubuntu')
      allow(Facter::Util::Resolution).to receive(:exec).with(dpkg_cmd).
        and_return(nil)
    }
    it { Facter.fact(:iptables_persistent_version).value.should be_nil }
  end

  describe 'CentOS not supported' do
    before { allow(Facter.fact(:operatingsystem)).to receive(:value).
               and_return("CentOS") }
    it { Facter.fact(:iptables_persistent_version).value.should be_nil }
  end
end
require 'spec_helper'

describe "Facter::Util::Fact" do
  before {
    Facter.clear
    allow(Facter.fact(:kernel)).to receive(:value).and_return('Linux')
    allow(Facter.fact(:kernelrelease)).to receive(:value).and_return('2.6')
  }

  describe 'iptables_version' do
    it {
      allow(Facter::Util::Resolution).to receive(:exec).with('iptables --version').
      and_return('iptables v1.4.7')
      Facter.fact(:iptables_version).value.should == '1.4.7'
    }
  end

  describe 'ip6tables_version' do
    before { allow(Facter::Util::Resolution).to receive(:exec).
             with('ip6tables --version').and_return('ip6tables v1.4.7') }
    it { Facter.fact(:ip6tables_version).value.should == '1.4.7' }
  end
end
#!/usr/bin/env rspec

require 'spec_helper'
if Puppet.version < '3.4.0'
  require 'puppet/provider/confine/exists'
else
  require 'puppet/confine/exists'
end

describe 'iptables chain provider detection' do
  if Puppet.version < '3.4.0'
    let(:exists) {
      Puppet::Provider::Confine::Exists
    }
  else
    let(:exists) {
      Puppet::Confine::Exists
    }
  end

  before :each do
    # Reset the default provider
    Puppet::Type.type(:firewallchain).defaultprovider = nil
  end

  it "should default to iptables provider if /sbin/(eb|ip|ip6)tables[-save] exists" do
    # Stub lookup for /sbin/iptables & /sbin/iptables-save
    allow(exists).to receive(:which).with("ebtables").
      and_return "/sbin/ebtables"
    allow(exists).to receive(:which).with("ebtables-save").
      and_return "/sbin/ebtables-save"

    allow(exists).to receive(:which).with("iptables").
      and_return "/sbin/iptables"
    allow(exists).to receive(:which).with("iptables-save").
      and_return "/sbin/iptables-save"

    allow(exists).to receive(:which).with("ip6tables").
      and_return "/sbin/ip6tables"
    allow(exists).to receive(:which).with("ip6tables-save").
      and_return "/sbin/ip6tables-save"

    # Every other command should return false so we don't pick up any
    # other providers
    allow(exists).to receive(:which).with() { |value|
      value !~ /(eb|ip|ip6)tables(-save)?$/
    }.and_return false

    # Create a resource instance and make sure the provider is iptables
    resource = Puppet::Type.type(:firewallchain).new({
      :name => 'test:filter:IPv4',
    })
    expect(resource.provider.class.to_s).to eq("Puppet::Type::Firewallchain::ProviderIptables_chain")
  end
end

describe 'iptables chain provider' do
  let(:provider) { Puppet::Type.type(:firewallchain).provider(:iptables_chain) }
  let(:resource) {
    Puppet::Type.type(:firewallchain).new({
      :name  => ':test:',
    })
  }

  before :each do
    allow(Puppet::Type::Firewallchain).to receive(:defaultprovider).and_return provider
    allow(provider).to receive(:command).with(:ebtables_save).and_return "/sbin/ebtables-save"
    allow(provider).to receive(:command).with(:iptables_save).and_return "/sbin/iptables-save"
    allow(provider).to receive(:command).with(:ip6tables_save).and_return "/sbin/ip6tables-save"
  end

  it 'should be able to get a list of existing rules' do
    # Pretend to return nil from iptables
    allow(provider).to receive(:execute).with(['/sbin/ip6tables-save']).and_return("")
    allow(provider).to receive(:execute).with(['/sbin/ebtables-save']).and_return("")
    allow(provider).to receive(:execute).with(['/sbin/iptables-save']).and_return("")

    provider.instances.each do |chain|
      expect(chain).to be_instance_of(provider)
      expect(chain.properties[:provider].to_s).to eq(provider.name.to_s)
    end
  end

end

describe 'iptables chain resource parsing' do
  let(:provider) { Puppet::Type.type(:firewallchain).provider(:iptables_chain) }

  before :each do
    ebtables = ['BROUTE:BROUTING:ethernet',
                'BROUTE:broute:ethernet',
                ':INPUT:ethernet',
                ':FORWARD:ethernet',
                ':OUTPUT:ethernet',
                ':filter:ethernet',
                ':filterdrop:ethernet',
                ':filterreturn:ethernet',
                'NAT:PREROUTING:ethernet',
                'NAT:OUTPUT:ethernet',
                'NAT:POSTROUTING:ethernet',
               ]
    allow(provider).to receive(:execute).with(['/sbin/ebtables-save']).and_return('
*broute
:BROUTING ACCEPT
:broute ACCEPT

*filter
:INPUT ACCEPT
:FORWARD ACCEPT
:OUTPUT ACCEPT
:filter ACCEPT
:filterdrop DROP
:filterreturn RETURN

*nat
:PREROUTING ACCEPT
:OUTPUT ACCEPT
:POSTROUTING ACCEPT
')

    iptables = [
     'raw:PREROUTING:IPv4',
     'raw:OUTPUT:IPv4',
     'raw:raw:IPv4',
     'mangle:PREROUTING:IPv4',
     'mangle:INPUT:IPv4',
     'mangle:FORWARD:IPv4',
     'mangle:OUTPUT:IPv4',
     'mangle:POSTROUTING:IPv4',
     'mangle:mangle:IPv4',
     'NAT:PREROUTING:IPv4',
     'NAT:OUTPUT:IPv4',
     'NAT:POSTROUTING:IPv4',
     'NAT:mangle:IPv4',
     'NAT:mangle:IPv4',
     'NAT:mangle:IPv4',
     ':$5()*&%\'"^$): :IPv4',
    ]
    allow(provider).to receive(:execute).with(['/sbin/iptables-save']).and_return('
# Generated by iptables-save v1.4.9 on Mon Jan  2 01:20:06 2012
*raw
:PREROUTING ACCEPT [12:1780]
:OUTPUT ACCEPT [19:1159]
:raw - [0:0]
COMMIT
# Completed on Mon Jan  2 01:20:06 2012
# Generated by iptables-save v1.4.9 on Mon Jan  2 01:20:06 2012
*mangle
:PREROUTING ACCEPT [12:1780]
:INPUT ACCEPT [12:1780]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [19:1159]
:POSTROUTING ACCEPT [19:1159]
:mangle - [0:0]
COMMIT
# Completed on Mon Jan  2 01:20:06 2012
# Generated by iptables-save v1.4.9 on Mon Jan  2 01:20:06 2012
*nat
:PREROUTING ACCEPT [2242:639750]
:OUTPUT ACCEPT [5176:326206]
:POSTROUTING ACCEPT [5162:325382]
COMMIT
# Completed on Mon Jan  2 01:20:06 2012
# Generated by iptables-save v1.4.9 on Mon Jan  2 01:20:06 2012
*filter
:INPUT ACCEPT [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [5673:420879]
:$5()*&%\'"^$):  - [0:0]
COMMIT
# Completed on Mon Jan  2 01:20:06 2012
')
    ip6tables = [
      'raw:PREROUTING:IPv6',
      'raw:OUTPUT:IPv6',
      'raw:ff:IPv6',
      'mangle:PREROUTING:IPv6',
      'mangle:INPUT:IPv6',
      'mangle:FORWARD:IPv6',
      'mangle:OUTPUT:IPv6',
      'mangle:POSTROUTING:IPv6',
      'mangle:ff:IPv6',
      ':INPUT:IPv6',
      ':FORWARD:IPv6',
      ':OUTPUT:IPv6',
      ':test:IPv6',
    ]
    allow(provider).to receive(:execute).with(['/sbin/ip6tables-save']).and_return('
# Generated by ip6tables-save v1.4.9 on Mon Jan  2 01:31:39 2012
*raw
:PREROUTING ACCEPT [2173:489241]
:OUTPUT ACCEPT [0:0]
:ff - [0:0]
COMMIT
# Completed on Mon Jan  2 01:31:39 2012
# Generated by ip6tables-save v1.4.9 on Mon Jan  2 01:31:39 2012
*mangle
:PREROUTING ACCEPT [2301:518373]
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
:ff - [0:0]
COMMIT
# Completed on Mon Jan  2 01:31:39 2012
# Generated by ip6tables-save v1.4.9 on Mon Jan  2 01:31:39 2012
*filter
:INPUT ACCEPT [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [20:1292]
:test - [0:0]
COMMIT
# Completed on Mon Jan  2 01:31:39 2012
')
    @all = ebtables + iptables + ip6tables
    # IPv4 and IPv6 names also exist as resources {table}:{chain}:IP and {table}:{chain}:
    iptables.each { |name| @all += [ name[0..-3], name[0..-5] ] }
    ip6tables.each { |name| @all += [ name[0..-3], name[0..-5] ] }
  end

  it 'should have all in parsed resources' do
    provider.instances.each do |resource|
      @all.include?(resource.name)
    end
  end

end
#!/usr/bin/env rspec

require 'spec_helper'
if Puppet.version < '3.4.0'
  require 'puppet/provider/confine/exists'
else
  require 'puppet/confine/exists'
end

describe 'iptables provider detection' do
  if Puppet.version < '3.4.0'
    let(:exists) {
      Puppet::Provider::Confine::Exists
    }
  else
    let(:exists) {
      Puppet::Confine::Exists
    }
  end

  before :each do
    # Reset the default provider
    Puppet::Type.type(:firewall).defaultprovider = nil
  end

  it "should default to iptables provider if /sbin/iptables[-save] exists" do
    # Stub lookup for /sbin/iptables & /sbin/iptables-save
    allow(exists).to receive(:which).with("iptables").
      and_return "/sbin/iptables"
    allow(exists).to receive(:which).with("iptables-save").
      and_return "/sbin/iptables-save"

    # Every other command should return false so we don't pick up any
    # other providers
    allow(exists).to receive(:which).with() { |value|
      ! ["iptables","iptables-save"].include?(value)
    }.and_return false

    # Create a resource instance and make sure the provider is iptables
    resource = Puppet::Type.type(:firewall).new({
      :name => '000 test foo',
    })
    expect(resource.provider.class.to_s).to eq("Puppet::Type::Firewall::ProviderIptables")
  end
end

describe 'iptables provider' do
  let(:provider) { Puppet::Type.type(:firewall).provider(:iptables) }
  let(:resource) {
    Puppet::Type.type(:firewall).new({
      :name  => '000 test foo',
      :action  => 'accept',
    })
  }

  before :each do
    allow(Puppet::Type::Firewall).to receive(:defaultprovider).and_return provider
    allow(provider).to receive(:command).with(:iptables_save).and_return "/sbin/iptables-save"

    # Stub iptables version
    allow(Facter.fact(:iptables_version)).to receive(:value).and_return("1.4.2")

    allow(Puppet::Util::Execution).to receive(:execute).and_return ""
    allow(Puppet::Util).to receive(:which).with("iptables-save").
      and_return "/sbin/iptables-save"
  end

  it 'should be able to get a list of existing rules' do
    provider.instances.each do |rule|
      expect(rule).to be_instance_of(provider)
      expect(rule.properties[:provider].to_s).to eq(provider.name.to_s)
    end
  end

  it 'should ignore lines with fatal errors' do
    allow(Puppet::Util::Execution).to receive(:execute).with(['/sbin/iptables-save']).
      and_return("FATAL: Could not load /lib/modules/2.6.18-028stab095.1/modules.dep: No such file or directory")

    expect(provider.instances.length).to be_zero
  end

  describe '#insert_order' do
    let(:iptables_save_output) { [
      '-A INPUT -s 8.0.0.2/32 -p tcp -m multiport --ports 100 -m comment --comment "100 test" -j ACCEPT',
      '-A INPUT -s 8.0.0.3/32 -p tcp -m multiport --ports 200 -m comment --comment "200 test" -j ACCEPT',
      '-A INPUT -s 8.0.0.4/32 -p tcp -m multiport --ports 300 -m comment --comment "300 test" -j ACCEPT'
    ] }
    let(:resources) do
      iptables_save_output.each_with_index.collect { |l,index| provider.rule_to_hash(l, 'filter', index) }
    end
    let(:providers) do
      resources.collect { |r| provider.new(r) }
    end
    it 'understands offsets for adding rules to the beginning' do
      resource = Puppet::Type.type(:firewall).new({ :name => '001 test', })
      allow(resource.provider.class).to receive(:instances).and_return(providers)
      expect(resource.provider.insert_order).to eq(1) # 1-indexed
    end
    it 'understands offsets for editing rules at the beginning' do
      resource = Puppet::Type.type(:firewall).new({ :name => '100 test', })
      allow(resource.provider.class).to receive(:instances).and_return(providers)
      expect(resource.provider.insert_order).to eq(1)
    end
    it 'understands offsets for adding rules to the middle' do
      resource = Puppet::Type.type(:firewall).new({ :name => '101 test', })
      allow(resource.provider.class).to receive(:instances).and_return(providers)
      expect(resource.provider.insert_order).to eq(2)
    end
    it 'understands offsets for editing rules at the middle' do
      resource = Puppet::Type.type(:firewall).new({ :name => '200 test', })
      allow(resource.provider.class).to receive(:instances).and_return(providers)
      expect(resource.provider.insert_order).to eq(2)
    end
    it 'understands offsets for adding rules to the end' do
      resource = Puppet::Type.type(:firewall).new({ :name => '301 test', })
      allow(resource.provider.class).to receive(:instances).and_return(providers)
      expect(resource.provider.insert_order).to eq(4)
    end
    it 'understands offsets for editing rules at the end' do
      resource = Puppet::Type.type(:firewall).new({ :name => '300 test', })
      allow(resource.provider.class).to receive(:instances).and_return(providers)
      expect(resource.provider.insert_order).to eq(3)
    end

    context 'with unname rules between' do
      let(:iptables_save_output) { [
        '-A INPUT -s 8.0.0.2/32 -p tcp -m multiport --ports 100 -m comment --comment "100 test" -j ACCEPT',
        '-A INPUT -s 8.0.0.2/32 -p tcp -m multiport --ports 150 -m comment --comment "150 test" -j ACCEPT',
        '-A INPUT -s 8.0.0.3/32 -p tcp -m multiport --ports 200 -j ACCEPT',
        '-A INPUT -s 8.0.0.3/32 -p tcp -m multiport --ports 250 -j ACCEPT',
        '-A INPUT -s 8.0.0.4/32 -p tcp -m multiport --ports 300 -m comment --comment "300 test" -j ACCEPT',
        '-A INPUT -s 8.0.0.4/32 -p tcp -m multiport --ports 350 -m comment --comment "350 test" -j ACCEPT',
      ] }
      it 'understands offsets for adding rules before unnamed rules' do
        resource = Puppet::Type.type(:firewall).new({ :name => '001 test', })
        allow(resource.provider.class).to receive(:instances).and_return(providers)
        expect(resource.provider.insert_order).to eq(1)
      end
      it 'understands offsets for editing rules before unnamed rules' do
        resource = Puppet::Type.type(:firewall).new({ :name => '100 test', })
        allow(resource.provider.class).to receive(:instances).and_return(providers)
        expect(resource.provider.insert_order).to eq(1)
      end
      it 'understands offsets for adding rules between managed rules' do
        resource = Puppet::Type.type(:firewall).new({ :name => '120 test', })
        allow(resource.provider.class).to receive(:instances).and_return(providers)
        expect(resource.provider.insert_order).to eq(2)
      end
      it 'understands offsets for adding rules between unnamed rules' do
        resource = Puppet::Type.type(:firewall).new({ :name => '151 test', })
        allow(resource.provider.class).to receive(:instances).and_return(providers)
        expect(resource.provider.insert_order).to eq(3)
      end
      it 'understands offsets for adding rules after unnamed rules' do
        resource = Puppet::Type.type(:firewall).new({ :name => '351 test', })
        allow(resource.provider.class).to receive(:instances).and_return(providers)
        expect(resource.provider.insert_order).to eq(7)
      end
    end

    context 'with unname rules before and after' do
      let(:iptables_save_output) { [
        '-A INPUT -s 8.0.0.3/32 -p tcp -m multiport --ports 050 -j ACCEPT',
        '-A INPUT -s 8.0.0.3/32 -p tcp -m multiport --ports 090 -j ACCEPT',
        '-A INPUT -s 8.0.0.2/32 -p tcp -m multiport --ports 100 -m comment --comment "100 test" -j ACCEPT',
        '-A INPUT -s 8.0.0.2/32 -p tcp -m multiport --ports 150 -m comment --comment "150 test" -j ACCEPT',
        '-A INPUT -s 8.0.0.3/32 -p tcp -m multiport --ports 200 -j ACCEPT',
        '-A INPUT -s 8.0.0.3/32 -p tcp -m multiport --ports 250 -j ACCEPT',
        '-A INPUT -s 8.0.0.4/32 -p tcp -m multiport --ports 300 -m comment --comment "300 test" -j ACCEPT',
        '-A INPUT -s 8.0.0.4/32 -p tcp -m multiport --ports 350 -m comment --comment "350 test" -j ACCEPT',
        '-A INPUT -s 8.0.0.5/32 -p tcp -m multiport --ports 400 -j ACCEPT',
        '-A INPUT -s 8.0.0.5/32 -p tcp -m multiport --ports 450 -j ACCEPT',
      ] }
      it 'understands offsets for adding rules before unnamed rules' do
        resource = Puppet::Type.type(:firewall).new({ :name => '001 test', })
        allow(resource.provider.class).to receive(:instances).and_return(providers)
        expect(resource.provider.insert_order).to eq(1)
      end
      it 'understands offsets for editing rules before unnamed rules' do
        resource = Puppet::Type.type(:firewall).new({ :name => '100 test', })
        allow(resource.provider.class).to receive(:instances).and_return(providers)
        expect(resource.provider.insert_order).to eq(3)
      end
      it 'understands offsets for adding rules between managed rules' do
        resource = Puppet::Type.type(:firewall).new({ :name => '120 test', })
        allow(resource.provider.class).to receive(:instances).and_return(providers)
        expect(resource.provider.insert_order).to eq(4)
      end
      it 'understands offsets for adding rules between unnamed rules' do
        resource = Puppet::Type.type(:firewall).new({ :name => '151 test', })
        allow(resource.provider.class).to receive(:instances).and_return(providers)
        expect(resource.provider.insert_order).to eq(5)
      end
      it 'understands offsets for adding rules after unnamed rules' do
        resource = Puppet::Type.type(:firewall).new({ :name => '351 test', })
        allow(resource.provider.class).to receive(:instances).and_return(providers)
        expect(resource.provider.insert_order).to eq(9)
      end
      it 'understands offsets for adding rules at the end' do
        resource = Puppet::Type.type(:firewall).new({ :name => '950 test', })
        allow(resource.provider.class).to receive(:instances).and_return(providers)
        expect(resource.provider.insert_order).to eq(11)
      end
    end
  end

  # Load in ruby hash for test fixtures.
  load 'spec/fixtures/iptables/conversion_hash.rb'

  describe 'when converting rules to resources' do
    ARGS_TO_HASH.each do |test_name,data|
      describe "for test data '#{test_name}'" do
        let(:resource) { provider.rule_to_hash(data[:line], data[:table], 0) }

        # If this option is enabled, make sure the parameters exactly match
        if data[:compare_all] then
          it "the parameter hash keys should be the same as returned by rules_to_hash" do
            expect(resource.keys).to match_array(data[:params].keys)
          end
        end

        # Iterate across each parameter, creating an example for comparison
        data[:params].each do |param_name, param_value|
          it "the parameter '#{param_name.to_s}' should match #{param_value.inspect}" do
            # booleans get cludged to string "true"
            if param_value == true then
              expect(resource[param_name]).to be_true
            else
              expect(resource[param_name]).to eq(data[:params][param_name])
            end
          end
        end
      end
    end
  end

  describe 'when working out general_args' do
    HASH_TO_ARGS.each do |test_name,data|
      describe "for test data '#{test_name}'" do
        let(:resource) { Puppet::Type.type(:firewall).new(data[:params]) }
        let(:provider) { Puppet::Type.type(:firewall).provider(:iptables) }
        let(:instance) { provider.new(resource) }

        it 'general_args should be valid' do
          expect(instance.general_args.flatten).to eq(data[:args])
        end
      end
    end
  end

  describe 'when converting rules without comments to resources' do
    let(:sample_rule) {
      '-A INPUT -s 1.1.1.1 -d 1.1.1.1 -p tcp -m multiport --dports 7061,7062 -m multiport --sports 7061,7062 -j ACCEPT'
    }
    let(:resource) { provider.rule_to_hash(sample_rule, 'filter', 0) }
    let(:instance) { provider.new(resource) }

    it 'rule name contains a MD5 sum of the line' do
      expect(resource[:name]).to eq("9000 #{Digest::MD5.hexdigest(resource[:line])}")
    end

    it 'parsed the rule arguments correctly' do
      expect(resource[:chain]).to eq('INPUT')
      expect(resource[:source]).to eq('1.1.1.1/32')
      expect(resource[:destination]).to eq('1.1.1.1/32')
      expect(resource[:proto]).to eq('tcp')
      expect(resource[:dport]).to eq(['7061', '7062'])
      expect(resource[:sport]).to eq(['7061', '7062'])
      expect(resource[:action]).to eq('accept')
    end
  end

  describe 'when converting existing rules generates by system-config-firewall-tui to resources' do
    let(:sample_rule) {
      # as generated by iptables-save from rules created with system-config-firewall-tui
      '-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT'
    }
    let(:resource) { provider.rule_to_hash(sample_rule, 'filter', 0) }
    let(:instance) { provider.new(resource) }

    it 'rule name contains a MD5 sum of the line' do
      expect(resource[:name]).to eq("9000 #{Digest::MD5.hexdigest(resource[:line])}")
    end

    it 'parse arguments' do
      expect(resource[:chain]).to eq('INPUT')
      expect(resource[:proto]).to eq('tcp')
      expect(resource[:dport]).to eq(['22'])
      expect(resource[:state]).to eq(['NEW'])
      expect(resource[:action]).to eq('accept')
    end
  end

  describe 'when creating resources' do
    let(:instance) { provider.new(resource) }

    it 'insert_args should be an array' do
      expect(instance.insert_args.class).to eq(Array)
    end
  end

  describe 'when modifying resources' do
    let(:instance) { provider.new(resource) }

    it 'update_args should be an array' do
      expect(instance.update_args.class).to eq(Array)
    end

    it 'fails when modifying the chain' do
      expect { instance.chain = "OUTPUT" }.to raise_error(/is not supported/)
    end
  end

  describe 'when deleting resources' do
    let(:sample_rule) {
      '-A INPUT -s 1.1.1.1 -d 1.1.1.1 -p tcp -m multiport --dports 7061,7062 -m multiport --sports 7061,7062 -j ACCEPT'
    }
    let(:resource) { provider.rule_to_hash(sample_rule, 'filter', 0) }
    let(:instance) { provider.new(resource) }

    it 'resource[:line] looks like the original rule' do
      resource[:line] == sample_rule
    end

    it 'delete_args is an array' do
      expect(instance.delete_args.class).to eq(Array)
    end

    it 'delete_args is the same as the rule string when joined' do
      expect(instance.delete_args.join(' ')).to eq(sample_rule.gsub(/\-A/,
        '-t filter -D'))
    end
  end
end

describe 'ip6tables provider' do
  let(:provider6) { Puppet::Type.type(:firewall).provider(:ip6tables) }
  let(:resource) {
    Puppet::Type.type(:firewall).new({
      :name  => '000 test foo',
      :action  => 'accept',
      :provider => "ip6tables",
    })
  }

  before :each do
    allow(Puppet::Type::Firewall).to receive(:ip6tables).and_return provider6
    allow(provider6).to receive(:command).with(:ip6tables_save).and_return "/sbin/ip6tables-save"

    # Stub iptables version
    allow(Facter.fact(:ip6tables_version)).to receive(:value).and_return '1.4.7'

    allow(Puppet::Util::Execution).to receive(:execute).and_return ''
    allow(Puppet::Util).to receive(:which).with("ip6tables-save").
      and_return "/sbin/ip6tables-save"
  end

  it 'should be able to get a list of existing rules' do
    provider6.instances.each do |rule|
      rule.should be_instance_of(provider6)
      rule.properties[:provider6].to_s.should == provider6.name.to_s
    end
  end

  it 'should ignore lines with fatal errors' do
    allow(Puppet::Util::Execution).to receive(:execute).with(['/sbin/ip6tables-save']).
      and_return("FATAL: Could not load /lib/modules/2.6.18-028stab095.1/modules.dep: No such file or directory")
    provider6.instances.length.should == 0
  end

  # Load in ruby hash for test fixtures.
  load 'spec/fixtures/ip6tables/conversion_hash.rb'

  describe 'when converting rules to resources' do
    ARGS_TO_HASH6.each do |test_name,data|
      describe "for test data '#{test_name}'" do
        let(:resource) { provider6.rule_to_hash(data[:line], data[:table], 0) }

        # If this option is enabled, make sure the parameters exactly match
        if data[:compare_all] then
          it "the parameter hash keys should be the same as returned by rules_to_hash" do
            resource.keys.should =~ data[:params].keys
          end
        end

        # Iterate across each parameter, creating an example for comparison
        data[:params].each do |param_name, param_value|
          it "the parameter '#{param_name.to_s}' should match #{param_value.inspect}" do
            resource[param_name].should == data[:params][param_name]
          end
        end
      end
    end
  end

  describe 'when working out general_args' do
    HASH_TO_ARGS6.each do |test_name,data|
      describe "for test data '#{test_name}'" do
        let(:resource) { Puppet::Type.type(:firewall).new(data[:params]) }
        let(:provider6) { Puppet::Type.type(:firewall).provider(:ip6tables) }
        let(:instance) { provider6.new(resource) }

        it 'general_args should be valid' do
          instance.general_args.flatten.should == data[:args]
        end
      end
    end
  end
end

#!/usr/bin/env rspec

require 'spec_helper'

firewall = Puppet::Type.type(:firewall)

describe firewall do
  before :each do
    @class = firewall
    @provider = double 'provider'
    allow(@provider).to receive(:name).and_return(:iptables)
    allow(Puppet::Type::Firewall).to receive(:defaultprovider).and_return @provider

    @resource = @class.new({:name  => '000 test foo'})

    # Stub iptables version
    allow(Facter.fact(:iptables_version)).to receive(:value).and_return('1.4.2')
    allow(Facter.fact(:ip6tables_version)).to receive(:value).and_return('1.4.2')

    # Stub confine facts
    allow(Facter.fact(:kernel)).to receive(:value).and_return('Linux')
    allow(Facter.fact(:operatingsystem)).to receive(:value).and_return('Debian')
  end

  it 'should have :name be its namevar' do
    @class.key_attributes.should == [:name]
  end

  describe ':name' do
    it 'should accept a name' do
      @resource[:name] = '000-test-foo'
      @resource[:name].should == '000-test-foo'
    end

    it 'should not accept a name with non-ASCII chars' do
      lambda { @resource[:name] = '%*#^(#$' }.should raise_error(Puppet::Error)
    end
  end

  describe ':action' do
    it "should have no default" do
      res = @class.new(:name => "000 test")
      res.parameters[:action].should == nil
    end

    [:accept, :drop, :reject].each do |action|
      it "should accept value #{action}" do
        @resource[:action] = action
        @resource[:action].should == action
      end
    end

    it 'should fail when value is not recognized' do
      lambda { @resource[:action] = 'not valid' }.should raise_error(Puppet::Error)
    end
  end

  describe ':chain' do
    [:INPUT, :FORWARD, :OUTPUT, :PREROUTING, :POSTROUTING].each do |chain|
      it "should accept chain value #{chain}" do
        @resource[:chain] = chain
        @resource[:chain].should == chain
      end
    end

    it 'should fail when the chain value is not recognized' do
      lambda { @resource[:chain] = 'not valid' }.should raise_error(Puppet::Error)
    end
  end

  describe ':table' do
    [:nat, :mangle, :filter, :raw].each do |table|
      it "should accept table value #{table}" do
        @resource[:table] = table
        @resource[:table].should == table
      end
    end

    it "should fail when table value is not recognized" do
      lambda { @resource[:table] = 'not valid' }.should raise_error(Puppet::Error)
    end
  end

  describe ':proto' do
    [:tcp, :udp, :icmp, :esp, :ah, :vrrp, :igmp, :ipencap, :ospf, :gre, :all].each do |proto|
      it "should accept proto value #{proto}" do
        @resource[:proto] = proto
        @resource[:proto].should == proto
      end
    end

    it "should fail when proto value is not recognized" do
      lambda { @resource[:proto] = 'foo' }.should raise_error(Puppet::Error)
    end
  end

  describe ':jump' do
    it "should have no default" do
      res = @class.new(:name => "000 test")
      res.parameters[:jump].should == nil
    end

    ['QUEUE', 'RETURN', 'DNAT', 'SNAT', 'LOG', 'MASQUERADE', 'REDIRECT', 'MARK'].each do |jump|
      it "should accept jump value #{jump}" do
        @resource[:jump] = jump
        @resource[:jump].should == jump
      end
    end

    ['ACCEPT', 'DROP', 'REJECT'].each do |jump|
      it "should now fail when value #{jump}" do
        lambda { @resource[:jump] = jump }.should raise_error(Puppet::Error)
      end
    end

    it "should fail when jump value is not recognized" do
      lambda { @resource[:jump] = '%^&*' }.should raise_error(Puppet::Error)
    end
  end

  [:source, :destination].each do |addr|
    describe addr do
      it "should accept a #{addr} as a string" do
        @resource[addr] = '127.0.0.1'
        @resource[addr].should == '127.0.0.1/32'
      end
      ['0.0.0.0/0', '::/0'].each do |prefix|
        it "should be nil for zero prefix length address #{prefix}" do
          @resource[addr] = prefix
          @resource[addr].should == nil
        end
      end
      it "should accept a negated #{addr} as a string" do
        @resource[addr] = '! 127.0.0.1'
        @resource[addr].should == '! 127.0.0.1/32'
      end
    end
  end

  [:dport, :sport].each do |port|
    describe port do
      it "should accept a #{port} as string" do
        @resource[port] = '22'
        @resource[port].should == ['22']
      end

      it "should accept a #{port} as an array" do
        @resource[port] = ['22','23']
        @resource[port].should == ['22','23']
      end

      it "should accept a #{port} as a number" do
        @resource[port] = 22
        @resource[port].should == ['22']
      end

      it "should accept a #{port} as a hyphen separated range" do
        @resource[port] = ['22-1000']
        @resource[port].should == ['22-1000']
      end

      it "should accept a #{port} as a combination of arrays of single and " \
        "hyphen separated ranges" do

        @resource[port] = ['22-1000','33','3000-4000']
        @resource[port].should == ['22-1000','33','3000-4000']
      end

      it "should convert a port name for #{port} to its number" do
        @resource[port] = 'ssh'
        @resource[port].should == ['22']
      end

      it "should not accept something invalid for #{port}" do
        expect { @resource[port] = 'something odd' }.to raise_error(Puppet::Error, /^Parameter .+ failed.+Munging failed for value ".+" in class .+: no such service/)
      end

      it "should not accept something invalid in an array for #{port}" do
        expect { @resource[port] = ['something odd','something even odder'] }.to raise_error(Puppet::Error, /^Parameter .+ failed.+Munging failed for value ".+" in class .+: no such service/)
      end
    end
  end

  [:dst_type, :src_type].each do |addrtype|
    describe addrtype do
      it "should have no default" do
        res = @class.new(:name => "000 test")
        res.parameters[addrtype].should == nil
      end
    end

    [:UNSPEC, :UNICAST, :LOCAL, :BROADCAST, :ANYCAST, :MULTICAST, :BLACKHOLE,
     :UNREACHABLE, :PROHIBIT, :THROW, :NAT, :XRESOLVE].each do |type|
      it "should accept #{addrtype} value #{type}" do
        @resource[addrtype] = type
        @resource[addrtype].should == type
      end
    end

    it "should fail when #{addrtype} value is not recognized" do
      lambda { @resource[addrtype] = 'foo' }.should raise_error(Puppet::Error)
    end
  end

  [:iniface, :outiface].each do |iface|
    describe iface do
      it "should accept #{iface} value as a string" do
        @resource[iface] = 'eth1'
        @resource[iface].should == 'eth1'
      end
    end
  end

  [:tosource, :todest].each do |addr|
    describe addr do
      it "should accept #{addr} value as a string" do
        @resource[addr] = '127.0.0.1'
      end
    end
  end

  describe ':log_level' do
    values = {
      'panic' => '0',
      'alert' => '1',
      'crit'  => '2',
      'err'   => '3',
      'warn'  => '4',
      'warning' => '4',
      'not'  => '5',
      'notice' => '5',
      'info' => '6',
      'debug' => '7'
    }

    values.each do |k,v|
      it {
        @resource[:log_level] = k
        @resource[:log_level].should == v
      }

      it {
        @resource[:log_level] = 3
        @resource[:log_level].should == 3
      }

      it { lambda { @resource[:log_level] = 'foo' }.should raise_error(Puppet::Error) }
    end
  end

  describe ':icmp' do
    icmp_codes = {
      :iptables => {
        '0' => 'echo-reply',
        '3' => 'destination-unreachable',
        '4' => 'source-quench',
        '6' => 'redirect',
        '8' => 'echo-request',
        '9' => 'router-advertisement',
        '10' => 'router-solicitation',
        '11' => 'time-exceeded',
        '12' => 'parameter-problem',
        '13' => 'timestamp-request',
        '14' => 'timestamp-reply',
        '17' => 'address-mask-request',
        '18' => 'address-mask-reply'
      },
      :ip6tables => {
        '1' => 'destination-unreachable',
        '3' => 'time-exceeded',
        '4' => 'parameter-problem',
        '128' => 'echo-request',
        '129' => 'echo-reply',
        '133' => 'router-solicitation',
        '134' => 'router-advertisement',
        '137' => 'redirect'
      }
    }
    icmp_codes.each do |provider, values|
      describe provider do
        values.each do |k,v|
          it 'should convert icmp string to number' do
            @resource[:provider] = provider
            @resource[:provider].should == provider
            @resource[:icmp] = v
            @resource[:icmp].should == k
          end
        end
      end
    end

    it 'should accept values as integers' do
      @resource[:icmp] = 9
      @resource[:icmp].should == 9
    end

    it 'should fail if icmp type is "any"' do
      lambda { @resource[:icmp] = 'any' }.should raise_error(Puppet::Error)
    end

    it 'should fail if icmp type cannot be mapped to a numeric' do
      lambda { @resource[:icmp] = 'foo' }.should raise_error(Puppet::Error)
    end
  end

  describe ':state' do
    it 'should accept value as a string' do
      @resource[:state] = :INVALID
      @resource[:state].should == [:INVALID]
    end

    it 'should accept value as an array' do
      @resource[:state] = [:INVALID, :NEW]
      @resource[:state].should == [:INVALID, :NEW]
    end

    it 'should sort values alphabetically' do
      @resource[:state] = [:NEW, :ESTABLISHED]
      @resource[:state].should == [:ESTABLISHED, :NEW]
    end
  end

  describe ':ctstate' do
    it 'should accept value as a string' do
      @resource[:ctstate] = :INVALID
      @resource[:ctstate].should == [:INVALID]
    end

    it 'should accept value as an array' do
      @resource[:ctstate] = [:INVALID, :NEW]
      @resource[:ctstate].should == [:INVALID, :NEW]
    end

    it 'should sort values alphabetically' do
      @resource[:ctstate] = [:NEW, :ESTABLISHED]
      @resource[:ctstate].should == [:ESTABLISHED, :NEW]
    end
  end

  describe ':burst' do
    it 'should accept numeric values' do
      @resource[:burst] = 12
      @resource[:burst].should == 12
    end

    it 'should fail if value is not numeric' do
      lambda { @resource[:burst] = 'foo' }.should raise_error(Puppet::Error)
    end
  end

  describe ':recent' do
    ['set', 'update', 'rcheck', 'remove'].each do |recent|
      it "should accept recent value #{recent}" do
        @resource[:recent] = recent
        @resource[:recent].should == "--#{recent}"
      end
    end
  end

  describe ':action and :jump' do
    it 'should allow only 1 to be set at a time' do
      expect {
        @class.new(
          :name => "001-test",
          :action => "accept",
          :jump => "custom_chain"
        )
      }.to raise_error(Puppet::Error, /Only one of the parameters 'action' and 'jump' can be set$/)
    end
  end
  describe ':gid and :uid' do
    it 'should allow me to set uid' do
      @resource[:uid] = 'root'
      @resource[:uid].should == 'root'
    end
    it 'should allow me to set uid as an array, and silently hide my error' do
      @resource[:uid] = ['root', 'bobby']
      @resource[:uid].should == 'root'
    end
    it 'should allow me to set gid' do
      @resource[:gid] = 'root'
      @resource[:gid].should == 'root'
    end
    it 'should allow me to set gid as an array, and silently hide my error' do
      @resource[:gid] = ['root', 'bobby']
      @resource[:gid].should == 'root'
    end
  end

  describe ':set_mark' do
    ['1.3.2', '1.4.2'].each do |iptables_version|
      describe "with iptables #{iptables_version}" do
        before {
          Facter.clear
          allow(Facter.fact(:iptables_version)).to receive(:value).and_return iptables_version
          allow(Facter.fact(:ip6tables_version)).to receive(:value).and_return iptables_version
        }

        if iptables_version == '1.3.2'
          it 'should allow me to set set-mark without mask' do
            @resource[:set_mark] = '0x3e8'
            @resource[:set_mark].should == '0x3e8'
          end
          it 'should convert int to hex without mask' do
            @resource[:set_mark] = '1000'
            @resource[:set_mark].should == '0x3e8'
          end
          it 'should fail if mask is present' do
            lambda { @resource[:set_mark] = '0x3e8/0xffffffff'}.should raise_error(
              Puppet::Error, /iptables version #{iptables_version} does not support masks on MARK rules$/
            )
          end
        end

        if iptables_version == '1.4.2'
          it 'should allow me to set set-mark with mask' do
            @resource[:set_mark] = '0x3e8/0xffffffff'
            @resource[:set_mark].should == '0x3e8/0xffffffff'
          end
          it 'should convert int to hex and add a 32 bit mask' do
            @resource[:set_mark] = '1000'
            @resource[:set_mark].should == '0x3e8/0xffffffff'
          end
          it 'should add a 32 bit mask' do
            @resource[:set_mark] = '0x32'
            @resource[:set_mark].should == '0x32/0xffffffff'
          end
          it 'should use the mask provided' do
            @resource[:set_mark] = '0x32/0x4'
            @resource[:set_mark].should == '0x32/0x4'
          end
          it 'should use the mask provided and convert int to hex' do
            @resource[:set_mark] = '1000/0x4'
            @resource[:set_mark].should == '0x3e8/0x4'
          end
          it 'should fail if mask value is more than 32 bits' do
            lambda { @resource[:set_mark] = '1/4294967296'}.should raise_error(
              Puppet::Error, /MARK mask must be integer or hex between 0 and 0xffffffff$/
            )
          end
          it 'should fail if mask is malformed' do
            lambda { @resource[:set_mark] = '1000/0xq4'}.should raise_error(
              Puppet::Error, /MARK mask must be integer or hex between 0 and 0xffffffff$/
            )
          end
        end

        ['/', '1000/', 'pwnie'].each do |bad_mark|
          it "should fail with malformed mark '#{bad_mark}'" do
            lambda { @resource[:set_mark] = bad_mark}.should raise_error(Puppet::Error)
          end
        end
        it 'should fail if mark value is more than 32 bits' do
          lambda { @resource[:set_mark] = '4294967296'}.should raise_error(
            Puppet::Error, /MARK value must be integer or hex between 0 and 0xffffffff$/
          )
        end
      end
    end
  end

  [:chain, :jump].each do |param|
    describe param do
      it 'should autorequire fwchain when table and provider are undefined' do
        @resource[param] = 'FOO'
        @resource[:table].should == :filter
        @resource[:provider].should == :iptables

        chain = Puppet::Type.type(:firewallchain).new(:name => 'FOO:filter:IPv4')
        catalog = Puppet::Resource::Catalog.new
        catalog.add_resource @resource
        catalog.add_resource chain
        rel = @resource.autorequire[0]
        rel.source.ref.should == chain.ref
        rel.target.ref.should == @resource.ref
      end

      it 'should autorequire fwchain when table is undefined and provider is ip6tables' do
        @resource[param] = 'FOO'
        @resource[:table].should == :filter
        @resource[:provider] = :ip6tables

        chain = Puppet::Type.type(:firewallchain).new(:name => 'FOO:filter:IPv6')
        catalog = Puppet::Resource::Catalog.new
        catalog.add_resource @resource
        catalog.add_resource chain
        rel = @resource.autorequire[0]
        rel.source.ref.should == chain.ref
        rel.target.ref.should == @resource.ref
      end

      it 'should autorequire fwchain when table is raw and provider is undefined' do
        @resource[param] = 'FOO'
        @resource[:table] = :raw
        @resource[:provider].should == :iptables

        chain = Puppet::Type.type(:firewallchain).new(:name => 'FOO:raw:IPv4')
        catalog = Puppet::Resource::Catalog.new
        catalog.add_resource @resource
        catalog.add_resource chain
        rel = @resource.autorequire[0]
        rel.source.ref.should == chain.ref
        rel.target.ref.should == @resource.ref
      end

      it 'should autorequire fwchain when table is raw and provider is ip6tables' do
        @resource[param] = 'FOO'
        @resource[:table] = :raw
        @resource[:provider] = :ip6tables

        chain = Puppet::Type.type(:firewallchain).new(:name => 'FOO:raw:IPv6')
        catalog = Puppet::Resource::Catalog.new
        catalog.add_resource @resource
        catalog.add_resource chain
        rel = @resource.autorequire[0]
        rel.source.ref.should == chain.ref
        rel.target.ref.should == @resource.ref
      end

      # test where autorequire is still needed (table != filter)
      ['INPUT', 'OUTPUT', 'FORWARD'].each do |test_chain|
        it "should autorequire fwchain #{test_chain} when table is mangle and provider is undefined" do
          @resource[param] = test_chain
          @resource[:table] = :mangle
          @resource[:provider].should == :iptables

          chain = Puppet::Type.type(:firewallchain).new(:name => "#{test_chain}:mangle:IPv4")
          catalog = Puppet::Resource::Catalog.new
          catalog.add_resource @resource
          catalog.add_resource chain
          rel = @resource.autorequire[0]
          rel.source.ref.should == chain.ref
          rel.target.ref.should == @resource.ref
        end

        it "should autorequire fwchain #{test_chain} when table is mangle and provider is ip6tables" do
          @resource[param] = test_chain
          @resource[:table] = :mangle
          @resource[:provider] = :ip6tables

          chain = Puppet::Type.type(:firewallchain).new(:name => "#{test_chain}:mangle:IPv6")
          catalog = Puppet::Resource::Catalog.new
          catalog.add_resource @resource
          catalog.add_resource chain
          rel = @resource.autorequire[0]
          rel.source.ref.should == chain.ref
          rel.target.ref.should == @resource.ref
        end
      end

      # test of case where autorequire should not happen
      ['INPUT', 'OUTPUT', 'FORWARD'].each do |test_chain|

        it "should not autorequire fwchain #{test_chain} when table and provider are undefined" do
          @resource[param] = test_chain
          @resource[:table].should == :filter
          @resource[:provider].should == :iptables

          chain = Puppet::Type.type(:firewallchain).new(:name => "#{test_chain}:filter:IPv4")
          catalog = Puppet::Resource::Catalog.new
          catalog.add_resource @resource
          catalog.add_resource chain
          rel = @resource.autorequire[0]
          rel.should == nil
        end

        it "should not autorequire fwchain #{test_chain} when table is undefined and provider is ip6tables" do
          @resource[param] = test_chain
          @resource[:table].should == :filter
          @resource[:provider] = :ip6tables

          chain = Puppet::Type.type(:firewallchain).new(:name => "#{test_chain}:filter:IPv6")
          catalog = Puppet::Resource::Catalog.new
          catalog.add_resource @resource
          catalog.add_resource chain
          rel = @resource.autorequire[0]
          rel.should == nil
        end
      end
    end
  end

  describe ":chain and :jump" do
    it 'should autorequire independent fwchains' do
      @resource[:chain] = 'FOO'
      @resource[:jump] = 'BAR'
      @resource[:table].should == :filter
      @resource[:provider].should == :iptables

      chain_foo = Puppet::Type.type(:firewallchain).new(:name => 'FOO:filter:IPv4')
      chain_bar = Puppet::Type.type(:firewallchain).new(:name => 'BAR:filter:IPv4')
      catalog = Puppet::Resource::Catalog.new
      catalog.add_resource @resource
      catalog.add_resource chain_foo
      catalog.add_resource chain_bar
      rel = @resource.autorequire
      rel[0].source.ref.should == chain_foo.ref
      rel[0].target.ref.should == @resource.ref
      rel[1].source.ref.should == chain_bar.ref
      rel[1].target.ref.should == @resource.ref
    end
  end

  describe ':pkttype' do
    [:multicast, :broadcast, :unicast].each do |pkttype|
      it "should accept pkttype value #{pkttype}" do
        @resource[:pkttype] = pkttype
        @resource[:pkttype].should == pkttype
      end
    end

    it 'should fail when the pkttype value is not recognized' do
      lambda { @resource[:pkttype] = 'not valid' }.should raise_error(Puppet::Error)
    end
  end

  describe 'autorequire packages' do
    [:iptables, :ip6tables].each do |provider|
      it "provider #{provider} should autorequire package iptables" do
        @resource[:provider] = provider
        @resource[:provider].should == provider
        package = Puppet::Type.type(:package).new(:name => 'iptables')
        catalog = Puppet::Resource::Catalog.new
        catalog.add_resource @resource
        catalog.add_resource package
        rel = @resource.autorequire[0]
        rel.source.ref.should == package.ref
        rel.target.ref.should == @resource.ref
      end

      it "provider #{provider} should autorequire packages iptables and iptables-persistent" do
        @resource[:provider] = provider
        @resource[:provider].should == provider
        packages = [
          Puppet::Type.type(:package).new(:name => 'iptables'),
          Puppet::Type.type(:package).new(:name => 'iptables-persistent')
        ]
        catalog = Puppet::Resource::Catalog.new
        catalog.add_resource @resource
        packages.each do |package|
          catalog.add_resource package
        end
        packages.zip(@resource.autorequire) do |package, rel|
          rel.source.ref.should == package.ref
          rel.target.ref.should == @resource.ref
        end
      end
    end
  end
end
#!/usr/bin/env rspec

require 'spec_helper'

firewallchain = Puppet::Type.type(:firewallchain)

describe firewallchain do
  before(:each) do
    # Stub confine facts
    allow(Facter.fact(:kernel)).to receive(:value).and_return('Linux')
    allow(Facter.fact(:operatingsystem)).to receive(:value).and_return('Debian')
  end
  let(:klass) { firewallchain }
  let(:provider) {
    prov = double 'provider'
    allow(prov).to receive(:name).and_return(:iptables_chain)
    prov
  }
  let(:resource) {
    allow(Puppet::Type::Firewallchain).to receive(:defaultprovider).and_return provider
    klass.new({:name => 'INPUT:filter:IPv4', :policy => :accept })
  }

  it 'should have :name be its namevar' do
    klass.key_attributes.should == [:name]
  end

  describe ':name' do
    {'nat' => ['PREROUTING', 'POSTROUTING', 'INPUT', 'OUTPUT'],
     'mangle' => [ 'PREROUTING', 'POSTROUTING', 'INPUT', 'FORWARD', 'OUTPUT' ],
     'filter' => ['INPUT','OUTPUT','FORWARD'],
     'raw' => [ 'PREROUTING', 'OUTPUT'],
     'broute' => ['BROUTING']
    }.each_pair do |table, allowedinternalchains|
      ['IPv4', 'IPv6', 'ethernet'].each do |protocol|
        [ 'test', '$5()*&%\'"^$09):' ].each do |chainname|
          name = "#{chainname}:#{table}:#{protocol}"
          if table == 'nat' && protocol == 'IPv6'
            it "should fail #{name}" do
              expect { resource[:name] = name }.to raise_error(Puppet::Error)
            end
          elsif protocol != 'ethernet' && table == 'broute'
            it "should fail #{name}" do
              expect { resource[:name] = name }.to raise_error(Puppet::Error)
            end
          else
            it "should accept name #{name}" do
              resource[:name] = name
              resource[:name].should == name
            end
          end
        end # chainname
      end # protocol

      [ 'PREROUTING', 'POSTROUTING', 'BROUTING', 'INPUT', 'FORWARD', 'OUTPUT' ].each do |internalchain|
        name = internalchain + ':' + table + ':'
        if internalchain == 'BROUTING'
          name += 'ethernet'
        elsif table == 'nat'
          name += 'IPv4'
        else
          name += 'IPv4'
        end
        if allowedinternalchains.include? internalchain
          it "should allow #{name}" do
            resource[:name] = name
            resource[:name].should == name
          end
        else
          it "should fail #{name}" do
            expect { resource[:name] = name }.to raise_error(Puppet::Error)
          end
        end
      end # internalchain

    end # table, allowedinternalchainnames

    it 'should fail with invalid table names' do
      expect { resource[:name] = 'wrongtablename:test:IPv4' }.to raise_error(Puppet::Error)
    end

    it 'should fail with invalid protocols names' do
      expect { resource[:name] = 'test:filter:IPv5' }.to raise_error(Puppet::Error)
    end

  end

  describe ':policy' do

    [:accept, :drop, :queue, :return].each do |policy|
      it "should accept policy #{policy}" do
        resource[:policy] = policy
        resource[:policy].should == policy
      end
    end

    it 'should fail when value is not recognized' do
      expect { resource[:policy] = 'not valid' }.to raise_error(Puppet::Error)
    end

    [:accept, :drop, :queue, :return].each do |policy|
      it "non-inbuilt chains should not accept policy #{policy}" do
        expect { klass.new({:name => 'testchain:filter:IPv4', :policy => policy }) }.to raise_error(Puppet::Error)
      end
      it "non-inbuilt chains can accept policies on protocol = ethernet (policy #{policy})" do
        klass.new({:name => 'testchain:filter:ethernet', :policy => policy })
      end
    end

  end

  describe 'autorequire packages' do
    it "provider iptables_chain should autorequire package iptables" do
      resource[:provider].should == :iptables_chain
      package = Puppet::Type.type(:package).new(:name => 'iptables')
      catalog = Puppet::Resource::Catalog.new
      catalog.add_resource resource
      catalog.add_resource package
      rel = resource.autorequire[0]
      rel.source.ref.should == package.ref
      rel.target.ref.should == resource.ref
    end

    it "provider iptables_chain should autorequire packages iptables and iptables-persistent" do
      resource[:provider].should == :iptables_chain
      packages = [
        Puppet::Type.type(:package).new(:name => 'iptables'),
        Puppet::Type.type(:package).new(:name => 'iptables-persistent')
      ]
      catalog = Puppet::Resource::Catalog.new
      catalog.add_resource resource
      packages.each do |package|
        catalog.add_resource package
      end
      packages.zip(resource.autorequire) do |package, rel|
        rel.source.ref.should == package.ref
        rel.target.ref.should == resource.ref
      end
    end
  end

  describe 'purge iptables rules' do
    before(:each) do
      allow(Puppet::Type.type(:firewall).provider(:iptables)).to receive(:iptables_save).and_return(<<EOS
# Completed on Sun Jan  5 19:30:21 2014
# Generated by iptables-save v1.4.12 on Sun Jan  5 19:30:21 2014
*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
:LOCAL_FORWARD - [0:0]
:LOCAL_FORWARD_PRE - [0:0]
:LOCAL_INPUT - [0:0]
:LOCAL_INPUT_PRE - [0:0]
:fail2ban-ssh - [0:0]
-A INPUT -p tcp -m multiport --dports 22 -j fail2ban-ssh
-A INPUT -i lo -m comment --comment "012 accept loopback" -j ACCEPT
-A INPUT -p tcp -m multiport --dports 22 -m comment --comment "020 ssh" -j ACCEPT
-A OUTPUT -d 1.2.1.2 -j DROP
-A fail2ban-ssh -j RETURN
COMMIT
# Completed on Sun Jan  5 19:30:21 2014
EOS
)
    end

    it 'should generate iptables resources' do
      resource = Puppet::Type::Firewallchain.new(:name => 'INPUT:filter:IPv4', :purge => true)

      expect(resource.generate.size).to eq(3)
    end

    it 'should not generate ignored iptables rules' do
      resource = Puppet::Type::Firewallchain.new(:name => 'INPUT:filter:IPv4', :purge => true, :ignore => ['-j fail2ban-ssh'])

      expect(resource.generate.size).to eq(2)
    end

    it 'should not generate iptables resources when not enabled' do
      resource = Puppet::Type::Firewallchain.new(:name => 'INPUT:filter:IPv4')

      expect(resource.generate.size).to eq(0)
    end
  end
end
require 'spec_helper'

describe 'Puppet::Util::Firewall' do
  let(:resource) {
    type = Puppet::Type.type(:firewall)
    provider = double 'provider'
    allow(provider).to receive(:name).and_return(:iptables)
    allow(Puppet::Type::Firewall).to receive(:defaultprovider).and_return(provider)
    type.new({:name => '000 test foo'})
  }

  before(:each) { resource }

  describe '#host_to_ip' do
    subject { resource }
    specify {
      expect(Resolv).to receive(:getaddress).with('puppetlabs.com').and_return('96.126.112.51')
      subject.host_to_ip('puppetlabs.com').should == '96.126.112.51/32'
    }
    specify { subject.host_to_ip('96.126.112.51').should == '96.126.112.51/32' }
    specify { subject.host_to_ip('96.126.112.51/32').should == '96.126.112.51/32' }
    specify { subject.host_to_ip('2001:db8:85a3:0:0:8a2e:370:7334').should == '2001:db8:85a3::8a2e:370:7334/128' }
    specify { subject.host_to_ip('2001:db8:1234::/48').should == '2001:db8:1234::/48' }
    specify { subject.host_to_ip('0.0.0.0/0').should == nil }
    specify { subject.host_to_ip('::/0').should == nil }
  end

  describe '#host_to_mask' do
    subject { resource }
    specify {
      expect(Resolv).to receive(:getaddress).at_least(:once).with('puppetlabs.com').and_return('96.126.112.51')
      subject.host_to_mask('puppetlabs.com').should == '96.126.112.51/32'
      subject.host_to_mask('!puppetlabs.com').should == '! 96.126.112.51/32'
    }
    specify { subject.host_to_mask('96.126.112.51').should == '96.126.112.51/32' }
    specify { subject.host_to_mask('!96.126.112.51').should == '! 96.126.112.51/32' }
    specify { subject.host_to_mask('96.126.112.51/32').should == '96.126.112.51/32' }
    specify { subject.host_to_mask('! 96.126.112.51/32').should == '! 96.126.112.51/32' }
    specify { subject.host_to_mask('2001:db8:85a3:0:0:8a2e:370:7334').should == '2001:db8:85a3::8a2e:370:7334/128' }
    specify { subject.host_to_mask('!2001:db8:85a3:0:0:8a2e:370:7334').should == '! 2001:db8:85a3::8a2e:370:7334/128' }
    specify { subject.host_to_mask('2001:db8:1234::/48').should == '2001:db8:1234::/48' }
    specify { subject.host_to_mask('! 2001:db8:1234::/48').should == '! 2001:db8:1234::/48' }
    specify { subject.host_to_mask('0.0.0.0/0').should == nil }
    specify { subject.host_to_mask('!0.0.0.0/0').should == nil }
    specify { subject.host_to_mask('::/0').should == nil }
    specify { subject.host_to_mask('! ::/0').should == nil }
  end

  describe '#icmp_name_to_number' do
    describe 'proto unsupported' do
      subject { resource }

      %w{inet5 inet8 foo}.each do |proto|
        it "should reject invalid proto #{proto}" do
          expect { subject.icmp_name_to_number('echo-reply', proto) }.
            to raise_error(ArgumentError, "unsupported protocol family '#{proto}'")
        end
      end
    end

    describe 'proto IPv4' do
      proto = 'inet'
      subject { resource }
      specify { subject.icmp_name_to_number('echo-reply', proto).should == '0' }
      specify { subject.icmp_name_to_number('destination-unreachable', proto).should == '3' }
      specify { subject.icmp_name_to_number('source-quench', proto).should == '4' }
      specify { subject.icmp_name_to_number('redirect', proto).should == '6' }
      specify { subject.icmp_name_to_number('echo-request', proto).should == '8' }
      specify { subject.icmp_name_to_number('router-advertisement', proto).should == '9' }
      specify { subject.icmp_name_to_number('router-solicitation', proto).should == '10' }
      specify { subject.icmp_name_to_number('time-exceeded', proto).should == '11' }
      specify { subject.icmp_name_to_number('parameter-problem', proto).should == '12' }
      specify { subject.icmp_name_to_number('timestamp-request', proto).should == '13' }
      specify { subject.icmp_name_to_number('timestamp-reply', proto).should == '14' }
      specify { subject.icmp_name_to_number('address-mask-request', proto).should == '17' }
      specify { subject.icmp_name_to_number('address-mask-reply', proto).should == '18' }
    end

    describe 'proto IPv6' do
      proto = 'inet6'
      subject { resource }
      specify { subject.icmp_name_to_number('destination-unreachable', proto).should == '1' }
      specify { subject.icmp_name_to_number('time-exceeded', proto).should == '3' }
      specify { subject.icmp_name_to_number('parameter-problem', proto).should == '4' }
      specify { subject.icmp_name_to_number('echo-request', proto).should == '128' }
      specify { subject.icmp_name_to_number('echo-reply', proto).should == '129' }
      specify { subject.icmp_name_to_number('router-solicitation', proto).should == '133' }
      specify { subject.icmp_name_to_number('router-advertisement', proto).should == '134' }
      specify { subject.icmp_name_to_number('redirect', proto).should == '137' }
    end
  end

  describe '#string_to_port' do
    subject { resource }
    specify { subject.string_to_port('80','tcp').should == '80' }
    specify { subject.string_to_port(80,'tcp').should == '80' }
    specify { subject.string_to_port('http','tcp').should == '80' }
    specify { subject.string_to_port('domain','udp').should == '53' }
  end

  describe '#to_hex32' do
    subject { resource }
    specify { subject.to_hex32('0').should == '0x0' }
    specify { subject.to_hex32('0x32').should == '0x32' }
    specify { subject.to_hex32('42').should == '0x2a' }
    specify { subject.to_hex32('4294967295').should == '0xffffffff' }
    specify { subject.to_hex32('4294967296').should == nil }
    specify { subject.to_hex32('-1').should == nil }
    specify { subject.to_hex32('bananas').should == nil }
  end

  describe '#persist_iptables' do
    before { Facter.clear }
    subject { resource }

    describe 'when proto is IPv4' do
      let(:proto) { 'IPv4' }

      it 'should exec /sbin/service if running RHEL 6 or earlier' do
        allow(Facter.fact(:osfamily)).to receive(:value).and_return('RedHat')
        allow(Facter.fact(:operatingsystem)).to receive(:value).and_return('RedHat')
        allow(Facter.fact(:operatingsystemrelease)).to receive(:value).and_return('6')

        expect(subject).to receive(:execute).with(%w{/sbin/service iptables save})
        subject.persist_iptables(proto)
      end

      it 'should exec for systemd if running RHEL 7 or greater' do
        allow(Facter.fact(:osfamily)).to receive(:value).and_return('RedHat')
        allow(Facter.fact(:operatingsystem)).to receive(:value).and_return('RedHat')
        allow(Facter.fact(:operatingsystemrelease)).to receive(:value).and_return('7')

        expect(subject).to receive(:execute).with(%w{/usr/libexec/iptables/iptables.init save})
        subject.persist_iptables(proto)
      end

      it 'should exec for systemd if running Fedora 15 or greater' do
        allow(Facter.fact(:osfamily)).to receive(:value).and_return('RedHat')
        allow(Facter.fact(:operatingsystem)).to receive(:value).and_return('Fedora')
        allow(Facter.fact(:operatingsystemrelease)).to receive(:value).and_return('15')

        expect(subject).to receive(:execute).with(%w{/usr/libexec/iptables/iptables.init save})
        subject.persist_iptables(proto)
      end

      it 'should exec for CentOS identified from operatingsystem' do
        allow(Facter.fact(:osfamily)).to receive(:value).and_return(nil)
        allow(Facter.fact(:operatingsystem)).to receive(:value).and_return('CentOS')
        expect(subject).to receive(:execute).with(%w{/sbin/service iptables save})
        subject.persist_iptables(proto)
      end

      it 'should exec for Archlinux identified from osfamily' do
        allow(Facter.fact(:osfamily)).to receive(:value).and_return('Archlinux')
        expect(subject).to receive(:execute).with(['/bin/sh', '-c', '/usr/sbin/iptables-save > /etc/iptables/iptables.rules'])
        subject.persist_iptables(proto)
      end

      it 'should raise a warning when exec fails' do
        allow(Facter.fact(:osfamily)).to receive(:value).and_return('RedHat')
        allow(Facter.fact(:operatingsystem)).to receive(:value).and_return('RedHat')
        allow(Facter.fact(:operatingsystemrelease)).to receive(:value).and_return('6')

        expect(subject).to receive(:execute).with(%w{/sbin/service iptables save}).
          and_raise(Puppet::ExecutionFailure, 'some error')
        expect(subject).to receive(:warning).with('Unable to persist firewall rules: some error')
        subject.persist_iptables(proto)
      end
    end

    describe 'when proto is IPv6' do
      let(:proto) { 'IPv6' }

      it 'should exec for newer Ubuntu' do
        allow(Facter.fact(:osfamily)).to receive(:value).and_return(nil)
        allow(Facter.fact(:operatingsystem)).to receive(:value).and_return('Ubuntu')
        allow(Facter.fact(:iptables_persistent_version)).to receive(:value).and_return('0.5.3ubuntu2')
        expect(subject).to receive(:execute).with(%w{/usr/sbin/service iptables-persistent save})
        subject.persist_iptables(proto)
      end

      it 'should not exec for older Ubuntu which does not support IPv6' do
        allow(Facter.fact(:osfamily)).to receive(:value).and_return(nil)
        allow(Facter.fact(:operatingsystem)).to receive(:value).and_return('Ubuntu')
        allow(Facter.fact(:iptables_persistent_version)).to receive(:value).and_return('0.0.20090701')
        expect(subject).to receive(:execute).never
        subject.persist_iptables(proto)
      end

      it 'should not exec for Suse which is not supported' do
        allow(Facter.fact(:osfamily)).to receive(:value).and_return('Suse')
        expect(subject).to receive(:execute).never
        subject.persist_iptables(proto)
      end
    end
  end
end
require 'spec_helper'

describe 'Puppet::Util::IPCidr' do
  describe 'ipv4 address' do
    before { @ipaddr = Puppet::Util::IPCidr.new('96.126.112.51') }
    subject { @ipaddr }
    specify { subject.cidr.should == '96.126.112.51/32' }
    specify { subject.prefixlen.should == 32 }
    specify { subject.netmask.should == '255.255.255.255' }
  end

  describe 'single ipv4 address with cidr' do
    before { @ipcidr = Puppet::Util::IPCidr.new('96.126.112.51/32') }
    subject { @ipcidr }
    specify { subject.cidr.should == '96.126.112.51/32' }
    specify { subject.prefixlen.should == 32 }
    specify { subject.netmask.should == '255.255.255.255' }
  end

  describe 'ipv4 address range with cidr' do
    before { @ipcidr = Puppet::Util::IPCidr.new('96.126.112.0/24') }
    subject { @ipcidr }
    specify { subject.cidr.should == '96.126.112.0/24' }
    specify { subject.prefixlen.should == 24 }
    specify { subject.netmask.should == '255.255.255.0' }
  end

  describe 'ipv4 open range with cidr' do
    before { @ipcidr = Puppet::Util::IPCidr.new('0.0.0.0/0') }
    subject { @ipcidr }
    specify { subject.cidr.should == '0.0.0.0/0' }
    specify { subject.prefixlen.should == 0 }
    specify { subject.netmask.should == '0.0.0.0' }
  end

  describe 'ipv6 address' do
    before { @ipaddr = Puppet::Util::IPCidr.new('2001:db8:85a3:0:0:8a2e:370:7334') }
    subject { @ipaddr }
    specify { subject.cidr.should == '2001:db8:85a3::8a2e:370:7334/128' }
    specify { subject.prefixlen.should == 128 }
    specify { subject.netmask.should == 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff' }
  end

  describe 'single ipv6 addr with cidr' do
    before { @ipaddr = Puppet::Util::IPCidr.new('2001:db8:85a3:0:0:8a2e:370:7334/128') }
    subject { @ipaddr }
    specify { subject.cidr.should == '2001:db8:85a3::8a2e:370:7334/128' }
    specify { subject.prefixlen.should == 128 }
    specify { subject.netmask.should == 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff' }
  end

  describe 'ipv6 addr range with cidr' do
    before { @ipaddr = Puppet::Util::IPCidr.new('2001:db8:1234::/48') }
    subject { @ipaddr }
    specify { subject.cidr.should == '2001:db8:1234::/48' }
    specify { subject.prefixlen.should == 48 }
    specify { subject.netmask.should == 'ffff:ffff:ffff:0000:0000:0000:0000:0000' }
  end

  describe 'ipv6 open range with cidr' do
    before { @ipaddr = Puppet::Util::IPCidr.new('::/0') }
    subject { @ipaddr }
    specify { subject.cidr.should == '::/0' }
    specify { subject.prefixlen.should == 0 }
    specify { subject.netmask.should == '0000:0000:0000:0000:0000:0000:0000:0000' }
  end
end
fixtures:
  repositories:
    vcsrepo: git://github.com/puppetlabs/puppetlabs-vcsrepo.git
  symlinks:
    git: "#{source_dir}"
2011-06-03 - Dan Bode <dan@puppetlabs.com> - 0.0.1
* initial commit
                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!) The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright 2013 Puppet Labs

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
name 'puppetlabs-git'
version '0.0.3'
source 'git://github.com/puppetlabs/puppetlabs-git.git'
author 'puppetlabs'
license 'Apache 2.0'
summary 'module for installing git'
description 'module for installing git'
project_page 'https://github.com/puppetlabs/puppetlabs-git/'
dependency 'puppetlabs/vcsrepo'

#git

####Table of Contents

1. [Overview - What is the [Modulename] module?](#overview)
2. [Module Description - What does the module do?](#module-description)
3. [Setup - The basics of getting started with [Modulename]](#setup)
    * [What [Modulename] affects](#what-registry-affects)
4. [Usage - Configuration options and additional functionality](#usage)
6. [Limitations - OS compatibility, etc.](#limitations)
7. [Development - Guide for contributing to the module](#development)

##Overview

Simple module that can install git or gitosis

##Module Description

This module installs the git revision control system on a target node. It does not manage a git server or any associated services; it simply ensures a bare minimum set of features (e.g. just a package) to use git.

##Setup

###What git affects

* Package['git']

The specifics managed by the module may vary depending on the platform.

##Usage

###I just want `git` installed
Simply include the `git` class.

```puppet
include git
```

###I want to use `git subtree` with bash completion

```puppet
include git::subtree
```

##Reference

###Classes

* `git`: Installs the git client package.
* `gitosis`: Installs the gitosis package. No configuration
* `subtree`: Installs and configures git-subtree for git 1.7 and up.

###Facts

* `git_exec_path`: Path to the directory containing all `git-*` commands.
* `git_version`: Version of git that is installed. Undefined if not installed.

##Limitations

This module is known to work with the following operating system families:

 - RedHat 5, 6
 - Debian 6.0.7 or newer
 - Ubuntu 12.04 or newer

##Development

Puppet Labs modules on the Puppet Forge are open projects, and community contributions are essential for keeping them great. We can’t access the huge number of platforms and myriad of hardware, software, and deployment configurations that Puppet is intended to serve.

We want to keep it as easy as possible to contribute changes so that our modules work in your environment. There are a few guidelines that we need contributors to follow so that we can have a chance of keeping on top of things.

You can read the complete module contribution guide [on the Puppet Labs wiki.](http://projects.puppetlabs.com/projects/module-site/wiki/Module_contributing)
require 'puppetlabs_spec_helper/rake_tasks'
#!bash
#
# bash completion support for Git subtree.
#
# To use this routine:
#
#    1) Make sure you have installed and configured the core Git completion script, which is required to make this script work;
#    2) Copy this file to somewhere (e.g. ~/.git-subtree-completion.sh);
#    3) Added the following line to your .bashrc:
#        source ~/.git-subtree-completion.sh
#

_git_subtree ()
{
        local cur="${COMP_WORDS[COMP_CWORD]}"

        if [ $COMP_CWORD -eq 2 ]; then
                __gitcomp "add merge pull push split"
                return
        elif [ $COMP_CWORD -eq 3 ]; then
                __gitcomp "--prefix="
                return
        fi
        __gitcomp "$(__git_remotes)"
}
# git_exec_path.rb
Facter.add('git_exec_path') do
  setcode 'git --exec-path 2>/dev/null'
end
# git_version
Facter.add('git_version') do
  setcode 'git --version 2>/dev/null'.sub(/git version /, '')
end
# Class: gitosis
#
# This installs and configures gitosis 
#
# Requires:
#  - Class[git]
#
class git::gitosis {
  include ::git
  package {'gitosis':
    ensure => present
  }
}
# Class: git
#
# This class installs git
#
# Actions:
#   - Install the git package
#
# Sample Usage:
#  class { 'git': }
#
class git {
  if ! defined(Package['git']) {
    package { 'git':
      ensure => present
    }
  }
}
# == Class: git::subtree
#
# Installs and configure git-subtree
#
class git::subtree {

  include ::git

  Package['git'] -> Class['git::subtree']

  if (versioncmp('1.7.0', $::git_version) > 0) {
    fail 'git-subtree requires git 1.7 or later!'
  }

  if (versioncmp('1.7.11', $::git_version) > 0) {
    $source_dir = '/usr/src/git-subtree'
    vcsrepo { $source_dir:
      ensure   => present,
      source   => 'http://github.com/apenwarr/git-subtree.git',
      provider => 'git',
      revision => '2793ee6ba',
    }
  } else {
    $source_dir = '/usr/share/doc/git-core/contrib/subtree'
  }

  exec { "/usr/bin/make prefix=/usr libexecdir=${::git_exec_path}":
    creates => "${source_dir}/git-subtree",
    cwd     => $source_dir,
  }
  ->
  exec { "/usr/bin/make prefix=/usr libexecdir=${::git_exec_path} install":
    creates => "${::git_exec_path}/git-subtree",
    cwd     => $source_dir,
  }

  file { '/etc/bash_completion.d/git-subtree':
    ensure => file,
    source => 'puppet:///modules/git/subtree/bash_completion.sh',
    mode   => '0644',
  }

}
require 'spec_helper'

describe 'git::subtree' do

  context 'when git version < 1.7.0' do
    let(:facts) { { :git_version => '1.6.0' } }

    it 'should fail' do
      expect { should create_class('git::subtree') }.to raise_error(Puppet::Error, /git-subtree requires git 1.7 or later!/)
    end
  end

  context 'when git version > 1.7.0 and < 1.7.11' do
    let(:facts) { {
      :git_version   => '1.7.0',
      :git_exec_path => '/usr/lib/git-core',
    } }

    it { should create_class('git') }

    it { should create_vcsrepo('/usr/src/git-subtree').with({
      :ensure   => 'present',
      :source   => 'http://github.com/apenwarr/git-subtree.git',
      :provider => 'git',
      :revision => '2793ee6ba',
    })}

    it { should create_exec('/usr/bin/make prefix=/usr libexecdir=/usr/lib/git-core').with({
      :creates => '/usr/src/git-subtree/git-subtree',
      :cwd     => '/usr/src/git-subtree',
    })}

    it { should create_exec('/usr/bin/make prefix=/usr libexecdir=/usr/lib/git-core install').with({
      :creates => '/usr/lib/git-core/git-subtree',
      :cwd     => '/usr/src/git-subtree',
    })}

    it { should create_file('/etc/bash_completion.d/git-subtree').with({
      :ensure => 'file',
      :source => 'puppet:///modules/git/subtree/bash_completion.sh',
      :mode   => '0644',
    })}
  end 

  context 'when git version >= 1.7.11' do
    let(:facts) { {
      :git_version   => '1.7.11',
      :git_exec_path => '/usr/lib/git-core',
    } }

    it { should create_class('git') }

    it { should create_exec('/usr/bin/make prefix=/usr libexecdir=/usr/lib/git-core').with({
      :creates => '/usr/share/doc/git-core/contrib/subtree/git-subtree',
      :cwd     => '/usr/share/doc/git-core/contrib/subtree',
    })}

    it { should create_exec('/usr/bin/make prefix=/usr libexecdir=/usr/lib/git-core install').with({
      :creates => '/usr/lib/git-core/git-subtree',
      :cwd     => '/usr/share/doc/git-core/contrib/subtree',
    })}

    it { should create_file('/etc/bash_completion.d/git-subtree').with({
      :ensure => 'file',
      :source => 'puppet:///modules/git/subtree/bash_completion.sh',
      :mode   => '0644',
    })}
  end 

end
require 'puppetlabs_spec_helper/module_spec_helper'
class { 'git::gitosis': }
class { 'git': }
fixtures:
  repositories:
    stdlib: http://github.com/puppetlabs/puppetlabs-stdlib.git
  symlinks:
    java: "#{source_dir}"
branches:
  only:
  - master
language: ruby
bundler_args: --without development
script: "bundle exec rake spec SPEC_OPTS='--format documentation'"
after_success:
  - git clone -q git://github.com/puppetlabs/ghpublisher.git .forge-releng
  - .forge-release/publish
rvm:
- 1.8.7
- 1.9.3
- 2.0.0
env:
  matrix:
    - PUPPET_GEM_VERSION="~> 2.7.0"
    - PUPPET_GEM_VERSION="~> 3.0.0"
    - PUPPET_GEM_VERSION="~> 3.1.0"
    - PUPPET_GEM_VERSION="~> 3.2.0"
  global:
    - PUBLISHER_LOGIN=puppetlabs
    - secure: |-
        InMPZJVSGFC/AfcTbM6eKpYjPU3L1m1/P8BiXwcwreeyz0elsX2qmXk80A1h
        \nakUY6VxLtzcFGBHV1V8NvpRHovUBSzRGuhSFUm72XL62OB6TMl+Wg30coJ
        /N\nXjEfy7N5TQ3ThTKf1gfph0x/3iJBPgqIuIIELJCQJusTRDPKWYQ=
matrix:
  exclude:
    - rvm: 1.9.3
      env: PUPPET_GEM_VERSION="~> 2.7.0"
    - rvm: 2.0.0
      env: PUPPET_GEM_VERSION="~> 2.7.0"
    - rvm: 2.0.0
      env: PUPPET_GEM_VERSION="~> 3.0.0"
    - rvm: 2.0.0
      env: PUPPET_GEM_VERSION="~> 3.1.0"
    - rvm: 1.8.7
      env: PUPPET_GEM_VERSION="~> 3.2.0"
notifications:
  email: false
##2014-11-11 - Supported Version 1.2.0

###Summary: 
This release adds SLES 12 support and is tested for Future Parser Support

####Bugfixes:
- Several readme updates
- Testcase flexability increased

####Features:
- Add SLES 12 support
- Future Parser tested
- Validated against PE 3.7  

##2014-08-25 - Supported Version 1.1.2

###Summary: 
This release begins the support coverage of the puppetlabs-java module.

###Bugfixes:
- Update java alternative values from deprecated names
- Readme updated
- Testing updated

##2014-05-02 - Version 1.1.1

###Summary:

Add support for new versions of Debian and Ubuntu!

####Features:
- Add support for Ubuntu Trusty (14.04)
- Add support for Debian Jessie (8.x)

##2014-01-06 - Version 1.1.0

####Summary:

Primarily a release for Ubuntu users!

####Features:
- Add support for Ubuntu Saucy (13.10)
- Add `java_home` parameter for centralized setting of JAVA_HOME.
- Add Scientific Linux

###Bugfixes:
- Plus signs are valid in debian/ubuntu package names.

##2013-08-01 - Version 1.0.1

Matthaus Owens <matthaus@puppetlabs.com>
* Update java packages for Fedora systems

##2013-07-29 - Version 1.0.0

####Detailed Changes

Krzysztof Suszyński <krzysztof.suszynski@coi.gov.pl>
* Adding support for Oracle Enterprise Linux

Peter Drake <pdrake@allplayers.com>
* Add support for natty

Robert Munteanu <rmuntean@adobe.com>
* Add support for OpenSUSE

Martin Jackson <martin@uncommonsense-uk.com>
* Added support Amazon Linux using facter >= 1.7.x

Gareth Rushgrove <gareth@morethanseven.net>
Brett Porter <brett@apache.org>
* Fixes for older versions of CentOS
* Improvements to module build and tests

Nathan R Valentine <nrvale0@gmail.com>
* Add support for Ubuntu quantal and raring

Sharif Nassar <sharif@mediatemple.net>
* Add support for Debian alternatives, and more than one JDK/JRE per platform.

##2013-04-04 - Version 0.3.0
Reid Vandewiele <reid@puppetlabs.com> -
* Refactor, introduce params pattern

##2012-11-15 - Version 0.2.0
Scott Schneider <sschneider@puppetlabs.com>
* Add Solaris support

##2011-06-16 - Version 0.1.5
Jeff McCune <jeff@puppetlabs.com> 
* Add Debian based distro (Lucid) support

##2011-06-02 - Version 0.1.4
Jeff McCune <jeff@puppetlabs.com> 
* Fix class composition ordering problems

##2011-05-28 - Version 0.1.3
Jeff McCune <jeff@puppetlabs.com>
* Remove stages

##2011-05-26 - Version 0.1.2
Jeff McCune <jeff@puppetlabs.com>
* Changes JRE/JDK selection class parameter to $distribution

##2011-05-25 - Version 0.1.1
Jeff McCune <jeff@puppetlabs.com>
* Re-did versioning to follow semantic versioning
* Add validation of class parameters

##2011-05-24 - Version 0.1.0
Jeff McCune <jeff@puppetlabs.com> 
* Default to JDK version 6u25

##2011-05-24 - Version 0.0.1
Jeff McCune <jeff@puppetlabs.com> 
* Initial release
source ENV['GEM_SOURCE'] || "https://rubygems.org"

group :development, :test do
  gem 'rake',                    :require => false
  gem 'rspec-puppet',            :require => false
  gem 'puppetlabs_spec_helper',  :require => false
  gem 'serverspec',              :require => false
  gem 'puppet-lint',             :require => false
  gem 'beaker',                  :require => false
  gem 'beaker-rspec',            :require => false
  gem 'pry',                     :require => false
  gem 'simplecov',               :require => false
end

if facterversion = ENV['FACTER_GEM_VERSION']
  gem 'facter', facterversion, :require => false
else
  gem 'facter', :require => false
end

if puppetversion = ENV['PUPPET_GEM_VERSION']
  gem 'puppet', puppetversion, :require => false
else
  gem 'puppet', :require => false
end

# vim:ft=ruby
Puppet Java Module - Puppet module for managing Java

Copyright (C) 2011 Puppet Labs Inc

Puppet Labs can be contacted at: info@puppetlabs.com

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
#java

####Table of Contents

1. [Overview](#overview)
2. [Module Description - What the module does and why it is useful](#module-description)
3. [Setup - The basics of getting started with the java module](#setup)
    * [Beginning with the java module](#beginning-with-the-java-module)
4. [Usage - Configuration options and additional functionality](#usage)
5. [Reference - An under-the-hood peek at what the module is doing and how](#reference)
5. [Limitations - OS compatibility, etc.](#limitations)
6. [Development - Guide for contributing to the module](#development)

##Overview

Installs the correct Java package on various platforms. 

##Module Description

The java module can automatically install Java jdk or jre on a wide variety of systems. Java is a base component for many software platforms, but Java system packages don't always follow packaging conventions. The java module simplifies the Java installation process.

##Setup

###Beginning with the java module
To install the correct Java package on your system, include the `java` class: `include java`.

##Usage

The java module installs the correct jdk or jre package on a wide variety of systems. By default, the module will install the jdk package, but you can set different installation parameters as needed. For example, to install jre instead of jdk, you would set the distribution parameter:

```
class { 'java':
  distribution => 'jre',
}
```

##Reference

###Classes

####Public classes

* `java`: This is the module's main class, which installs and manages the Java package.

####Private classes

* `java::params`: Builds a hash of jdk/jre packages for all compatible operating systems. 

* `java::config`: Configures the Java alternatives on Debian systems.

###Parameters:

The following parameters are available in the java module:

* `distribution`: The Java distribution to install. Can be 'jdk','jre', or, where the platform supports alternative packages, 'sun-jdk', 'sun-jre', 'oracle-jdk', 'oracle-jre'. Defaults to 'jdk'.

* `version`: The version of Java to install, if you want to ensure a particular version. By default, the module ensures that Java is present but does not require a specific version.

* `package`: The name of the Java package. This is configurable in case you want to install a non-standard Java package. If not set, the module will install the appropriate package for the `distribution` parameter and target platform. If you set `package`, the `distribution` parameter will do nothing. 

* `java_alternative`: The name of the Java alternative to use on Debian systems. The command 'update-java-alternatives -l' will show which choices are available. If you specify a particular package, you will usually want to specify which Java alternative to use. If you set this parameter, you also need to set the `java_alternative_path`.

* `java_alternative_path`: The path to the 'java' command on Debian systems. Since the alternatives system makes it difficult to verify which alternative is actually enabled, this is required to ensure the correct JVM is enabled.

##Limitations

This module cannot guarantee installation of Java versions that are not available on  platform repositories. 

Oracle Java packages are not included in Debian 7 and Ubuntu 12.04/14.04 repositories. To install Java on those systems, you'll need to package Oracle JDK/JRE, and then the module will be able to install the package. For more information on how to package Oracle JDK/JRE, see the [Debian wiki](http://wiki.debian.org/JavaPackage).

This module is officially [supported](https://forge.puppetlabs.com/supported) for the following Java versions and platforms:

OpenJDK is supported on:
* Red Hat Enterprise Linux (RHEL) 5, 6, 7
* CentOS 5, 6, 7
* Oracle Linux 6, 7
* Scientific Linux 5, 6
* Debian 6, 7
* Ubuntu 10.04, 12.04, 14.04
* Solaris 11
* SLES 11 SP1, 12 

Sun Java is supported on:
* Debian 6

##Development

Puppet Labs modules on the Puppet Forge are open projects, and community contributions are essential for keeping them great. We can’t access the huge number of platforms and myriad of hardware, software, and deployment configurations that Puppet is intended to serve.

We want to keep it as easy as possible to contribute changes so that our modules work in your environment. There are a few guidelines that we need contributors to follow so that we can have a chance of keeping on top of things.

You can read the complete module contribution guide on the [Puppet Labs wiki](http://projects.puppetlabs.com/projects/module-site/wiki/Module_contributing).

##Contributors

The list of contributors can be found at: [https://github.com/puppetlabs/puppetlabs-java/graphs/contributors](https://github.com/puppetlabs/puppetlabs-java/graphs/contributors).
require 'puppetlabs_spec_helper/rake_tasks'
require 'puppet-lint/tasks/puppet-lint'

PuppetLint.configuration.send("disable_80chars")
PuppetLint.configuration.log_format = "%{path}:%{linenumber}:%{check}:%{KIND}:%{message}"
# On Debian systems, if alternatives are set, manually assign them.
class java::config ( ) {
  case $::osfamily {
    'Debian': {
      if $java::use_java_alternative != undef and $java::use_java_alternative_path != undef {
        exec { 'update-java-alternatives':
          path    => '/usr/bin:/usr/sbin:/bin:/sbin',
          command => "update-java-alternatives --set ${java::use_java_alternative} --jre",
          unless  => "test /etc/alternatives/java -ef '${java::use_java_alternative_path}'",
        }
      }
    }
    default: {
      # Do nothing.
    }
  }
}
# Class: java
#
# This module manages the Java runtime package
#
# Parameters:
#
#  [*distribution*]
#    The java distribution to install. Can be one of "jdk" or "jre",
#    or other platform-specific options where there are multiple
#    implementations available (eg: OpenJDK vs Oracle JDK).
#
#
#  [*version*]
#    The version of java to install. By default, this module simply ensures
#    that java is present, and does not require a specific version.
#
#  [*package*]
#    The name of the java package. This is configurable in case a non-standard
#    java package is desired.
#
#  [*java_alternative*]
#    The name of the java alternative to use on Debian systems.
#    "update-java-alternatives -l" will show which choices are available.
#    If you specify a particular package, you will almost always also
#    want to specify which java_alternative to choose. If you set
#    this, you also need to set the path below.
#
#  [*java_alternative_path*]
#    The path to the "java" command on Debian systems. Since the
#    alternatives system makes it difficult to verify which
#    alternative is actually enabled, this is required to ensure the
#    correct JVM is enabled.
#
# Actions:
#
# Requires:
#
# Sample Usage:
#
class java(
  $distribution          = 'jdk',
  $version               = 'present',
  $package               = undef,
  $java_alternative      = undef,
  $java_alternative_path = undef
) {
  include java::params

  validate_re($version, 'present|installed|latest|^[.+_0-9a-zA-Z:-]+$')

  if has_key($java::params::java, $distribution) {
    $default_package_name     = $java::params::java[$distribution]['package']
    $default_alternative      = $java::params::java[$distribution]['alternative']
    $default_alternative_path = $java::params::java[$distribution]['alternative_path']
    $java_home                = $java::params::java[$distribution]['java_home']
  } else {
    fail("Java distribution ${distribution} is not supported.")
  }

  $use_java_package_name = $package ? {
    undef   => $default_package_name,
    default => $package,
  }

  ## If $java_alternative is set, use that.
  ## Elsif the DEFAULT package is being used, then use $default_alternative.
  ## Else undef
  $use_java_alternative = $java_alternative ? {
    undef   => $use_java_package_name ? {
      $default_package_name => $default_alternative,
      default               => undef,
    },
    default => $java_alternative,
  }

  ## Same logic as $java_alternative above.
  $use_java_alternative_path = $java_alternative_path ? {
    undef   => $use_java_package_name ? {
      $default_package_name => $default_alternative_path,
      default               => undef,
    },
    default => $java_alternative_path,
  }

  anchor { 'java::begin:': }
  ->
  package { 'java':
    ensure => $version,
    name   => $use_java_package_name,
  }
  ->
  class { 'java::config': }
  -> anchor { 'java::end': }

}
# Class: java::params
#
# This class builds a hash of JDK/JRE packages and (for Debian)
# alternatives.  For wheezy/precise, we provide Oracle JDK/JRE
# options, even though those are not in the package repositories.
#
# For more info on how to package Oracle JDK/JRE, see the Debian wiki:
# http://wiki.debian.org/JavaPackage
#
# Because the alternatives system makes it very difficult to tell
# which Java alternative is enabled, we hard code the path to bin/java
# for the config class to test if it is enabled.
class java::params {

  case $::osfamily {
    default: { fail("unsupported platform ${::osfamily}") }
    'RedHat': {
      case $::operatingsystem {
        default: { fail("unsupported os ${::operatingsystem}") }
        'RedHat', 'CentOS', 'OracleLinux', 'Scientific': {
          if (versioncmp($::operatingsystemrelease, '5.0') < 0) {
            $jdk_package = 'java-1.6.0-sun-devel'
            $jre_package = 'java-1.6.0-sun'
          }
          elsif (versioncmp($::operatingsystemrelease, '6.3') < 0) {
            $jdk_package = 'java-1.6.0-openjdk-devel'
            $jre_package = 'java-1.6.0-openjdk'
          }
          else {
            $jdk_package = 'java-1.7.0-openjdk-devel'
            $jre_package = 'java-1.7.0-openjdk'
          }
        }
        'Fedora': {
          $jdk_package = 'java-1.7.0-openjdk-devel'
          $jre_package = 'java-1.7.0-openjdk'
        }
        'Amazon': {
          $jdk_package = 'java-1.7.0-openjdk-devel'
          $jre_package = 'java-1.7.0-openjdk'
        }
      }
      $java = {
        'jdk' => { 'package' => $jdk_package, },
        'jre' => { 'package' => $jre_package, },
      }
    }
    'Debian': {
      case $::lsbdistcodename {
        default: { fail("unsupported release ${::lsbdistcodename}") }
        'lenny', 'squeeze', 'lucid', 'natty': {
          $java  = {
            'jdk' => {
              'package'          => 'openjdk-6-jdk',
              'alternative'      => "java-6-openjdk-${architecture}",
              'alternative_path' => '/usr/lib/jvm/java-6-openjdk/jre/bin/java',
              'java_home'        => '/usr/lib/jvm/java-6-openjdk/jre/',
            },
            'jre' => {
              'package'          => 'openjdk-6-jre-headless',
              'alternative'      => "java-6-openjdk-${architecture}",
              'alternative_path' => '/usr/lib/jvm/java-6-openjdk/jre/bin/java',
              'java_home'        => '/usr/lib/jvm/java-6-openjdk/jre/',
            },
            'sun-jre' => {
              'package'          => 'sun-java6-jre',
              'alternative'      => 'java-6-sun',
              'alternative_path' => '/usr/lib/jvm/java-6-sun/jre/bin/java',
              'java_home'        => '/usr/lib/jvm/java-6-sun/jre/',
            },
            'sun-jdk' => {
              'package'          => 'sun-java6-jdk',
              'alternative'      => 'java-6-sun',
              'alternative_path' => '/usr/lib/jvm/java-6-sun/jre/bin/java',
              'java_home'        => '/usr/lib/jvm/java-6-sun/jre/',
            },
          }
        }
        'wheezy', 'jessie', 'precise','quantal','raring','saucy', 'trusty': {
          $java =  {
            'jdk' => {
              'package'          => 'openjdk-7-jdk',
              'alternative'      => "java-1.7.0-openjdk-${::architecture}",
              'alternative_path' => "/usr/lib/jvm/java-1.7.0-openjdk-${::architecture}/bin/java",
              'java_home'        => "/usr/lib/jvm/java-1.7.0-openjdk-${::architecture}/",
            },
            'jre' => {
              'package'          => 'openjdk-7-jre-headless',
              'alternative'      => "java-1.7.0-openjdk-${::architecture}",
              'alternative_path' => "/usr/lib/jvm/java-1.7.0-openjdk-${::architecture}/bin/java",
              'java_home'        => "/usr/lib/jvm/java-1.7.0-openjdk-${::architecture}/",
            },
            'oracle-jre' => {
              'package'          => 'oracle-j2re1.7',
              'alternative'      => 'j2re1.7-oracle',
              'alternative_path' => '/usr/lib/jvm/j2re1.7-oracle/bin/java',
              'java_home'        => '/usr/lib/jvm/j2re1.7-oracle/',
            },
            'oracle-jdk' => {
              'package'          => 'oracle-j2sdk1.7',
              'alternative'      => 'j2sdk1.7-oracle',
              'alternative_path' => '/usr/lib/jvm/j2sdk1.7-oracle/jre/bin/java',
              'java_home'        => '/usr/lib/jvm/j2sdk1.7-oracle/jre/',
            },
          }
        }
      }
    }
    'Solaris': {
      $java = {
        'jdk' => { 'package' => 'developer/java/jdk-7', },
        'jre' => { 'package' => 'runtime/java/jre-7', },
      }
    }
    'Suse': {
      case $::operatingsystem {
        default: {
          $jdk_package = 'java-1_6_0-ibm-devel'
          $jre_package = 'java-1_6_0-ibm'
        }

        "SLES": {
          case $::operatingsystemmajrelease{
            default: {
              $jdk_package = 'java-1_6_0-ibm-devel'
              $jre_package = 'java-1_6_0-ibm'
            }
            '12': {
              $jdk_package = 'java-1_7_0-openjdk-devel'
              $jre_package = 'java-1_7_0-openjdk'
            }
          }
        }

        'OpenSuSE': {
          $jdk_package = 'java-1_7_0-openjdk-devel'
          $jre_package = 'java-1_7_0-openjdk'
        }
      }
      $java = {
        'jdk' => { 'package' => $jdk_package, },
        'jre' => { 'package' => $jre_package, },
      }
    }
  }
}
{
  "name": "puppetlabs-java",
  "version": "1.2.0",
  "author": "puppetlabs",
  "summary": "Manage the official Java runtime",
  "license": "Apache",
  "source": "git://github.com/puppetlabs/puppetlabs-java",
  "project_page": "https://github.com/puppetlabs/puppetlabs-java",
  "issues_url": "https://tickets.puppetlabs.com/browse/MODULES",
  "operatingsystem_support": [
    {
      "operatingsystem": "RedHat",
      "operatingsystemrelease": [
        "5",
        "6",
        "7"
      ]
    },
    {
      "operatingsystem": "CentOS",
      "operatingsystemrelease": [
        "5",
        "6",
        "7"
      ]
    },
    {
      "operatingsystem": "OracleLinux",
      "operatingsystemrelease": [
        "6",
        "7"
      ]
    },
    {
      "operatingsystem": "Scientific",
      "operatingsystemrelease": [
        "5",
        "6"
      ]
    },
    {
      "operatingsystem": "Debian",
      "operatingsystemrelease": [
        "6",
        "7"
      ]
    },
    {
      "operatingsystem": "Ubuntu",
      "operatingsystemrelease": [
        "10.04",
        "12.04",
        "14.04"
      ]
    },
    {
      "operatingsystem": "SLES",
      "operatingsystemrelease": [
        "11 SP1",
        "12"
      ]
    },
    {
      "operatingsystem": "Solaris",
      "operatingsystemrelease": [
        "11"
      ]
    }
  ],
  "requirements": [
    {
      "name": "pe",
      "version_requirement": "3.x"
    },
    {
      "name": "puppet",
      "version_requirement": "3.x"
    }
  ],
  "dependencies": [
    {
      "name": "puppetlabs/stdlib",
      "version_requirement": ">= 2.4.0"
    }
  ]
}
require 'spec_helper_acceptance'

#RedHat, CentOS, Scientific, Oracle prior to 5.0  : Sun Java JDK/JRE 1.6
#RedHat, CentOS, Scientific, Oracle 5.0 < x < 6.3 : OpenJDK Java JDK/JRE 1.6
#RedHat, CentOS, Scientific, Oracle after 6.3     : OpenJDK Java JDK/JRE 1.7
#Debian 5/6 & Ubuntu 10.04/11.04                  : OpenJDK Java JDK/JRE 1.6 or Sun Java JDK/JRE 1.6
#Debian 7/Jesse & Ubuntu 12.04 - 14.04            : OpenJDK Java JDK/JRE 1.7 or Oracle Java JDK/JRE 1.6
#Solaris (what versions?)                         : Java JDK/JRE 1.7
#OpenSuSE                                         : OpenJDK Java JDK/JRE 1.7
#SLES                                             : IBM Java JDK/JRE 1.6

# C14677
# C14678
# C14679
# C14680
# C14681
# C14682
# C14684
# C14687
# C14692
# C14696
# C14697
# C14700 check on solaris 11
# C14701 check on sles 11
# C14703
# C14723 Where is oracle linux 5?
# C14724 Where is oracle linux 5?
# C14771 Where is redhat 7? Centos 7?
describe "installing java", :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
  describe "jre" do
    it 'should install jre' do
      pp = <<-EOS
        class { 'java':
          distribution => 'jre',
        }
      EOS

      apply_manifest(pp, :catch_failures => true)
      apply_manifest(pp, :catch_changes => true)
    end
  end
  describe "jdk" do
    it 'should install jdk' do
      pp = <<-EOS
        class { 'java': }
      EOS

      apply_manifest(pp, :catch_failures => true)
      apply_manifest(pp, :catch_changes => true)
    end
  end
end
# C14686
describe 'sun', :if => (fact('operatingsystem') == 'Debian' and fact('operatingsystemrelease').match(/(5|6)/)) do
  before :all do
    pp = <<-EOS
      file_line { 'non-free source':
        path  => '/etc/apt/sources.list',
        match => "deb http://osmirror.delivery.puppetlabs.net/debian/ ${::lsbdistcodename} main",
        line  => "deb http://osmirror.delivery.puppetlabs.net/debian/ ${::lsbdistcodename} main non-free",
      }
    EOS
    apply_manifest(pp)
    shell('apt-get update')
    shell('echo "sun-java6-jdk shared/accepted-sun-dlj-v1-1 select true" | debconf-set-selections')
    shell('echo "sun-java6-jre shared/accepted-sun-dlj-v1-1 select true" | debconf-set-selections')
  end
  describe 'jre' do
    it 'should install sun-jre' do
      pp = <<-EOS
        class { 'java':
          distribution => 'sun-jre',
        }
      EOS

      apply_manifest(pp, :catch_failures => true)
      apply_manifest(pp, :catch_changes => true)
    end
  end
  describe 'jdk' do
    it 'should install sun-jdk' do
      pp = <<-EOS
        class { 'java':
          distribution => 'sun-jdk',
        }
      EOS

      apply_manifest(pp, :catch_failures => true)
      apply_manifest(pp, :catch_changes => true)
    end
  end
end

# C14704
# C14705
# C15006
describe 'oracle', :if => (
  (fact('operatingsystem') == 'Debian') and (fact('operatingsystemrelease').match(/^7/)) or
  (fact('operatingsystem') == 'Ubuntu') and (fact('operatingsystemrelease').match(/^12\.04/)) or
  (fact('operatingsystem') == 'Ubuntu') and (fact('operatingsystemrelease').match(/^14\.04/))
) do
  # not supported
  # The package is not available from any sources, but if a customer
  # custom-builds the package using java-package and adds it to a local
  # repository, that is the intention of this version ability
  describe 'jre' do
    it 'should install oracle-jre' do
      pp = <<-EOS
        class { 'java':
          distribution => 'oracle-jre',
        }
      EOS

      apply_manifest(pp, :expect_failures => true)
    end
  end
  describe 'jdk' do
    it 'should install oracle-jdk' do
      pp = <<-EOS
        class { 'java':
          distribution => 'oracle-jdk',
        }
      EOS

      apply_manifest(pp, :expect_failures => true)
    end
  end
end

describe 'failure cases' do
  # C14711
  it 'should fail to install java with an incorrect version' do
    pp = <<-EOS
      class { 'java':
        version => '14.5',
      }
    EOS

    apply_manifest(pp, :expect_failures => true)
  end

  # C14712
  it 'should fail to install java with a blank version' do
    pp = <<-EOS
      class { 'java':
        version => '',
      }
    EOS

    apply_manifest(pp, :expect_failures => true)
  end

  # C14713
  it 'should fail to install java with an incorrect distribution' do
    pp = <<-EOS
      class { 'java':
        distribution => 'xyz',
      }
    EOS

    apply_manifest(pp, :expect_failures => true)
  end

  # C14714
  it 'should fail to install java with a blank distribution' do
    pp = <<-EOS
      class { 'java':
        distribution => '',
      }
    EOS

    apply_manifest(pp, :expect_failures => true)
  end

  # C14715
  it 'should fail to install java with an incorrect package' do
    pp = <<-EOS
      class { 'java':
        package => 'xyz',
      }
    EOS

    apply_manifest(pp, :expect_failures => true)
  end
  # C14715
  it 'should fail to install java with an incorrect package' do
    pp = <<-EOS
      class { 'java':
        package => 'xyz',
      }
    EOS

    apply_manifest(pp, :expect_failures => true)
  end
  # C14717
  # C14719
  # C14725
  it 'should fail on debian when passed fake java_alternative and path' do
    pp = <<-EOS
      class { 'java':
        java_alternative      => 'whatever',
        java_alternative_path => '/whatever',
      }
    EOS

    if fact('osfamily') == 'Debian'
      apply_manifest(pp, :expect_failures => true)
    else
      apply_manifest(pp, :catch_failures => true)
    end
  end
end
HOSTS:
  'centos-5-vcloud':
    roles:
      - master
    platform: el-5-x86_64
    hypervisor: vcloud
    template: centos-5-x86_64
CONFIG:
  type: foss
  ssh:
    keys: "~/.ssh/id_rsa-acceptance"
  datastore: instance0
  folder: Delivery/Quality Assurance/Enterprise/Dynamic
  resourcepool: delivery/Quality Assurance/Enterprise/Dynamic
  pooling_api: http://vcloud.delivery.puppetlabs.net/
HOSTS:
  centos-59-x64:
    roles:
      - master
      - database
      - console
    platform: el-5-x86_64
    box : centos-59-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-59-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: pe
HOSTS:
  centos-59-x64:
    roles:
      - master
    platform: el-5-x86_64
    box : centos-59-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-59-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: git
HOSTS:
  'centos-6-vcloud':
    roles:
      - master
    platform: el-6-x86_64
    hypervisor: vcloud
    template: centos-6-x86_64
CONFIG:
  type: foss
  ssh:
    keys: "~/.ssh/id_rsa-acceptance"
  datastore: instance0
  folder: Delivery/Quality Assurance/Enterprise/Dynamic
  resourcepool: delivery/Quality Assurance/Enterprise/Dynamic
  pooling_api: http://vcloud.delivery.puppetlabs.net/
HOSTS:
  centos-64-x64:
    roles:
      - master
    platform: el-6-x86_64
    box : centos-64-x64-fusion503-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x64-fusion503-nocm.box
    hypervisor : fusion
CONFIG:
  type: foss
HOSTS:
  centos-64-x64:
    roles:
      - master
      - database
      - dashboard
    platform: el-6-x86_64
    box : centos-64-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: pe
HOSTS:
  centos-64-x64:
    roles:
      - master
    platform: el-6-x86_64
    box : centos-64-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: foss
HOSTS:
  centos-65-x64:
    roles:
      - master
    platform: el-6-x86_64
    box : centos-65-x64-vbox436-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-65-x64-virtualbox-nocm.box
    hypervisor : vagrant
CONFIG:
  type: foss
HOSTS:
  'centos-7-vcloud':
    roles:
      - master
    platform: el-7-x86_64
    hypervisor: vcloud
    template: centos-7-x86_64
CONFIG:
  type: foss
  ssh:
    keys: "~/.ssh/id_rsa-acceptance"
  datastore: instance0
  folder: Delivery/Quality Assurance/Enterprise/Dynamic
  resourcepool: delivery/Quality Assurance/Enterprise/Dynamic
  pooling_api: http://vcloud.delivery.puppetlabs.net/
HOSTS:
  'debian-6-amd64':
    roles:
      - master
    platform: debian-6-amd64
    hypervisor: vcloud
    template: debian-6-x86_64
CONFIG:
  type: foss
  ssh:
    keys: "~/.ssh/id_rsa-acceptance"
  datastore: instance0
  folder: Delivery/Quality Assurance/Enterprise/Dynamic
  resourcepool: delivery/Quality Assurance/Enterprise/Dynamic
  pooling_api: http://vcloud.delivery.puppetlabs.net/
HOSTS:
  debian-607-x64:
    roles:
      - master
    platform: debian-6-amd64
    box : debian-607-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/debian-607-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: git
HOSTS:
  'debian-7-amd64':
    roles:
      - master
    platform: debian-7-amd64
    hypervisor: vcloud
    template: debian-7-x86_64
CONFIG:
  type: foss
  ssh:
    keys: "~/.ssh/id_rsa-acceptance"
  datastore: instance0
  folder: Delivery/Quality Assurance/Enterprise/Dynamic
  resourcepool: delivery/Quality Assurance/Enterprise/Dynamic
  pooling_api: http://vcloud.delivery.puppetlabs.net/
HOSTS:
  debian-70rc1-x64:
    roles:
      - master
    platform: debian-7-amd64
    box : debian-70rc1-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/debian-70rc1-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: git
HOSTS:
  centos-64-x64:
    roles:
      - master
    platform: el-6-x86_64
    box : centos-64-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: foss
HOSTS:
  fedora-18-x64:
    roles:
      - master
    platform: fedora-18-x86_64
    box : fedora-18-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/fedora-18-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: git
HOSTS:
  'redhat-7-vcloud':
    roles:
      - master
    platform: el-7-x86_64
    hypervisor: vcloud
    template: redhat-7-x86_64
CONFIG:
  type: foss
  ssh:
    keys: "~/.ssh/id_rsa-acceptance"
  datastore: instance0
  folder: Delivery/Quality Assurance/Enterprise/Dynamic
  resourcepool: delivery/Quality Assurance/Enterprise/Dynamic
  pooling_api: http://vcloud.delivery.puppetlabs.net/
HOSTS:
  'sles-11-vcloud':
    roles:
      - master
    platform: sles-11-x86_64
    hypervisor: vcloud
    template: sles-11-x86_64

CONFIG:
  type: foss
  ssh:
    keys: "~/.ssh/id_rsa-acceptance"
  datastore: instance0
  folder: Delivery/Quality Assurance/Enterprise/Dynamic
  resourcepool: delivery/Quality Assurance/Enterprise/Dynamic
  pooling_api: http://vcloud.delivery.puppetlabs.net/
HOSTS:
  sles-11sp1-x64:
    roles:
      - master
    platform: sles-11-x86_64
    box : sles-11sp1-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/sles-11sp1-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: git
HOSTS:
  'solaris-11-vcloud':
    roles:
      - master
    platform: solaris-11-i386
    hypervisor: vcloud
    template: solaris-11-x86_64
CONFIG:
  type: foss
  ssh:
    keys: "~/.ssh/id_rsa-acceptance"
  datastore: instance0
  folder: Delivery/Quality Assurance/Enterprise/Dynamic
  resourcepool: delivery/Quality Assurance/Enterprise/Dynamic
  pooling_api: http://vcloud.delivery.puppetlabs.net/
HOSTS:
  'ubuntu-1004-amd64':
    roles:
      - master
    platform: ubuntu-10.04-amd64
    hypervisor: vcloud
    template: ubuntu-1004-x86_64
CONFIG:
  type: foss
  ssh:
    keys: "~/.ssh/id_rsa-acceptance"
  datastore: instance0
  folder: Delivery/Quality Assurance/Enterprise/Dynamic
  resourcepool: delivery/Quality Assurance/Enterprise/Dynamic
  pooling_api: http://vcloud.delivery.puppetlabs.net/
HOSTS:
  'ubuntu-1404-amd64':
    roles:
      - master
    platform: ubuntu-14.04-amd64
    hypervisor: vcloud
    template: ubuntu-1404-x86_64
CONFIG:
  type: foss
  ssh:
    keys: "~/.ssh/id_rsa-acceptance"
  datastore: instance0
  folder: Delivery/Quality Assurance/Enterprise/Dynamic
  resourcepool: delivery/Quality Assurance/Enterprise/Dynamic
  pooling_api: http://vcloud.delivery.puppetlabs.net/
HOSTS:
  ubuntu-server-10044-x64:
    roles:
      - master
    platform: ubuntu-10.04-amd64
    box : ubuntu-server-10044-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/ubuntu-server-10044-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: foss
HOSTS:
  ubuntu-server-12042-x64:
    roles:
      - master
    platform: ubuntu-12.04-amd64
    box : ubuntu-server-12042-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/ubuntu-server-12042-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: foss
HOSTS:
  ubuntu-server-1404-x64:
    roles:
      - master
    platform: ubuntu-14.04-amd64
    box : puppetlabs/ubuntu-14.04-64-nocm
    box_url : https://vagrantcloud.com/puppetlabs/ubuntu-14.04-64-nocm
    hypervisor : vagrant
CONFIG:
  log_level   : debug
  type: git
require 'spec_helper'

describe 'java', :type => :class do

  context 'select openjdk for Centos 5.8' do
    let(:facts) { {:osfamily => 'RedHat', :operatingsystem => 'Centos', :operatingsystemrelease => '5.8'} }
    it { should contain_package('java').with_name('java-1.6.0-openjdk-devel') }
  end

  context 'select openjdk for Centos 6.3' do
    let(:facts) { {:osfamily => 'RedHat', :operatingsystem => 'Centos', :operatingsystemrelease => '6.3'} }
    it { should contain_package('java').with_name('java-1.7.0-openjdk-devel') }
  end

  context 'select openjdk for Centos 6.2' do
    let(:facts) { {:osfamily => 'RedHat', :operatingsystem => 'Centos', :operatingsystemrelease => '6.2'} }
    it { should contain_package('java').with_name('java-1.6.0-openjdk-devel') }
  end

  context 'select openjdk for Fedora' do
    let(:facts) { {:osfamily => 'RedHat', :operatingsystem => 'Fedora'} }
    it { should contain_package('java').with_name('java-1.7.0-openjdk-devel') }
  end

  context 'select passed value for Fedora' do
    let(:facts) { {:osfamily => 'RedHat', :operatingsystem => 'Fedora'} }
    let(:params) { { 'distribution' => 'jre' } }
    it { should contain_package('java').with_name('java-1.7.0-openjdk') }
  end

  context 'select passed value for Centos 5.3' do
    let(:facts) { {:osfamily => 'RedHat', :operatingsystem => 'Centos', :operatingsystemrelease => '5.3'} }
    let(:params) { { 'package' => 'jdk' } }
    it { should contain_package('java').with_name('jdk') }
    it { should_not contain_exec('update-java-alternatives') }
  end

  context 'select default for Centos 5.3' do
    let(:facts) { {:osfamily => 'RedHat', :operatingsystem => 'Centos', :operatingsystemrelease => '5.3'} }
    it { should contain_package('java').with_name('java-1.6.0-openjdk-devel') }
    it { should_not contain_exec('update-java-alternatives') }
  end

  context 'select default for Debian Wheezy' do
    let(:facts) { {:osfamily => 'Debian', :operatingsystem => 'Debian', :lsbdistcodename => 'wheezy', :operatingsystemrelease => '7.1', :architecture => 'amd64',} }
    it { should contain_package('java').with_name('openjdk-7-jdk') }
    it { should contain_exec('update-java-alternatives').with_command('update-java-alternatives --set java-1.7.0-openjdk-amd64 --jre') }
  end

  context 'select Oracle JRE for Debian Wheezy' do
    let(:facts) { {:osfamily => 'Debian', :operatingsystem => 'Debian', :lsbdistcodename => 'wheezy', :operatingsystemrelease => '7.1', } }
    let(:params) { { 'distribution' => 'oracle-jre' } }
    it { should contain_package('java').with_name('oracle-j2re1.7') }
    it { should contain_exec('update-java-alternatives').with_command('update-java-alternatives --set j2re1.7-oracle --jre') }
  end

  context 'select default for Debian Squeeze' do
    let(:facts) { {:osfamily => 'Debian', :operatingsystem => 'Debian', :lsbdistcodename => 'squeeze', :operatingsystemrelease => '6.0.5', :architecture => 'amd64',} }
    it { should contain_package('java').with_name('openjdk-6-jdk') }
    it { should contain_exec('update-java-alternatives').with_command('update-java-alternatives --set java-6-openjdk-amd64 --jre') }
  end

  context 'select Oracle JRE for Debian Squeeze' do
    let(:facts) { {:osfamily => 'Debian', :operatingsystem => 'Debian', :lsbdistcodename => 'squeeze', :operatingsystemrelease => '6.0.5'} }
    let(:params) { { 'distribution' => 'sun-jre', } }
    it { should contain_package('java').with_name('sun-java6-jre') }
    it { should contain_exec('update-java-alternatives').with_command('update-java-alternatives --set java-6-sun --jre') }
  end

  context 'select random alternative for Debian Wheezy' do
    let(:facts) { {:osfamily => 'Debian', :operatingsystem => 'Debian', :lsbdistcodename => 'wheezy', :operatingsystemrelease => '7.1'} }
    let(:params) { { 'java_alternative' => 'bananafish' } }
    it { should contain_package('java').with_name('openjdk-7-jdk') }
    it { should contain_exec('update-java-alternatives').with_command('update-java-alternatives --set bananafish --jre') }
  end

  context 'select openjdk for Amazon Linux' do
    let(:facts) { {:osfamily => 'RedHat', :operatingsystem => 'Amazon', :operatingsystemrelease => '3.4.43-43.43.amzn1.x86_64'} }
    it { should contain_package('java').with_name('java-1.7.0-openjdk-devel') }
  end

  context 'select passed value for Amazon Linux' do
    let(:facts) { {:osfamily => 'RedHat', :operatingsystem => 'Amazon', :operatingsystemrelease => '5.3.4.43-43.43.amzn1.x86_64'} }
    let(:params) { { 'distribution' => 'jre' } }
    it { should contain_package('java').with_name('java-1.7.0-openjdk') }
  end

  context 'select openjdk for Oracle Linux' do
    let(:facts) { {:osfamily => 'RedHat', :operatingsystem => 'OracleLinux', :operatingsystemrelease => '6.4'} }
    it { should contain_package('java').with_name('java-1.7.0-openjdk-devel') }
  end

  context 'select openjdk for Oracle Linux 6.2' do
    let(:facts) { {:osfamily => 'RedHat', :operatingsystem => 'OracleLinux', :operatingsystemrelease => '6.2'} }
    it { should contain_package('java').with_name('java-1.6.0-openjdk-devel') }
  end

  context 'select passed value for Oracle Linux' do
    let(:facts) { {:osfamily => 'RedHat', :operatingsystem => 'OracleLinux', :operatingsystemrelease => '6.3'} }
    let(:params) { { 'distribution' => 'jre' } }
    it { should contain_package('java').with_name('java-1.7.0-openjdk') }
  end

  context 'select passed value for Scientific Linux' do
    let(:facts) { {:osfamily => 'RedHat', :operatingsystem => 'Scientific', :operatingsystemrelease => '6.4'} }
    let(:params) { { 'distribution' => 'jre' } }
    it { should contain_package('java').with_name('java-1.7.0-openjdk') }
  end

  context 'select default for OpenSUSE 12.3' do
    let(:facts) { {:osfamily => 'Suse', :operatingsystem => 'OpenSUSE', :operatingsystemrelease => '12.3'}}
    it { should contain_package('java').with_name('java-1_7_0-openjdk-devel')}
  end

  describe 'incompatible OSs' do
    [
      {
        # C14706
        :osfamily               => 'windows',
        :operatingsystem        => 'windows',
        :operatingsystemrelease => '8.1',
      },
      {
        # C14707
        :osfamily               => 'Darwin',
        :operatingsystem        => 'Darwin',
        :operatingsystemrelease => '13.3.0',
      },
      {
        # C14708
        :osfamily               => 'AIX',
        :operatingsystem        => 'AIX',
        :operatingsystemrelease => '7100-02-00-000',
      },
      {
        # C14708
        :osfamily               => 'AIX',
        :operatingsystem        => 'AIX',
        :operatingsystemrelease => '6100-07-04-1216',
      },
      {
        # C14708
        :osfamily               => 'AIX',
        :operatingsystem        => 'AIX',
        :operatingsystemrelease => '5300-12-01-1016',
      },
    ].each do |facts|
      let(:facts) { facts }
      it "should fail on #{facts[:operatingsystem]} #{facts[:operatingsystemrelease]}" do
        expect { subject }.to raise_error Puppet::Error, /unsupported platform/
      end
    end
  end
end
require 'puppetlabs_spec_helper/module_spec_helper'
require 'beaker-rspec'

UNSUPPORTED_PLATFORMS = [ "Darwin", "windows" ]

unless ENV["RS_PROVISION"] == "no" or ENV["BEAKER_provision"] == "no"
  # This will install the latest available package on el and deb based
  # systems fail on windows and osx, and install via gem on other *nixes
  foss_opts = { :default_action => 'gem_install' }

  if default.is_pe?; then install_pe; else install_puppet( foss_opts ); end

  hosts.each do |host|
    if host["platform"] =~ /solaris/
      on host, "echo 'export PATH=/opt/puppet/bin:/var/ruby/1.8/gem_home/bin:${PATH}' >> ~/.bashrc"
    end
    unless host.is_pe?
      on host, "/bin/mkdir -p #{host["puppetpath"]}"
      on host, "/bin/echo '' > #{host["hieraconf"]}"
    end
    on host, "mkdir -p #{host["distmoduledir"]}"
    if host['platform'] =~ /sles-1/i ||  host['platform'] =~ /solaris-1/i
      get_stdlib = <<-stdlib
      package{'wget':}
      exec{'download':
        command => "wget -P /root/ https://forgeapi.puppetlabs.com/v3/files/puppetlabs-stdlib-4.3.2.tar.gz --no-check-certificate",
        path => ['/opt/csw/bin/','/usr/bin/']
      }
      stdlib
      apply_manifest_on(host, get_stdlib)
      # have to use force otherwise it checks ssl cert even though it is a local file
      on host, puppet('module install /root/puppetlabs-stdlib-4.3.2.tar.gz --force')
    else
      on host, puppet("module install puppetlabs-stdlib")
      # For test support
      on host, puppet("module install puppetlabs-apt")
    end
  end
end

RSpec.configure do |c|
  # Project root
  proj_root = File.expand_path(File.join(File.dirname(__FILE__), ".."))

  # Readable test descriptions
  c.formatter = :documentation

  # Configure all nodes in nodeset
  c.before :suite do
    # Install module
    hosts.each do |host|
      copy_module_to(host, :source => proj_root, :module_name => "java")
    end
  end
end
class { 'java':
  distribution => 'jdk',
  version      => 'latest',
}
fixtures:
  repositories:
    stdlib: "git://github.com/puppetlabs/puppetlabs-stdlib.git"
  symlinks:
    mailcatcher: "#{source_dir}"
branches:
  only:
  - master
language: ruby
bundler_args: --without development
script: "bundle exec rake spec SPEC_OPTS='--format documentation'"
rvm:
- 1.8.7
- 1.9.3
- 2.0.0
env:
  matrix:
    - PUPPET_GEM_VERSION="~> 2.7.0"
    - PUPPET_GEM_VERSION="~> 3.0.0"
    - PUPPET_GEM_VERSION="~> 3.1.0"
    - PUPPET_GEM_VERSION="~> 3.2.0"
matrix:
  exclude:
    - rvm: 1.9.3
      env: PUPPET_GEM_VERSION="~> 2.7.0"
    - rvm: 2.0.0
      env: PUPPET_GEM_VERSION="~> 2.7.0"
    - rvm: 2.0.0
      env: PUPPET_GEM_VERSION="~> 3.0.0"
    - rvm: 2.0.0
      env: PUPPET_GEM_VERSION="~> 3.1.0"
    - rvm: 1.8.7
      env: PUPPET_GEM_VERSION="~> 3.2.0"
notifications:
  email: false
source 'https://rubygems.org'
puppetversion = ENV.key?('PUPPET_VERSION') ? "= #{ENV['PUPPET_VERSION']}" : ['>= 2.7']

gem 'puppet', puppetversion

group :test do
  gem 'rake', '>= 0.9.0'
  gem 'rspec', '>= 2.8.0'
  gem 'rspec-puppet', '>= 0.1.1'
  gem 'puppetlabs_spec_helper', '>= 0.4.1'
  gem 'puppet-lint'
end
name    'actionjack-mailcatcher'
version '0.1.5'
source 'https://github.com/actionjack/puppet-mailcatcher'
author 'actionjack'
license 'Apache License, Version 2.0'
summary 'Install and configure the mailcatcher application.'
description "This puppet module is used to install and configure the mailcatcher
application.
MailCatcher runs a super simple SMTP server which catches any message sent to it
to display in a web interface."
project_page 'https://github.com/actionjack/puppet-mailcatcher'

dependency 'puppetlabs/stdlib', '>= 2.2.1'
# Mailcatcher

[![Build Status](https://travis-ci.org/actionjack/puppet-mailcatcher.png?branch=master)](https://travis-ci.org/actionjack/puppet-mailcatcher)

This puppet module is used to install and configure the mailcatcher application.
MailCatcher runs a super simple SMTP server which catches any message sent to it to display in a web interface.
http://mailcatcher.me/

* * *

## Configuration


## Dependencies

Current dependencies are:

 * 'puppetlabs/stdlib', '>= 2.1.0'

## Usage



```ruby
class {'mailcatcher': }
```

## Documentation

This module is written in puppetdoc compliant format so details on configuration and usage can be found by executing:

```bash
$ puppet doc manifest/init.pp
```
require 'puppetlabs_spec_helper/rake_tasks'
require 'puppet-lint/tasks/puppet-lint'

PuppetLint.configuration.send('disable_class_inherits_from_params_class')
PuppetLint.configuration.send("disable_80chars")
PuppetLint.configuration.log_format = "%{path}:%{linenumber}:%{check}:%{KIND}:%{message}"
# class mailcatcher::config
#
class mailcatcher::config {
  user { 'mailcatcher':
    ensure  => present,
    comment => 'Mailcatcher Mock Smtp Service User',
    home    => '/var/spool/mailcatcher',
    shell   => '/bin/true',
  }

  file { $mailcatcher::params::log_path:
    ensure  => directory,
    owner   => 'mailcatcher',
    group   => 'mailcatcher',
    mode    => 0755,
    require => User['mailcatcher']
  }
}
# == Class: mailcatcher
#
# Install and configure Mailcatcher.
# MailCatcher runs a super simple SMTP server which catches any message sent to
# it to display in a web interface.
# http://mailcatcher.me/
#
# === Parameters
#
# Document parameters here.
#
# [*smtp_ip*]
#   What IP address the mailcatcher smtp service should listen on.
#   The default is 127.0.0.1
#
# [*smtp_port*]
#   What TCP Port the mailcatcher smtp service should listen on.
#   The default is 1025
#
# [*http_ip*]
#   What IP address the mailcatcher web mail client service should listen on.
#   The default is 0.0.0.0
#
# [*http_port*]
#   What TCP Port the mailcatcher web mail client service should listen on.
#   The default is 1080
#
# [*mailcatcher_path*]
#   Path to the mailcatcher program.
#   The default is '/usr/local/bin'
#
# === Examples
#
# [*default*]
#
#  class { mailcatcher:  }
#
# [*listen on all ethernet adapters*]
#
#  class { mailcatcher:
#   smtp_ip => '0.0.0.0'
#  }
#
# === Authors
#
# Martin Jackson <contact@uncommonsense-uk.com>
#
# === Copyright
#
# Copyright 2013 Martin Jackson, unless otherwise noted.
#
class mailcatcher (
  $smtp_ip          = $mailcatcher::params::smtp_ip,
  $smtp_port        = $mailcatcher::params::smtp_port,
  $http_ip          = $mailcatcher::params::http_ip,
  $http_port        = $mailcatcher::params::http_port,
  $mailcatcher_path = $mailcatcher::params::mailcatcher_path,
  $log_path         = $mailcatcher::params::log_path
) inherits mailcatcher::params {

  class {'mailcatcher::package': } ->
  class {'mailcatcher::config': }

}
# class mailcatcher::package
#
class mailcatcher::package {
  each( $mailcatcher::params::packages ) |$package| {
    if ! defined(Package[$package]) {
      package { $package:
        ensure => present
      }
    }
  }

  package { 'mailcatcher':
    ensure   => present,
    provider => 'gem',
    require  => Package[$mailcatcher::params::packages]
  }
}
# class mailcatcher::params
#
class mailcatcher::params {
  $smtp_ip          = '0.0.0.0'
  $smtp_port        = '1025'
  $http_ip          = '0.0.0.0'
  $http_port        = '1080'
  $mailcatcher_path = '/usr/local/bin'
  $log_path         = '/var/log/mailcatcher'

  case $::osfamily {
    'Debian': {
      $packages = ['ruby-dev', 'sqlite3', 'libsqlite3-dev', 'rubygems']
    }
    'Redhat': {
      $packages = ['ruby-devel', 'sqlite', 'sqlite-devel', 'ruby-sqlite3', 'rubygems']
    }
    default: {
      fail("${::osfamily} is not supported.")
    }
  }
}
require 'spec_helper'

describe 'mailcatcher', :type => :class do
  context "As a Web Operations Engineer" do
    context 'When I install the mailcatcher base class on Ubuntu' do
      let :facts do {
          :osfamily        => 'Debian',
          :operatingsystem => 'Ubuntu'
      }
      end

      describe 'by default it' do
        it { should contain_package('ruby-dev') }
        it { should contain_package('sqlite3') }
        it { should contain_package('libsqlite3-dev') }
        it { should contain_package('rubygems') }
        it { should contain_package('mailcatcher').with({ 'provider' => 'gem'}) }
        it { should contain_user('mailcatcher') }
        it 'should contain a properly formatted start up configuration for upstart' do
          should contain_file('/etc/init/mailcatcher.conf').with_content(/exec\s+nohup\s+\/usr\/local\/bin\/mailcatcher\s+--http-ip\s+0\.0\.0\.0\s+--http-port\s+1080\s+--smtp-ip\s+0\.0\.0\.0\s+--smtp-port\s+1025\s+-f/)
        end
        it { should contain_file('/etc/init/mailcatcher.conf').with({ :notify => 'Class[Mailcatcher::Service]'})}
        it { should contain_file('/var/log/mailcatcher').with({
            :ensure  => 'directory',
            :owner   => 'mailcatcher',
            :group   => 'mailcatcher',
            :mode    => '0755',
            :require => 'User[mailcatcher]'
        })}
        it { should contain_service('mailcatcher').with({
            :ensure     => 'running',
            :provider   => 'upstart',
            :hasstatus  => true,
            :hasrestart => true,
            :require    => 'Class[Mailcatcher::Config]',
        })}

      end
    end
  end
end
require 'puppetlabs_spec_helper/module_spec_helper'
# mailcatcher - mock smtp server
#
# mailCatcher runs a super simple SMTP server which catches any
# message sent to it to display in a web interface.

description     "mock smtp server"

start on startup
stop on shutdown

setuid mailcatcher
setgid mailcatcher

script
 exec nohup <%= @mailcatcher_path %>/mailcatcher<%= @options.join(' ') %> -f  >> /var/log/mailcatcher/mailcatcher.log 2>&1
end script
# The baseline for module testing used by Puppet Labs is that each manifest
# should have a corresponding test manifest that declares that class or defined
# type.
#
# Tests are then run by using puppet apply --noop (to check for compilation
# errors and view a log of events) or by fully applying the test in a virtual
# environment (to compare the resulting system state to the desired state).
#
# Learn more about module testing here:
# http://docs.puppetlabs.com/guides/tests_smoke.html
#
include mailcatcher
fixtures:
  repositories:
    "stdlib": "git://github.com/puppetlabs/puppetlabs-stdlib.git"
    "apt": "git://github.com/puppetlabs/puppetlabs-apt.git"
  symlinks:
    "mongodb": "#{source_dir}"
default_set: 'centos-64-x64'
sets:
  'centos-59-x64':
    nodes:
      "main.foo.vm":
        prefab: 'centos-59-x64'
  'centos-64-x64':
    nodes:
      "main.foo.vm":
        prefab: 'centos-64-x64'
  'fedora-18-x64':
    nodes:
      "main.foo.vm":
        prefab: 'fedora-18-x64'
  'debian-607-x64':
    nodes:
      "main.foo.vm":
        prefab: 'debian-607-x64'
  'debian-70rc1-x64':
    nodes:
      "main.foo.vm":
        prefab: 'debian-70rc1-x64'
  'ubuntu-server-10044-x64':
    nodes:
      "main.foo.vm":
        prefab: 'ubuntu-server-10044-x64'
  'ubuntu-server-12042-x64':
    nodes:
      "main.foo.vm":
        prefab: 'ubuntu-server-12042-x64'
branches:
  only:
    - master
language: ruby
before_install:
  - gem update bundler
  - bundle --version
  - gem update --system 2.1.11
  - gem --version
bundler_args: --without development
script: "bundle exec rake spec SPEC_OPTS='--format documentation'"
after_success:
  - git clone -q git://github.com/puppetlabs/ghpublisher.git .forge-release
  - .forge-release/publish
rvm:
  - 1.8.7
  - 1.9.3
  - 2.0.0
env:
  matrix:
    - PUPPET_GEM_VERSION="~> 2.7.0"
    - PUPPET_GEM_VERSION="~> 3.3.0"
  global:
    - PUBLISHER_LOGIN=puppetlabs
    - secure: "iUYpjvk33JffZB9lVRqjuwRWesvcvmTknh908xnf60rUOA0QbGEPXxQY+LsQJEIimVsMA22fV6vp9BcqMEjO7OfK2MvAWsEWU/lG+kisFqhWDRf96sADE7k/RvPWJeB2xe+lWXK7Eh26jgctNfk4NptX1X1MjGmdzEvH7Aq79/w="
matrix:
  exclude:
    - rvm: 1.9.3
      env: PUPPET_GEM_VERSION="~> 2.7.0"
    - rvm: 2.0.0
      env: PUPPET_GEM_VERSION="~> 2.7.0"
notifications:
  email: false
##2014-05-27 - Release 0.8.0

This feature features a rewritten mongodb_replset{} provider, includes several
important bugfixes, ruby 1.8 support, and two new features.

####Features
- Rewritten mongodb_replset{}, featuring puppet resource support, prefetching,
and flushing.
- Add Ruby 1.8 compatibility.
- Adds `syslog`, allowing you to configure mongodb to send all logging to the hosts syslog.
- Add mongodb::replset, a wrapper class for hiera users.
- Improved testing!

####Bugfixes
- Fixes the package names to work since 10gen renamed them again.
- Fix provider name in the README.
- Disallow `nojournal` and `journal` to be set at the same time.
- Changed - to = for versioned install on Ubuntu.

####Known Bugs
* No known bugs

2014-1-29 - Version 0.7.0

Summary:

Added Replica Set Type and Provider

2014-1-17 - Version 0.6.0

Summary:

Added support for installing MongoDB client on 
RHEL family systems.

2014-01-10 Version 0.5.0

Summary:

Added types for providers for Mongo users and databases.

2013-12 Version 0.4.0

Major refactoring of the MongoDB module. Includes a new 'mongodb::globals' 
that consolidates many shared parameters into one location. This is an 
API-breaking release in anticipation of a 1.0 release.

2013-10-31 - Version 0.3.0

Summary:

Adds a number of parameters and fixes some platform
specific bugs in module deployment.

2013-09-25 - Version 0.2.0

Summary:

This release fixes a duplicate parameter.

Fixes:
- Fix a duplicated parameter.

2012-07-13 Puppet Labs <info@puppetlabs.com> - 0.1.0
* Add support for RHEL/CentOS
* Change default mongodb install location to OS repo

2012-05-29 Puppet Labs <info@puppetlabs.com> - 0.0.2
* Fix Modulefile typo.
* Remove repo pin.
* Update spec tests and add travis support.

2012-05-03 Puppet Labs <info@puppetlabs.com> - 0.0.1
* Initial Release.
source ENV['GEM_SOURCE'] || 'https://rubygems.org'

group :test, :development do
  gem 'rspec-puppet',            :require => false
  gem 'rake',                    :require => false
  gem 'puppetlabs_spec_helper',  :require => false
  gem 'serverspec',              :require => false
  gem 'puppet-lint',             :require => false
  gem 'pry',                     :require => false
  gem 'simplecov',               :require => false
  gem 'beaker',                  :require => false
  gem 'beaker-rspec',            :require => false
end

if puppetversion = ENV['PUPPET_VERSION']
  gem 'puppet', puppetversion, :require => false
else
  gem 'puppet', :require => false
end
Copyright (C) 2012 Puppet Labs Inc

Puppet Labs can be contacted at: info@puppetlabs.com

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
name 'puppetlabs-mongodb'
version '0.8.0'
source 'git@github.com:puppetlabs/puppetlabs-mongodb.git'
author 'puppetlabs'
license 'Apache License Version 2.0'
summary 'mongodb puppet module'
description '10gen mongodb puppet module'
project_page 'https://github.com/puppetlabs/puppetlabs-mongodb'

## Add dependencies, if any:
dependency 'puppetlabs/apt', '>= 1.0.0'
dependency 'puppetlabs/stdlib', '>= 2.2.0'
# mongodb puppet module

[![Build Status](https://travis-ci.org/puppetlabs/puppetlabs-mongodb.png?branch=master)](https://travis-ci.org/puppetlabs/puppetlabs-mongodb)

####Table of Contents

1. [Overview] (#overview)
2. [Module Description - What does the module do?](#module-description)
3. [Setup - The basics of getting started with mongodb](#setup)
4. [Usage - Configuration options and additional functionality](#usage)
5. [Reference - An under-the-hood peek at what the module is doing and how](#reference)
6. [Limitations - OS compatibility, etc.] (#limitations)
7. [Development - Guide for contributing to the module] (#development)

## Overview

Installs MongoDB on RHEL/Ubuntu/Debian from OS repo, or alternatively from
10gen repository [installation documentation](http://www.mongodb.org/display/DOCS/Ubuntu+and+Debian+packages).

### Deprecation Warning ###

This release is a major refactoring of the module which means that the API may
have changed in backwards incompatible ways. If your project depends on the old API,
please pin your dependencies to 0.3 version to ensure your environments don't break.

The current module design is undergoing review for potential 1.0 release. We welcome
any feedback with regard to the APIs and patterns used in this release.

##Module Description

The MongoDB module manages mongod server installation and configuration of the
mongod daemon. For the time being it supports only a single MongoDB server
instance, without sharding functionality.

For the 0.5 release, the MongoDB module now supports database and user types.

For the 0.6 release, the MongoDB module now supports basic replicaset features
(initiating a replicaset and adding members, but without specific options).

## Setup

###What MongoDB affects

* MongoDB package.
* MongoDB configuration files.
* MongoDB service.
* MongoDB client.
* 10gen/mongodb apt/yum repository.

###Beginning with MongoDB

If you just want a server installation with the default options you can run
`include '::mongodb::server'`. If you need to customize configuration
options you need to do the following:

```puppet
class {'::mongodb::server':
  port    => 27018,
  verbose => true,
}
```

For Red Hat family systems, the client can be installed in a similar fashion:

```
puppet class {'::mongodb::client':}
```

Note that for Debian/Ubuntu family systems the client is installed with the 
server. Using the client class will by default install the server.

Although most distros come with a prepacked MongoDB server we recommend to
use the 10gen/MongoDB software repository, because most of the current OS
packages are outdated and not appropriate for a production environment.
To install MongoDB from 10gen repository:

```puppet
class {'::mongodb::globals':
  manage_package_repo => true,
}->
class {'::mongodb::server': }->
class {'::mongodb::client': }
```

## Usage

Most of the interaction for the server is done via `mongodb::server`. For
more options please have a look at [mongodb::server](#class-mongodbserver).
Also in this version we introduced `mongodb::globals`, which is meant more
for future implementation, where you can configure the main settings for
this module in a global way, to be used by other classes and defined resources.
On its own it does nothing.

### Create MongoDB database

To install MongoDB server, create database "testdb" and user "user1" with password "pass1".

```puppet
class {'::mongodb::server':
  auth => true,
}

mongodb::db { 'testdb':
  user          => 'user1',
  password_hash => 'a15fbfca5e3a758be80ceaf42458bcd8',
}
```
Parameter 'password_hash' is hex encoded md5 hash of "user1:mongo:pass1".
Unsafe plain text password could be used with 'password' parameter instead of 'password_hash'.

## Reference

### Classes

####Public classes
* `mongodb::server`: Installs and configure MongoDB
* `mongodb::client`: Installs the MongoDB client shell (for Red Hat family systems)
* `mongodb::globals`: Configure main settings in a global way

####Private classes
* `mongodb::repo`: Manage 10gen/MongoDB software repository
* `mongodb::repo::apt`: Manage Debian/Ubuntu apt 10gen/MongoDB repository
* `mongodb::repo::yum`: Manage Redhat/CentOS apt 10gen/MongoDB repository
* `mongodb::server::config`: Configures MongoDB configuration files
* `mongodb::server::install`: Install MongoDB software packages
* `mongodb::server::service`: Manages service
* `mongodb::client::install`: Installs the MongoDB client software package

####Class: mongodb::globals
*Note:* most server specific defaults should be overridden in the `mongodb::server`
class. This class should only be used if you are using a non-standard OS or
if you are changing elements such as `version` or `manage_package_repo` that
can only be changed here.

This class allows you to configure the main settings for this module in a
global way, to be used by the other classes and defined resources. On its
own it does nothing.

#####`server_package_name`
This setting can be used to override the default MongoDB server package
name. If not specified, the module will use whatever package name is the
default for your OS distro.

#####`service_name`
This setting can be used to override the default MongoDB service name. If not
specified, the module will use whatever service name is the default for your OS distro.

#####`service_provider`
This setting can be used to override the default MongoDB service provider. If
not specified, the module will use whatever service provider is the default for
your OS distro.

#####`service_status`
This setting can be used to override the default status check command for
your MongoDB service. If not specified, the module will use whatever service
name is the default for your OS distro.

#####`user`
This setting can be used to override the default MongoDB user and owner of the
service and related files in the file system. If not specified, the module will
use the default for your OS distro.

#####`group`
This setting can be used to override the default MongoDB user group to be used
for related files in the file system. If not specified, the module will use
the default for your OS distro.

#####`bind_ip`
This setting can be used to configure MonogDB process to bind to and listen
for connections from applications on this address. If not specified, the
module will use the default for your OS distro.
*Note:* This value should be passed as an array.

#####`version`
The version of MonogDB to install/manage. This is a simple way of providing
a specific version such as '2.2' or '2.4' for example. If not specified,
the module will use the default for your OS distro.

####Class: mongodb::server

Most of the parameters manipulate the mongod.conf file.

For more details about configuration parameters consult the
[MongoDB Configuration File Options](http://docs.mongodb.org/manual/reference/configuration-options/).

#####`ensure`
Used to ensure that the package is installed and the service is running, or that the package is absent/purged and the service is stopped. Valid values are true/false/present/absent/purged.

#####`config`
Path of the config file. If not specified, the module will use the default
for your OS distro.

#####`dbpath`
Set this value to designate a directory for the mongod instance to store
it's data. If not specified, the module will use the default for your OS distro.

#####`pidfilepath`
Specify a file location to hold the PID or process ID of the mongod process.
If not specified, the module will use the default for your OS distro.

#####`logpath`
Specify the path to a file name for the log file that will hold all diagnostic
logging information. Unless specified, mongod will output all log information
to the standard output.

#####`bind_ip`
Set this option to configure the mongod or mongos process to bind to and listen
for connections from applications on this address. If not specified, the module
will use the default for your OS distro. Example: bind_ip=['127.0.0.1', '192.168.0.3']
*Note*: bind_ip accepts an array as a value.

#####`logappend`
Set to true to add new entries to the end of the logfile rather than overwriting
the content of the log when the process restarts. Default: True

#####`fork`
Set to true to fork server process at launch time. The default setting depends on
the operating system.

#####`port`
Specifies a TCP port for the server instance to listen for client connections.
Default: 27017

#####`journal`
Set to true to enable operation journaling to ensure write durability and
data consistency. Default: on 64-bit systems true and on 32-bit systems false

#####`nojournal`
Set nojournal = true to disable durability journaling. By default, mongod
enables journaling in 64-bit versions after v2.0.
Default: on 64-bit systems  false and on 32-bit systems true

*Note*: You must use journal to enable journaling on 32-bit systems.

#####`smallfiles`
Set to true to modify MongoDB to use a smaller default data file size.
Specifically, smallfiles reduces the initial size for data files and
limits them to 512 megabytes.  Default: false

#####`cpu`
Set to true to force mongod to report every four seconds CPU utilization
and the amount of time that the processor waits for I/O operations to
complete (i.e. I/O wait.) Default: false

#####`auth`
Set to true to enable database authentication for users connecting from
remote hosts. If no users exist, the localhost interface will continue
to have access to the database until you create the first user.
Default: false

#####`noauth`
Disable authentication. Currently the default. Exists for future compatibility
 and clarity.

#####`verbose`
Increases the amount of internal reporting returned on standard output or in
the log file generated by `logpath`. Default: false

#####`verbositylevel`
MongoDB has the following levels of verbosity: v, vv, vvv, vvvv and vvvvv.
Default: None

#####`objcheck`
Forces the mongod to validate all requests from clients upon receipt to ensure
that clients never insert invalid documents into the database.
Default: on v2.4 default to true and on earlier version to false

#####`quota`
Set to true to enable a maximum limit for the number of data files each database
can have. The default quota is 8 data files, when quota is true. Default: false

#####`quotafiles`
Modify limit on the number of data files per database. This option requires the
`quota` setting. Default: 8

#####`diaglog`
Creates a very verbose diagnostic log for troubleshooting and recording various
errors.  Valid values: 0, 1, 2, 3 and 7.
For more information please refer to [MongoDB Configuration File Options](http://docs.mongodb.org/manual/reference/configuration-options/).

#####`directoryperdb`
Set to true to modify the storage pattern of the data directory to store each
database’s files in a distinct folder. Default: false

#####`profile`
Modify this value to changes the level of database profiling, which inserts
information about operation performance into output of mongod or the
log file if specified by `logpath`.

#####`maxconns`
Specifies a value to set the maximum number of simultaneous connections
that MongoDB will accept. Default: depends on system (i.e. ulimit and file descriptor)
limits. Unless set, MongoDB will not limit its own connections.

#####`oplog_size`
Specifies a maximum size in megabytes for the replication operation log
(e.g. oplog.) mongod creates an oplog based on the maximum amount of space
available. For 64-bit systems, the oplog is typically 5% of available disk space.

#####`nohints`
Ignore query hints. Default: None

#####`nohttpinterface`
Set to true to disable the HTTP interface. This command will override the rest
and disable the HTTP interface if you specify both. Default: false

#####`noscripting`
Set noscripting = true to disable the scripting engine. Default: false

#####`notablescan`
Set notablescan = true to forbid operations that require a table scan. Default: false

#####`noprealloc`
Set noprealloc = true to disable the preallocation of data files. This will shorten
the start up time in some cases, but can cause significant performance penalties
during normal operations. Default: false

#####`nssize`
Use this setting to control the default size for all newly created namespace
files (i.e .ns). Default: 16

#####`mms_token`
MMS token for mms monitoring. Default: None

#####`mms_name`
MMS identifier for mms monitoring. Default: None

#####`mms_interval`
MMS interval for mms monitoring. Default: None

#####`replset`
Use this setting to configure replication with replica sets. Specify a replica
set name as an argument to this set. All hosts must have the same set name.

#####`rest`
Set to true to enable a simple REST interface. Default: false

#####`slowms`
Sets the threshold for mongod to consider a query “slow” for the database profiler.
Default: 100 ms

#####`keyfile`
Specify the path to a key file to store authentication information. This option
is only useful for the connection between replica set members. Default: None

#####`master`
Set to true to configure the current instance to act as master instance in a
replication configuration. Default: False  *Note*: deprecated – use replica sets

#####`set_parameter`
Specify extra configuration file parameters (i.e.
textSearchEnabled=true). Default: None

#####`syslog`
Sends all logging output to the host’s syslog system rather than to standard
output or a log file. Default: None
*Important*: You cannot use syslog with logpath.

#####`slave`
Set to true to configure the current instance to act as slave instance in a
replication configuration. Default: false
*Note*: deprecated – use replica sets

#####`only`
Used with the slave option, only specifies only a single database to
replicate. Default: <>
*Note*: deprecated – use replica sets

#####`source`
Used with the slave setting to specify the master instance from which
this slave instance will replicate. Default: <>
*Note*: deprecated – use replica sets

### Definitions

#### Definition: mongodb:db

Creates database with user. Resource title used as database name.

#####`user`
Name of the user for database

#####`password_hash`
Hex encoded md5 hash of "$username:mongo:$password".
For more information please refer to [MongoDB Authentication Process](http://docs.mongodb.org/meta-driver/latest/legacy/implement-authentication-in-driver/#authentication-process).

#####`password`
Plain-text user password (will be hashed)

#####`roles`
Array with user roles. Default: ['dbAdmin']

### Providers

#### Provider: mongodb_database
'mongodb_database' can be used to create and manage databases within MongoDB.

```puppet
mongodb_database { testdb:
  ensure   => present,
  tries    => 10,
  require  => Class['mongodb::server'],
}
```
#####`tries`
The maximum amount of two second tries to wait MongoDB startup. Default: 10


#### Provider: mongodb_user
'mongodb_user' can be used to create and manage users within MongoDB database.

```puppet
mongodb_user { testuser:
  ensure        => present,
  password_hash => mongodb_password('testuser', 'p@ssw0rd'),
  database      => testdb,
  roles         => ['readWrite', 'dbAdmin'],
  tries         => 10,
  require       => Class['mongodb::server'],
}
```
#####`password_hash`
Hex encoded md5 hash of "$username:mongo:$password".

#####`database`
Name of database. It will be created, if not exists.

#####`roles`
Array with user roles. Default: ['dbAdmin']

#####`tries`
The maximum amount of two second tries to wait MongoDB startup. Default: 10

#### Provider: mongodb_replset
'mongodb_replset' can be used to create and manage MongoDB replicasets.

```puppet
mongodb_replset { rsmain:
  ensure  => present,
  members => ['host1:27017', 'host2:27017', 'host3:27017']
}
```

Ideally the ```mongodb_replset``` resource will be declared on the initial
desired primary node (arbitrarily the first of the list) and this node will be
processed once the secondary nodes are up. This will ensure all the nodes are
in the first configuration of the replicaset, else it will require running
puppet again to add them.

#####`members`
Array of 'host:port' of the replicaset members.

It currently only adds members without options.

## Limitation

This module has been tested on:

* Debian 7.* (Wheezy)
* Debian 6.* (squeeze)
* Ubuntu 12.04.2 (precise)
* Ubuntu 10.04.4 LTS (lucid)
* RHEL 5/6
* CentOS 5/6

For a full list of tested operating systems please have a look at the [.nodeset.xml](https://github.com/puppetlabs/puppetlabs-mongodb/blob/master/.nodeset.yml) definition.

This module should support `service_ensure` separate from the `ensure` value on `Class[mongodb::server]` but it does not yet.

## Development

Puppet Labs modules on the Puppet Forge are open projects, and community
contributions are essential for keeping them great. We can’t access the
huge number of platforms and myriad of hardware, software, and deployment
configurations that Puppet is intended to serve.

We want to keep it as easy as possible to contribute changes so that our
modules work in your environment. There are a few guidelines that we need
contributors to follow so that we can have a chance of keeping on top of things.

You can read the complete module contribution guide [on the Puppet Labs wiki.](http://projects.puppetlabs.com/projects/module-site/wiki/Module_contributing)

### Testing

There are two types of tests distributed with this module. Unit tests with
rspec-puppet and system tests using rspec-system.


unit tests should be run under Bundler with the gem versions as specified
in the Gemfile. To install the necessary gems:

    bundle install --path=vendor

Test setup and teardown is handled with rake tasks, so the
supported way of running tests is with

    bundle exec rake spec


For system test you will also need to install vagrant > 1.3.x and virtualbox > 4.2.10.
To run the system tests

    bundle exec rake spec:system

To run the tests on different operating systems, see the sets available in [.nodeset.xml](https://github.com/puppetlabs/puppetlabs-mongodb/blob/master/.nodeset.yml)
and run the specific set with the following syntax:

    RSPEC_SET=ubuntu-server-12042-x64 bundle exec rake spec:system

### Authors

We would like to thank everyone who has contributed issues and pull requests to this module.
A complete list of contributors can be found on the
[GitHub Contributor Graph](https://github.com/puppetlabs/puppetlabs-mongodb/graphs/contributors)
for the [puppetlabs-mongodb module](https://github.com/puppetlabs/puppetlabs-mongodb).
require 'puppetlabs_spec_helper/rake_tasks'
require 'digest/md5'

module Puppet::Parser::Functions
  newfunction(:mongodb_password, :type => :rvalue, :doc => <<-EOS
    Returns the mongodb password hash from the clear text password.
    EOS
  ) do |args|

    raise(Puppet::ParseError, 'mongodb_password(): Wrong number of arguments ' +
      "given (#{args.size} for 2)") if args.size != 2

    Digest::MD5.hexdigest("#{args[0]}:mongo:#{args[1]}")
  end
end
Puppet::Type.type(:mongodb_database).provide(:mongodb) do

  desc "Manages MongoDB database."

  defaultfor :kernel => 'Linux'

  commands :mongo => 'mongo'

  def block_until_mongodb(tries = 10)
    begin
      mongo('--quiet', '--eval', 'db.getMongo()')
    rescue => e
      debug('MongoDB server not ready, retrying')
      sleep 2
      if (tries -= 1) > 0
        retry
      else
        raise e
      end
    end
  end

  def create
    mongo(@resource[:name], '--quiet', '--eval', "db.dummyData.insert({\"created_by_puppet\": 1})")
  end

  def destroy
    mongo(@resource[:name], '--quiet', '--eval', 'db.dropDatabase()')
  end

  def exists?
    block_until_mongodb(@resource[:tries])
    mongo("--quiet", "--eval", 'db.getMongo().getDBNames()').split(",").include?(@resource[:name])
  end

end
#
# Author: François Charlier <francois.charlier@enovance.com>
#

Puppet::Type.type(:mongodb_replset).provide(:mongo) do

  desc "Manage hosts members for a replicaset."

  confine :true =>
    begin
      require 'json'
      true
    rescue LoadError
      false
    end

  commands :mongo => 'mongo'

  mk_resource_methods

  def initialize(resource={})
    super(resource)
    @property_flush = {}
  end

  def members=(hosts)
    @property_flush[:members] = hosts
  end

  def self.instances
    instance = get_replset_properties
    if instance
      # There can only be one replset per node
      [new(instance)]
    else
      []
    end
  end

  def self.prefetch(resources)
    instances.each do |prov|
      if resource = resources[prov.name]
        resource.provider = prov
      end
    end
  end

  def exists?
    @property_hash[:ensure] == :present
  end

  def create
    @property_flush[:ensure] = :present
    @property_flush[:members] = resource.should(:members)
  end

  def destroy
    @property_flush[:ensure] = :absent
  end

  def flush
    set_members
    @property_hash = self.class.get_replset_properties
  end

  private

  def db_ismaster(host)
    mongo_command("db.isMaster()", host)
  end

  def rs_initiate(conf, master)
    return mongo_command("rs.initiate(#{conf})", master)
  end

  def rs_status(host)
    mongo_command("rs.status()", host)
  end

  def rs_add(host, master)
    mongo_command("rs.add(\"#{host}\")", master)
  end

  def rs_remove(host, master)
    mongo_command("rs.remove(\"#{host}\")", master)
  end

  def master_host(hosts)
    hosts.each do |host|
      status = db_ismaster(host)
      if status.has_key?('primary')
        return status['primary']
      end
    end
    false
  end

  def self.get_replset_properties
    output = mongo_command('rs.conf()')
    if output['members']
      members = output['members'].collect do |val|
        val['host']
      end
      props = {
        :name     => output['_id'],
        :ensure   => :present,
        :members  => members,
        :provider => :mongo,
      }
    else
      props = nil
    end
    Puppet.debug("MongoDB replset properties: #{props.inspect}")
    props
  end

  def alive_members(hosts)
    hosts.select do |host|
      begin
        Puppet.debug "Checking replicaset member #{host} ..."
        status = rs_status(host)
        if status.has_key?('errmsg') and status['errmsg'] == 'not running with --replSet'
          raise Puppet::Error, "Can't configure replicaset #{self.name}, host #{host} is not supposed to be part of a replicaset."
        end
        if status.has_key?('set')
          if status['set'] != self.name
            raise Puppet::Error, "Can't configure replicaset #{self.name}, host #{host} is already part of another replicaset."
          end

          # This node is alive and supposed to be a member of our set
          Puppet.debug "Host #{self.name} is available for replset #{status['set']}"
          true
        elsif status.has_key?('info')
          Puppet.debug "Host #{self.name} is alive but unconfigured: #{status['info']}"
          true
        end
      rescue Puppet::ExecutionFailure
        Puppet.warning "Can't connect to replicaset member #{host}."

        false
      end
    end
  end

  def set_members
    if @property_flush[:ensure] == :absent
      # TODO: I don't know how to remove a node from a replset; unimplemented
      #Puppet.debug "Removing all members from replset #{self.name}"
      #@property_hash[:members].collect do |member|
      #  rs_remove(member, master_host(@property_hash[:members]))
      #end
      return
    end

    if ! @property_flush[:members].empty?
      # Find the alive members so we don't try to add dead members to the replset
      alive_hosts = alive_members(@property_flush[:members])
      dead_hosts  = @property_flush[:members] - alive_hosts
      raise Puppet::Error, "Can't connect to any member of replicaset #{self.name}." if alive_hosts.empty?
      Puppet.debug "Alive members: #{alive_hosts.inspect}"
      Puppet.debug "Dead members: #{dead_hosts.inspect}" unless dead_hosts.empty?
    else
      alive_hosts = []
    end

    if @property_flush[:ensure] == :present and @property_hash[:ensure] != :present
      Puppet.debug "Initializing the replset #{self.name}"

      # Create a replset configuration
      hostconf = alive_hosts.each_with_index.map do |host,id|
        "{ _id: #{id}, host: \"#{host}\" }"
      end.join(',')
      conf = "{ _id: \"#{self.name}\", members: [ #{hostconf} ] }"

      # Set replset members with the first host as the master
      output = rs_initiate(conf, alive_hosts[0])
      if output['ok'] == 0
        raise Puppet::Error, "rs.initiate() failed for replicaset #{self.name}: #{output['errmsg']}"
      end
    else
      # Add members to an existing replset
      if master = master_host(alive_hosts)
        current_hosts = db_ismaster(master)['hosts']
        newhosts = alive_hosts - current_hosts
        newhosts.each do |host|
          output = rs_add(host, master)
          if output['ok'] == 0
            raise Puppet::Error, "rs.add() failed to add host to replicaset #{self.name}: #{output['errmsg']}"
          end
        end
      else
        raise Puppet::Error, "Can't find master host for replicaset #{self.name}."
      end
    end
  end

  def mongo_command(command, host, retries=4)
    self.class.mongo_command(command,host,retries)
  end

  def self.mongo_command(command, host=nil, retries=4)
    # Allow waiting for mongod to become ready
    # Wait for 2 seconds initially and double the delay at each retry
    wait = 2
    begin
      args = Array.new
      args << '--quiet'
      args << ['--host',host] if host
      args << ['--eval',"printjson(#{command})"]
      output = mongo(args.flatten)
    rescue Puppet::ExecutionFailure => e
      if e =~ /Error: couldn't connect to server/ and wait <= 2**max_wait
        info("Waiting #{wait} seconds for mongod to become available")
        sleep wait
        wait *= 2
        retry
      else
        raise
      end
    end

    # Dirty hack to remove JavaScript objects
    output.gsub!(/ISODate\((.+?)\)/, '\1 ')
    output.gsub!(/Timestamp\((.+?)\)/, '[\1]')

    #Hack to avoid non-json empty sets
    output = "{}" if output == "null\n"

    JSON.parse(output)
  end

end
Puppet::Type.type(:mongodb_user).provide(:mongodb) do

  desc "Manage users for a MongoDB database."

  defaultfor :kernel => 'Linux'

  commands :mongo => 'mongo'

  def block_until_mongodb(tries = 10)
    begin
      mongo('--quiet', '--eval', 'db.getMongo()')
    rescue
      debug('MongoDB server not ready, retrying')
      sleep 2
      retry unless (tries -= 1) <= 0
    end
  end

  def create
    mongo(@resource[:database], '--eval', "db.system.users.insert({user:\"#{@resource[:name]}\", pwd:\"#{@resource[:password_hash]}\", roles: #{@resource[:roles].inspect}})")
  end

  def destroy
    mongo(@resource[:database], '--quiet', '--eval', "db.removeUser(\"#{@resource[:name]}\")")
  end

  def exists?
    block_until_mongodb(@resource[:tries])
    mongo(@resource[:database], '--quiet', '--eval', "db.system.users.find({user:\"#{@resource[:name]}\"}).count()").strip.eql?('1')
  end

  def password_hash
    mongo(@resource[:database], '--quiet', '--eval', "db.system.users.findOne({user:\"#{@resource[:name]}\"})[\"pwd\"]").strip
  end

  def password_hash=(value)
    mongo(@resource[:database], '--quiet', '--eval', "db.system.users.update({user:\"#{@resource[:name]}\"}, { $set: {pwd:\"#{value}\"}})")
  end

  def roles
    mongo(@resource[:database], '--quiet', '--eval', "db.system.users.findOne({user:\"#{@resource[:name]}\"})[\"roles\"]").strip.split(",").sort
  end

  def roles=(value)
    mongo(@resource[:database], '--quiet', '--eval', "db.system.users.update({user:\"#{@resource[:name]}\"}, { $set: {roles: #{@resource[:roles].inspect}}})")
  end

end
Puppet::Type.newtype(:mongodb_database) do
  @doc = "Manage MongoDB databases."

  ensurable

  newparam(:name, :namevar=>true) do
    desc "The name of the database."
    newvalues(/^\w+$/)
  end

  newparam(:tries) do
    desc "The maximum amount of two second tries to wait MongoDB startup."
    defaultto 10
    newvalues(/^\d+$/)
    munge do |value|
      Integer(value)
    end
  end

  autorequire(:package) do
    'mongodb'
  end

  autorequire(:service) do
    'mongodb'
  end
end
#
# Author: François Charlier <francois.charlier@enovance.com>
#

Puppet::Type.newtype(:mongodb_replset) do
  @doc = "Manage a MongoDB replicaSet"

  ensurable do
    defaultto :present

    newvalue(:present) do
      provider.create
    end
  end

  newparam(:name) do
    desc "The name of the replicaSet"
  end

  newproperty(:members, :array_matching => :all) do
    desc "The replicaSet members"

    def insync?(is)
      is.sort == should.sort
    end
  end

  autorequire(:package) do
    'mongodb'
  end

  autorequire(:service) do
    'mongodb'
  end
end
Puppet::Type.newtype(:mongodb_user) do
  @doc = 'Manage a MongoDB user. This includes management of users password as well as privileges.'

  ensurable

  def initialize(*args)
    super
    # Sort roles array before comparison.
    self[:roles] = Array(self[:roles]).sort!
  end

  newparam(:name, :namevar=>true) do
    desc "The name of the user."
  end

  newparam(:database) do
    desc "The user's target database."
    defaultto do
      fail("Parameter 'database' must be set")
    end
    newvalues(/^\w+$/)
  end

  newparam(:tries) do
    desc "The maximum amount of two second tries to wait MongoDB startup."
    defaultto 10
    newvalues(/^\d+$/)
    munge do |value|
      Integer(value)
    end
  end

  newproperty(:roles, :array_matching => :all) do
    desc "The user's roles."
    defaultto ['dbAdmin']
    newvalue(/^\w+$/)

    # Pretty output for arrays.
    def should_to_s(value)
      value.inspect
    end

    def is_to_s(value)
      value.inspect
    end
  end

  newproperty(:password_hash) do
    desc "The password hash of the user. Use mongodb_password() for creating hash."
    defaultto do
      fail("Property 'password_hash' must be set. Use mongodb_password() for creating hash.")
    end
    newvalue(/^\w+$/)
  end

  autorequire(:package) do
    'mongodb'
  end

  autorequire(:service) do
    'mongodb'
  end
end
# Class for installing a MongoDB client shell (CLI).
#
# == Parameters
#
# [ensure] Desired ensure state of the package. Optional.
#   Defaults to 'true'
#
# [package_name] Name of the package to install the client from. Default
#   is repository dependent.
#
class mongodb::client (
  $ensure       = $mongodb::params::ensure_client,
  $package_name = $mongodb::params::client_package_name,
) inherits mongodb::params {
  case $::osfamily {
    'RedHat', 'Linux': {
      class { 'mongodb::client::install': }
    }
    'Debian': {
      warning ('Debian client is included by default with server. Please use ::mongodb::server to install the mongo client for Debian family systems.')
    }
    default: {
      # no action taken, failure happens in params.pp
    }
  }
}
# PRIVATE CLASS: do not call directly
class mongodb::client::install {
  $package_ensure = $mongodb::client::ensure
  $package_name   = $mongodb::client::package_name

  case $package_ensure {
    true:     {
      $my_package_ensure = 'present'
    }
    false:    {
      $my_package_ensure = 'purged'
    }
    'absent': {
      $my_package_ensure = 'purged'
    }
    default:  {
      $my_package_ensure = $package_ensure
    }
  }

  package { 'mongodb_client':
    ensure  => $my_package_ensure,
    name    => $package_name,
    tag     => 'mongodb',
  }
}
# == Class: mongodb::db
#
# Class for creating mongodb databases and users.
#
# == Parameters
#
#  user - Database username.
#  password_hash - Hashed password. Hex encoded md5 hash of "$username:mongo:$password".
#  password - Plain text user password. This is UNSAFE, use 'password_hash' unstead.
#  roles (default: ['dbAdmin']) - array with user roles.
#  tries (default: 10) - The maximum amount of two second tries to wait MongoDB startup.
#
define mongodb::db (
  $user,
  $password_hash = false,
  $password      = false,
  $roles         = ['dbAdmin'],
  $tries         = 10,
) {

  mongodb_database { $name:
    ensure   => present,
    tries    => $tries,
    require  => Class['mongodb::server'],
  }

  if $password_hash {
    $hash = $password_hash
  } elsif $password {
    $hash = mongodb_password($user, $password)
  } else {
    fail("Parameter 'password_hash' or 'password' should be provided to mongodb::db.")
  }

  mongodb_user { $user:
    ensure        => present,
    password_hash => $hash,
    database      => $name,
    roles         => $roles,
    require       => Mongodb_database[$name],
  }

}
# Class for setting cross-class global overrides. See README.md for more
# details.

class mongodb::globals (
  $server_package_name  = undef,
  $client_package_name  = undef,

  $service_name         = undef,
  $service_provider     = undef,
  $service_status       = undef,

  $user                 = undef,
  $group                = undef,
  $bind_ip              = undef,

  $version              = undef,

  $manage_package_repo  = undef,
) {

  # Setup of the repo only makes sense globally, so we are doing it here.
  if($manage_package_repo) {
    class { '::mongodb::repo':
      ensure  => present,
    }
  }
}
# == Class: mongodb
#
# Direct use of this class is deprecated. Please use mongodb::server
#
# Manage mongodb installations on RHEL, CentOS, Debian and Ubuntu - either
# installing from the 10Gen repo or from EPEL in the case of EL systems.
#
# === Parameters
#
# enable_10gen (default: false) - Whether or not to set up 10gen software repositories
# init (auto discovered) - override init (sysv or upstart) for Debian derivatives
# location - override apt location configuration for Debian derivatives
# packagename (auto discovered) - override the package name
# servicename (auto discovered) - override the service name
# service-enable (default: true) - Enable the service and ensure it is running
#
# === Examples
#
# To install with defaults from the distribution packages on any system:
#   include mongodb
#
# To install from 10gen on a EL server
#   class { 'mongodb':
#     enable_10gen => true,
#   }
#
# === Authors
#
# Craig Dunn <craig@craigdunn.org>
#
# === Copyright
#
# Copyright 2013 PuppetLabs
#

class mongodb (
  # Deprecated parameters
  $enable_10gen    = undef,

  $init            = $mongodb::params::service_provider,
  $location        = '',
  $packagename     = undef,
  $version         = undef,
  $servicename     = $mongodb::params::service_name,
  $service_enable  = true, #deprecated
  $logpath         = $mongodb::params::logpath,
  $logappend       = true,
  $fork            = $mongodb::params::fork,
  $port            = 27017,
  $dbpath          = $mongodb::params::dbpath,
  $journal         = undef,
  $nojournal       = undef,
  $smallfiles      = undef,
  $cpu             = undef,
  $noauth          = undef,
  $auth            = undef,
  $verbose         = undef,
  $objcheck        = undef,
  $quota           = undef,
  $oplog           = undef, #deprecated it's on if replica set
  $oplog_size      = undef,
  $nohints         = undef,
  $nohttpinterface = undef,
  $noscripting     = undef,
  $notablescan     = undef,
  $noprealloc      = undef,
  $nssize          = undef,
  $mms_token       = undef,
  $mms_name        = undef,
  $mms_interval    = undef,
  $slave           = undef,
  $only            = undef,
  $master          = undef,
  $source          = undef,
  $replset         = undef,
  $rest            = undef,
  $slowms          = undef,
  $keyfile         = undef,
  $bind_ip         = undef,
  $pidfilepath     = undef
) inherits mongodb::params {

  if $enable_10gen {
    fail("Parameter enable_10gen is no longer supported. Please use class { 'mongodb::globals': manage_package_repo => true }")
  }

  if $version {
    fail("Parameter version is no longer supported. Please use class { 'mongodb::globals': version => VERSION }")
  }

  if $oplog {
    fail('Parameter is no longer supported. On replica set Oplog is enabled by default.')
  }

  notify { 'An attempt has been made below to automatically apply your custom
    settings to mongodb::server. Please verify this works in a safe test
    environment.': }

  class { 'mongodb::server':
    package_name    => $packagename,
    logpath         => $logpath,
    logappend       => $logappend,
    fork            => $fork,
    port            => $port,
    dbpath          => $dbpath,
    journal         => $journal,
    nojournal       => $nojournal,
    smallfiles      => $smallfiles,
    cpu             => $cpu,
    noauth          => $noauth,
    verbose         => $verbose,
    objcheck        => $objcheck,
    quota           => $quota,
    oplog_size      => $oplog_size,
    nohints         => $nohints,
    nohttpinterface => $nohttpinterface,
    noscripting     => $noscripting,
    notablescan     => $notablescan,
    noprealloc      => $noprealloc,
    nssize          => $nssize,
    mms_token       => $mms_token,
    mms_name        => $mms_name,
    mms_interval    => $mms_interval,
    slave           => $slave,
    only            => $only,
    master          => $master,
    source          => $source,
    replset         => $replset,
    rest            => $rest,
    slowms          => $slowms,
    keyfile         => $keyfile,
    bind_ip         => $bind_ip,
    pidfilepath     => $pidfilepath,
  }

}
# PRIVATE CLASS: do not use directly
class mongodb::params inherits mongodb::globals {
  $ensure           = true
  $service_status   = $service_status
  $ensure_client    = true

  # Amazon Linux's OS Family is 'Linux', operating system 'Amazon'.
  case $::osfamily {
    'RedHat', 'Linux': {

      if $mongodb::globals::manage_package_repo {
        $user        = pick($user, 'mongod')
        $group       = pick($group, 'mongod')
        if $::mongodb::globals::version {
          $server_package_name = "mongodb-org-server-${::mongodb::globals::version}"
          $client_package_name = "mongodb-org-${::mongodb::globals::version}"
        } else {
          $server_package_name = 'mongodb-org-server'
          $client_package_name = 'mongodb-org'
        }
        $service_name = pick($service_name, 'mongod')
        $config      = '/etc/mongod.conf'
        $dbpath      = '/var/lib/mongo'
        $logpath     = '/var/log/mongodb/mongod.log'
        $pidfilepath = '/var/run/mongodb/mongod.pid'
        $bind_ip     = pick($bind_ip, ['127.0.0.1'])
        $fork        = true
      } else {
        # RedHat/CentOS doesn't come with a prepacked mongodb
        # so we assume that you are using EPEL repository.
        $user                = pick($user, 'mongodb')
        $group               = pick($group, 'mongodb')
        $server_package_name = pick($server_package_name, 'mongodb-server')
        $client_package_name = pick($client_package_name, 'mongodb')

        $service_name        = pick($service_name, 'mongod')
        $config              = '/etc/mongodb.conf'
        $dbpath              = '/var/lib/mongodb'
        $logpath             = '/var/log/mongodb/mongodb.log'
        $bind_ip             = pick($bind_ip, ['127.0.0.1'])
        $pidfilepath         = '/var/run/mongodb/mongodb.pid'
        $fork                = true
        $journal             = true
      }
    }
    'Debian': {
      if $mongodb::globals::manage_package_repo {
        $user  = pick($user, 'mongodb')
        $group = pick($group, 'mongodb')
        if $::mongodb::globals::version {
          $server_package_name = "mongodb-10gen=${::mongodb::globals::version}"
        } else {
          $server_package_name = 'mongodb-10gen'
        }
        $service_name = 'mongodb'
        $config       = '/etc/mongodb.conf'
        $dbpath       = '/var/lib/mongodb'
        $logpath      = '/var/log/mongodb/mongodb.log'
        $bind_ip      = ['127.0.0.1']
      } else {
        # although we are living in a free world,
        # I would not recommend to use the prepacked
        # mongodb server on Ubuntu 12.04 or Debian 6/7,
        # because its really outdated
        $user                = pick($user, 'mongodb')
        $group               = pick($group, 'mongodb')
        $server_package_name = pick($server_package_name, 'mongodb-server')
        $client_package_name = pick($client_package_name, 'mongodb')
        $service_name        = pick($service_name, 'mongodb')
        $config              = '/etc/mongodb.conf'
        $dbpath              = '/var/lib/mongodb'
        $logpath             = '/var/log/mongodb/mongodb.log'
        $bind_ip             = pick($bind_ip, ['127.0.0.1'])
        $pidfilepath         = undef
      }
      # avoid using fork because of the init scripts design
      $fork = undef
    }
    default: {
      fail("Osfamily ${::osfamily} and ${::operatingsystem} is not supported")
    }
  }

  case $::operatingsystem {
    'Ubuntu': {
      $service_provider = pick($service_provider, 'upstart')
    }
    default: {
      $service_provider = undef
    }
  }

}
# Wrapper class useful for hiera based deployments

class mongodb::replset(
  $sets = undef
) {

  if $sets {
    create_resources(mongodb_replset, $sets)
  }
}
# PRIVATE CLASS: do not use directly
class mongodb::repo (
  $ensure  = $mongodb::params::ensure,
) inherits mongodb::params {
  case $::osfamily {
    'RedHat', 'Linux': {
      $location = $::architecture ? {
        'x86_64' => 'http://downloads-distro.mongodb.org/repo/redhat/os/x86_64/',
        'i686'   => 'http://downloads-distro.mongodb.org/repo/redhat/os/i686/',
        'i386'   => 'http://downloads-distro.mongodb.org/repo/redhat/os/i686/',
        default  => undef
      }
      class { 'mongodb::repo::yum': }
    }

    'Debian': {
      $location = $::operatingsystem ? {
        'Debian' => 'http://downloads-distro.mongodb.org/repo/debian-sysvinit',
        'Ubuntu' => 'http://downloads-distro.mongodb.org/repo/ubuntu-upstart',
        default  => undef
      }
      class { 'mongodb::repo::apt': }
    }

    default: {
      if($ensure == 'present' or $ensure == true) {
        fail("Unsupported managed repository for osfamily: ${::osfamily}, operatingsystem: ${::operatingsystem}, module ${module_name} currently only supports managing repos for osfamily RedHat, Debian and Ubuntu")
      }
    }
  }
}
# PRIVATE CLASS: do not use directly
class mongodb::repo::apt inherits mongodb::repo {
  # we try to follow/reproduce the instruction
  # from http://docs.mongodb.org/manual/tutorial/install-mongodb-on-ubuntu/

  include ::apt

  if($::mongodb::repo::ensure == 'present' or $::mongodb::repo::ensure == true) {
    apt::source { 'downloads-distro.mongodb.org':
      location    => $::mongodb::repo::location,
      release     => 'dist',
      repos       => '10gen',
      key         => '9ECBEC467F0CEB10',
      key_server  => 'keyserver.ubuntu.com',
      include_src => false,
    }

    Apt::Source['downloads-distro.mongodb.org']->Package<|tag == 'mongodb'|>
  }
  else {
    apt::source { 'downloads-distro.mongodb.org':
      ensure => absent,
    }
  }
}
# PRIVATE CLASS: do not use directly
class mongodb::repo::yum inherits mongodb::repo {
  # We try to follow/reproduce the instruction
  # http://docs.mongodb.org/manual/tutorial/install-mongodb-on-red-hat-centos-or-fedora-linux/

  if($::mongodb::repo::ensure == 'present' or $::mongodb::repo::ensure == true) {
    yumrepo { 'mongodb':
      descr    => 'MongoDB/10gen Repository',
      baseurl  => $::mongodb::repo::location,
      gpgcheck => '0',
      enabled  => '1',
    }
    Yumrepo['mongodb'] -> Package<|tag == 'mongodb'|>
  }
  else {
    yumrepo { 'mongodb':
      enabled => absent,
    }
  }
}
# This installs a MongoDB server. See README.md for more details.
class mongodb::server (
  $ensure           = $mongodb::params::ensure,

  $user             = $mongodb::params::user,
  $group            = $mongodb::params::group,

  $config           = $mongodb::params::config,
  $dbpath           = $mongodb::params::dbpath,
  $pidfilepath      = $mongodb::params::pidfilepath,

  $service_provider = $mongodb::params::service_provider,
  $service_name     = $mongodb::params::service_name,
  $service_status   = $mongodb::params::service_status,

  $package_ensure  = $ensure,
  $package_name    = $mongodb::params::server_package_name,

  $logpath         = $mongodb::params::logpath,
  $bind_ip         = $mongodb::params::bind_ip,
  $logappend       = true,
  $fork            = $mongodb::params::fork,
  $port            = 27017,
  $journal         = $mongodb::params::journal,
  $nojournal       = undef,
  $smallfiles      = undef,
  $cpu             = undef,
  $auth            = false,
  $noauth          = undef,
  $verbose         = undef,
  $verbositylevel  = undef,
  $objcheck        = undef,
  $quota           = undef,
  $quotafiles      = undef,
  $diaglog         = undef,
  $directoryperdb  = undef,
  $profile         = undef,
  $maxconns        = undef,
  $oplog_size      = undef,
  $nohints         = undef,
  $nohttpinterface = undef,
  $noscripting     = undef,
  $notablescan     = undef,
  $noprealloc      = undef,
  $nssize          = undef,
  $mms_token       = undef,
  $mms_name        = undef,
  $mms_interval    = undef,
  $replset         = undef,
  $rest            = undef,
  $slowms          = undef,
  $keyfile         = undef,
  $set_parameter   = undef,
  $syslog          = undef,

  # Deprecated parameters
  $master          = undef,
  $slave           = undef,
  $only            = undef,
  $source          = undef,
) inherits mongodb::params {


  if ($ensure == 'present' or $ensure == true) {
    anchor { 'mongodb::server::start': }->
    class { 'mongodb::server::install': }->
    class { 'mongodb::server::config': }->
    class { 'mongodb::server::service': }->
    anchor { 'mongodb::server::end': }
  } else {
    anchor { 'mongodb::server::start': }->
    class { 'mongodb::server::service': }->
    class { 'mongodb::server::config': }->
    class { 'mongodb::server::install': }->
    anchor { 'mongodb::server::end': }
  }
}
# PRIVATE CLASS: do not call directly
class mongodb::server::config {
  $ensure          = $mongodb::server::ensure
  $user            = $mongodb::server::user
  $group           = $mongodb::server::group
  $config          = $mongodb::server::config

  $dbpath          = $mongodb::server::dbpath
  $pidfilepath     = $mongodb::server::pidfilepath
  $logpath         = $mongodb::server::logpath
  $logappend       = $mongodb::server::logappend
  $fork            = $mongodb::server::fork
  $port            = $mongodb::server::port
  $journal         = $mongodb::server::journal
  $nojournal       = $mongodb::server::nojournal
  $smallfiles      = $mongodb::server::smallfiles
  $cpu             = $mongodb::server::cpu
  $auth            = $mongodb::server::auth
  $noath           = $mongodb::server::noauth
  $verbose         = $mongodb::server::verbose
  $verbositylevel  = $mongodb::server::verbositylevel
  $objcheck        = $mongodb::server::objcheck
  $quota           = $mongodb::server::quota
  $quotafiles      = $mongodb::server::quotafiles
  $diaglog         = $mongodb::server::diaglog
  $oplog_size      = $mongodb::server::oplog_size
  $nohints         = $mongodb::server::nohints
  $nohttpinterface = $mongodb::server::nohttpinterface
  $noscripting     = $mongodb::server::noscripting
  $notablescan     = $mongodb::server::notablescan
  $noprealloc      = $mongodb::server::noprealloc
  $nssize          = $mongodb::server::nssize
  $mms_token       = $mongodb::server::mms_token
  $mms_name        = $mongodb::server::mms_name
  $mms_interval    = $mongodb::server::mms_interval
  $master          = $mongodb::server::master
  $slave           = $mongodb::server::slave
  $only            = $mongodb::server::only
  $source          = $mongodb::server::source
  $replset         = $mongodb::server::replset
  $rest            = $mongodb::server::rest
  $slowms          = $mongodb::server::slowms
  $keyfile         = $mongodb::server::keyfile
  $bind_ip         = $mongodb::server::bind_ip
  $directoryperdb  = $mongodb::server::directoryperdb
  $profile         = $mongodb::server::profile
  $set_parameter   = $mongodb::server::set_parameter
  $syslog          = $mongodb::server::syslog

  File {
    owner => $user,
    group => $group,
  }

  if ($logpath and $syslog) { fail('You cannot use syslog with logpath')}

  if ($ensure == 'present' or $ensure == true) {

    # Exists for future compatibility and clarity.
    if $auth {
      $noauth = false
    }
    else {
      $noauth = true
    }

    file { $config:
      content => template('mongodb/mongodb.conf.erb'),
      owner   => 'root',
      group   => 'root',
      mode    => '0644',
      notify  => Class['mongodb::server::service']
    }

    file { $dbpath:
      ensure  => directory,
      mode    => '0755',
      owner   => $user,
      group   => $group,
      require => File[$config]
    }
  } else {
    file { $dbpath:
      ensure => absent,
      force  => true,
      backup => false,
    }
    file { $config:
      ensure => absent
    }
  }
}
# PRIVATE CLASS: do not call directly
class mongodb::server::install {
  $package_ensure = $mongodb::server::package_ensure
  $package_name   = $mongodb::server::package_name

  case $package_ensure {
    true:     {
      $my_package_ensure = 'present'
      $file_ensure     = 'directory'
    }
    false:    {
      $my_package_ensure = 'absent'
      $file_ensure     = 'absent'
    }
    'absent': {
      $my_package_ensure = 'absent'
      $file_ensure     = 'absent'
    }
    'purged': {
      $my_package_ensure = 'purged'
      $file_ensure     = 'absent'
    }
    default:  {
      $my_package_ensure = $package_ensure
      $file_ensure     = 'present'
    }
  }

  package { 'mongodb_server':
    ensure  => $my_package_ensure,
    name    => $package_name,
    tag     => 'mongodb',
  }
}
# PRIVATE CLASS: do not call directly
class mongodb::server::service {
  $ensure           = $mongodb::server::ensure
  $service_name     = $mongodb::server::service_name
  $service_provider = $mongodb::server::service_provider
  $service_status   = $mongodb::server::service_status

  $service_ensure = $ensure ? {
    present => true,
    absent  => false,
    purged  => false,
    default => $ensure
  }

  service { 'mongodb':
    ensure    => $service_ensure,
    name      => $service_name,
    enable    => $service_ensure,
    provider  => $service_provider,
    hasstatus => true,
    status    => $service_status,
  }
}
HOSTS:
  'master':
    roles:
      - master
    platform: el-6-x86_64
    hypervisor: vcloud
    template: centos-6-x86_64
  'slave':
    roles:
      - slave
    platform: el-6-x86_64
    hypervisor: vcloud
    template: centos-6-x86_64
CONFIG:
  type: foss
  ssh:
    keys: "~/.ssh/id_rsa-acceptance"
  datastore: instance0
  folder: Delivery/Quality Assurance/Enterprise/Dynamic
  resourcepool: delivery/Quality Assurance/Enterprise/Dynamic
  pooling_api: http://vcloud.delivery.puppetlabs.net/
HOSTS:
  centos-64-x64:
    roles:
      - master
      - database
      - dashboard
    platform: el-6-x86_64
    box : centos-64-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: pe
HOSTS:
  centos-64-x64:
    roles:
      - master
    platform: el-6-x86_64
    box : centos-64-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: foss
HOSTS:
  centos-65-x64:
    roles:
      - master
    platform: el-6-x86_64
    box : centos-65-x64-vbox436-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-65-x64-virtualbox-nocm.box
    hypervisor : vagrant
CONFIG:
  type: foss
HOSTS:
  fedora-18-x64:
    roles:
      - master
    platform: fedora-18-x86_64
    box : fedora-18-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/fedora-18-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: foss
HOSTS:
  'master':
    roles:
      - master
    platform: el-6-x86_64
    hypervisor: vcloud
    template: centos-6-x86_64
  'slave':
    roles:
      - slave
    platform: el-6-x86_64
    hypervisor: vcloud
    template: centos-6-x86_64
CONFIG:
  type: foss
  ssh:
    keys: "~/.ssh/id_rsa-acceptance"
  datastore: instance0
  folder: Delivery/Quality Assurance/Enterprise/Dynamic
  resourcepool: delivery/Quality Assurance/Enterprise/Dynamic
  pooling_api: http://vcloud.delivery.puppetlabs.net/
HOSTS:
  centos-64-x64:
    roles:
      - master
    platform: el-6-x86_64
    box : centos-64-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: foss
HOSTS:
  sles-11-x64.local:
    roles:
      - master
    platform: sles-11-x64
    box : sles-11sp1-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/sles-11sp1-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
    type: foss
HOSTS:
  ubuntu-server-10044-x64:
    roles:
      - master
    platform: ubuntu-10.04-amd64
    box : ubuntu-server-10044-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/ubuntu-server-10044-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: foss
HOSTS:
  ubuntu-server-12042-x64:
    roles:
      - master
    platform: ubuntu-12.04-amd64
    box : ubuntu-server-12042-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/ubuntu-server-12042-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: foss
require 'spec_helper_acceptance'

if hosts.length > 1
  describe 'mongodb_replset resource' do
    after :all do
      # Have to drop the DB to disable replsets for further testing
      on hosts, %{mongo local --verbose --eval 'db.dropDatabase()'}

      pp = <<-EOS
        class { 'mongodb::globals': }
        -> class { 'mongodb::server':
          ensure => purged,
        }
        if $::osfamily == 'RedHat' {
          class { 'mongodb::client': }
        }
      EOS

      apply_manifest_on(hosts.reverse, pp, :catch_failures => true)
    end

    it 'configures mongo on both nodes' do
      pp = <<-EOS
        class { 'mongodb::globals': }
        -> class { 'mongodb::server':
          bind_ip => '0.0.0.0',
          replset => 'test',
        }
        if $::osfamily == 'RedHat' {
          class { 'mongodb::client': }
        }
      EOS

      apply_manifest_on(hosts.reverse, pp, :catch_failures => true)
      apply_manifest_on(hosts.reverse, pp, :catch_changes  => true)
    end

    it 'sets up the replset with puppet' do
      pp = <<-EOS
        mongodb_replset { 'test':
          members => [#{hosts.collect{|x|"'#{x}:27017'"}.join(',')}],
        }
      EOS
      apply_manifest_on(hosts_as('master'), pp, :catch_failures => true)
      on(hosts_as('master'), 'mongo --quiet --eval "printjson(rs.conf())"') do |r|
        expect(r.stdout).to match /#{hosts[0]}:27017/
        expect(r.stdout).to match /#{hosts[1]}:27017/
      end
    end

    it 'inserts data on the master' do
      sleep(30)
      on hosts_as('master'), %{mongo --verbose --eval 'db.test.save({name:"test1",value:"some value"})'}
    end

    it 'checks the data on the master' do
      on hosts_as('master'), %{mongo --verbose --eval 'printjson(db.test.findOne({name:"test1"}))'} do |r|
        expect(r.stdout).to match /some value/
      end
    end

    it 'checks the data on the slave' do
      sleep(10)
      on hosts_as('slave'), %{mongo --verbose --eval 'rs.slaveOk(); printjson(db.test.findOne({name:"test1"}))'} do |r|
        expect(r.stdout).to match /some value/
      end
    end
  end
end
require 'spec_helper_acceptance'

describe 'mongodb::server class' do

  shared_examples 'normal tests' do |tengen|
    if tengen
      case fact('osfamily')
      when 'RedHat'
        package_name = 'mongodb-org-server'
        service_name = 'mongod'
        config_file  = '/etc/mongod.conf'
      when 'Debian'
        package_name = 'mongodbdb-org-10gen'
        service_name = 'mongodb'
        config_file  = '/etc/mongodb.conf'
      end
    else
      case fact('osfamily')
      when 'RedHat'
        package_name = 'mongodb-server'
        service_name = 'mongod'
        config_file  = '/etc/mongodb.conf'
      when 'Debian'
        package_name = 'mongodb-server'
        service_name = 'mongodb'
        config_file  = '/etc/mongodb.conf'
      end
    end

    client_name  = 'mongo --version'

    context "default parameters with 10gen => #{tengen}" do
      after :all do
        if tengen
          puts "XXX uninstalls mongodb because changing the port with tengen doesn't work because they have a crappy init script"
          pp = <<-EOS
            class {'mongodb::globals': manage_package_repo => #{tengen}, }
            -> class { 'mongodb::server': ensure => absent, }
            -> class { 'mongodb::client': ensure => absent, }
          EOS
          apply_manifest(pp, :catch_failures => true)
        end
      end

      it 'should work with no errors' do
        case fact('osfamily')
        when 'RedHat'
          pp = <<-EOS
            class { 'mongodb::globals': manage_package_repo => #{tengen}, }
            -> class { 'mongodb::server': }
            -> class { 'mongodb::client': }
          EOS
        when 'Debian'
          pp = <<-EOS
            class { 'mongodb::globals': manage_package_repo => #{tengen}, }
            -> class { 'mongodb::server': }
          EOS
        end

        apply_manifest(pp, :catch_failures => true)
        apply_manifest(pp, :catch_changes  => true)
      end

      describe package(package_name) do
        it { should be_installed }
      end

      describe file(config_file) do
        it { should be_file }
      end

      describe service(service_name) do
         it { should be_enabled }
         it { should be_running }
      end

      describe port(27017) do
        it do
          sleep(20)
          should be_listening
        end
      end

      describe command(client_name) do
        it do
          should return_exit_status 0
        end
      end
    end

    context "test using custom port and 10gen => #{tengen}" do
      it 'change port to 27018' do
        pp = <<-EOS
          class { 'mongodb::globals': manage_package_repo => #{tengen}, }
          -> class { 'mongodb::server': port => 27018, }
        EOS

        apply_manifest(pp, :catch_failures => true)
        apply_manifest(pp, :catch_changes  => true)
      end

      describe port(27018) do
        sleep(20)
        it { sleep 5 ; should be_listening }
      end
    end

    describe "uninstalling with 10gen => #{tengen}" do
      it 'uninstalls mongodb' do
        pp = <<-EOS
          class {'mongodb::globals': manage_package_repo => #{tengen}, }
          -> class { 'mongodb::server': ensure => absent, }
          -> class { 'mongodb::client': ensure => absent, }
        EOS
        apply_manifest(pp, :catch_failures => true)
      end
    end
  end

  it_behaves_like 'normal tests', false
  it_behaves_like 'normal tests', true
end
require 'spec_helper'

describe 'mongodb::client::install', :type => :class do
  describe 'it should create package' do
    let(:pre_condition) { ["class mongodb::client { $ensure = true $package_name = 'mongodb' }", "include mongodb::client"]}
    it {
      should contain_package('mongodb_client').with({
        :ensure => 'present',
        :name   => 'mongodb',
      })
    }
  end
end
require 'spec_helper'

describe 'mongodb::repo', :type => :class do

  context 'when deploying on Debian' do
    let :facts do
      {
        :osfamily        => 'Debian',
        :operatingsystem => 'Debian',
        :lsbdistid       => 'Debian',
      }
    end

    it {
      should contain_class('mongodb::repo::apt')
    }
  end

  context 'when deploying on CentOS' do
    let :facts do
      {
        :osfamily        => 'RedHat',
        :operatingsystem => 'CentOS',
      }
    end

    it {
      should contain_class('mongodb::repo::yum')
    }
  end

end
require 'spec_helper'

describe 'mongodb::server::config', :type => :class do

  describe 'with preseted variables' do
    let(:pre_condition) { ["class mongodb::server { $config = '/etc/mongod.conf' $dbpath = '/var/lib/mongo' }", "include mongodb::server"]}

    it {
      should contain_file('/etc/mongod.conf')
    }

  end

  describe 'with default values' do
    let(:pre_condition) {[ "class mongodb::server { $config = '/etc/mongod.conf' $dbpath = '/var/lib/mongo' $ensure = present $user = 'mongod' $group = 'mongod' $port = 29017 $bind_ip = ['0.0.0.0'] $fork = true $logpath ='/var/log/mongo/mongod.log' $logappend = true }",  "include mongodb::server" ]}

    it {
      should contain_file('/etc/mongod.conf').with({
        :mode   => '0644',
        :owner  => 'root',
        :group  => 'root'
      })

      should contain_file('/etc/mongod.conf').with_content(/^dbpath=\/var\/lib\/mongo/)
      should contain_file('/etc/mongod.conf').with_content(/bind_ip\s=\s0\.0\.0\.0/)
      should contain_file('/etc/mongod.conf').with_content(/^port = 29017$/)
      should contain_file('/etc/mongod.conf').with_content(/^logappend=true/)
      should contain_file('/etc/mongod.conf').with_content(/^logpath=\/var\/log\/mongo\/mongod\.log/)
      should contain_file('/etc/mongod.conf').with_content(/^fork=true/)
    }
  end

  describe 'with absent ensure' do
    let(:pre_condition) { ["class mongodb::server { $config = '/etc/mongod.conf' $dbpath = '/var/lib/mongo' $ensure = absent }", "include mongodb::server"]}

    it {
      should contain_file('/etc/mongod.conf').with({ :ensure => 'absent' })
    }

  end

  describe 'with specific bind_ip values' do
    let(:pre_condition) { ["class mongodb::server { $config = '/etc/mongod.conf' $dbpath = '/var/lib/mongo' $ensure = present $bind_ip = ['127.0.0.1', '10.1.1.13']}", "include mongodb::server"]}

    it {
      should contain_file('/etc/mongod.conf').with_content(/bind_ip\s=\s127\.0\.0\.1\,10\.1\.1\.13/)
    }
  end

  describe 'when specifying auth to true' do
    let(:pre_condition) { ["class mongodb::server { $config = '/etc/mongod.conf' $auth = true $dbpath = '/var/lib/mongo' $ensure = present }", "include mongodb::server"]}

    it {
      should contain_file('/etc/mongod.conf').with_content(/^auth=true/)
    }
  end
  
  describe 'when specifying set_parameter value' do
    let(:pre_condition) { ["class mongodb::server { $config = '/etc/mongod.conf' $set_parameter = 'textSearchEnable=true' $dbpath = '/var/lib/mongo' $ensure = present }", "include mongodb::server"]}

    it {
      should contain_file('/etc/mongod.conf').with_content(/^setParameter = textSearchEnable=true/)
    }
  end

  describe 'with journal:' do
    context 'on true with i686 architecture' do
      let(:pre_condition) { ["class mongodb::server { $config = '/etc/mongod.conf' $dbpath = '/var/lib/mongo' $ensure = present $journal = true }", "include mongodb::server"]}
      let (:facts) { { :architecture => 'i686' } }

      it {
        should contain_file('/etc/mongod.conf').with_content(/^journal = true/)
      }
    end
  end

  # check nested quota and quotafiles
  describe 'with quota to' do

    context 'true and without quotafiles' do
      let(:pre_condition) { ["class mongodb::server { $config = '/etc/mongod.conf' $dbpath = '/var/lib/mongo' $ensure = present $quota = true }", "include mongodb::server"]}
      it {
        should contain_file('/etc/mongod.conf').with_content(/^quota = true/)
      }
    end

    context 'true and with quotafiles' do
      let(:pre_condition) { ["class mongodb::server { $config = '/etc/mongod.conf' $dbpath = '/var/lib/mongo' $ensure = present $quota = true $quotafiles = 1 }", "include mongodb::server"]}

      it {
        should contain_file('/etc/mongod.conf').with_content(/quota = true/)
        should contain_file('/etc/mongod.conf').with_content(/quotaFiles = 1/)
      }
    end
  end

  describe 'when specifying syslog value' do
    context 'it should be set to true' do
      let(:pre_condition) { ["class mongodb::server { $config = '/etc/mongod.conf' $dbpath = '/var/lib/mongo' $ensure = present $syslog = true }", "include mongodb::server"]}

      it {
        should contain_file('/etc/mongod.conf').with_content(/^syslog = true/)
      }
    end

    context 'if logpath is also set an error should be raised' do
      let(:pre_condition) { ["class mongodb::server { $config = '/etc/mongod.conf' $dbpath = '/var/lib/mongo' $ensure = present $syslog = true $logpath ='/var/log/mongo/mongod.log' }", "include mongodb::server"]}

      it {
        expect { should contain_file('/etc/mongod.conf') }.to raise_error(Puppet::Error, /You cannot use syslog with logpath/)
      }
    end

  end

end
require 'spec_helper'

describe 'mongodb::server::install', :type => :class do

  describe 'it should create package and dbpath file' do
    let(:pre_condition) { ["class mongodb::server { $package_ensure = true $dbpath = '/var/lib/mongo' $user = 'mongodb' $package_name = 'mongodb-server' }", "include mongodb::server"]}

    it {
      should contain_package('mongodb_server').with({
        :ensure => 'present',
        :name   => 'mongodb-server',
      })
    }
  end

end
require 'spec_helper'

describe 'mongodb::server' do
  let :facts do
    {
      :osfamily        => 'Debian',
      :operatingsystem => 'Debian',
    }
  end

  context 'with defaults' do
    it { should contain_class('mongodb::server::install') }
    it { should contain_class('mongodb::server::config') }
  end

  context 'when deploying on Solaris' do
    let :facts do
      { :osfamily        => 'Solaris' }
    end
    it { expect { should raise_error(Puppet::Error) } }
  end

end
require 'spec_helper'

describe 'mongodb::db', :type => :define do
  let(:title) { 'testdb' }

  let(:params) {
    { 'user'     => 'testuser',
      'password' => 'testpass',
    }
  }

  it 'should contain mongodb_database with mongodb::server requirement' do
    should contain_mongodb_database('testdb')\
      .with_require('Class[Mongodb::Server]')
  end

  it 'should contain mongodb_user with mongodb_database requirement' do
    should contain_mongodb_user('testuser')\
      .with_require('Mongodb_database[testdb]')
  end

  it 'should contain mongodb_user with proper database name' do
    should contain_mongodb_user('testuser')\
      .with_database('testdb')
  end

  it 'should contain mongodb_user with proper roles' do
    params.merge!({'roles' => ['testrole1', 'testrole2']})
    should contain_mongodb_user('testuser')\
      .with_roles(["testrole1", "testrole2"])
  end

  it 'should prefer password_hash instead of password' do
    params.merge!({'password_hash' => 'securehash'})
    should contain_mongodb_user('testuser')\
      .with_password_hash('securehash')
  end

  it 'should contain mongodb_database with proper tries param' do
    params.merge!({'tries' => 5})
    should contain_mongodb_database('testdb').with_tries(5)
  end
end
require 'puppetlabs_spec_helper/module_spec_helper'
#! /usr/bin/env ruby -S rspec
require 'beaker-rspec'

UNSUPPORTED_PLATFORMS = []

unless ENV['RS_PROVISION'] == 'no' or ENV['BEAKER_provision'] == 'no'
  if hosts.first.is_pe?
    install_pe
    on hosts, 'mkdir -p /etc/puppetlabs/facter/facts.d'
  else
    install_puppet
    on hosts, 'mkdir -p /etc/facter/facts.d'
    on hosts, '/bin/touch /etc/puppet/hiera.yaml'
  end
  hosts.each do |host|
    on host, "mkdir -p #{host['distmoduledir']}"
  end
end

RSpec.configure do |c|
  # Project root
  proj_root = File.expand_path(File.join(File.dirname(__FILE__), '..'))

  # Readable test descriptions
  c.formatter = :documentation

  # Configure all nodes in nodeset
  c.before :suite do
    puppet_module_install(:source => proj_root, :module_name => 'mongodb')
    on hosts, 'puppet module install puppetlabs-stdlib'
    on hosts, 'puppet module install puppetlabs-apt'
    case fact('osfamily')
    when 'RedHat'
      on hosts, 'puppet module install stahnma-epel'
      apply_manifest_on hosts, 'include epel'
    end
    on hosts, 'service iptables stop'
  end
end
require 'rspec-system/spec_helper'
require 'rspec-system-puppet/helpers'
require 'rspec-system-serverspec/helpers'

include RSpecSystemPuppet::Helpers
include Serverspec::Helper::RSpecSystem
include Serverspec::Helper::DetectOS

RSpec.configure do |c|
  # Project root
  proj_root = File.expand_path(File.join(File.dirname(__FILE__), '..'))

  # Enable colour
  c.tty = true

  c.include RSpecSystemPuppet::Helpers

  # This is where we 'setup' the nodes before running our tests
  c.before :suite do
    # Install puppet
    puppet_install

    # Install modules and dependencies
    puppet_module_install(:source => proj_root, :module_name => 'mongodb')
    shell('puppet module install puppetlabs-stdlib')
    shell('puppet module install puppetlabs-apt')

    case node.facts['osfamily']
    when 'RedHat'
      shell('puppet module install stahnma-epel')
      puppet_apply('include epel')
    end
  end
end
require 'spec_helper'

describe 'the mongodb_password function' do
  before :all do
    Puppet::Parser::Functions.autoloader.loadall
  end

  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it 'should exist' do
    Puppet::Parser::Functions.function('mongodb_password').should == 'function_mongodb_password'
  end

  it 'should raise a ParseError if there no arguments' do
    lambda { scope.function_mongodb_password([]) }.should( raise_error(Puppet::ParseError))
  end

  it 'should raise a ParseError if there is more than 2 arguments' do
    lambda { scope.function_mongodb_password(%w(foo bar baz)) }.should( raise_error(Puppet::ParseError))
  end

  it 'should convert password into a hash' do
    result = scope.function_mongodb_password(%w(user pass))
    result.should(eq('e0c4a7b97d4db31f5014e9694e567d6b'))
  end

end
require 'spec_helper'

describe Puppet::Type.type(:mongodb_database).provider(:mongodb) do

  let(:resource) { Puppet::Type.type(:mongodb_database).new(
    { :ensure   => :present,
      :name     => 'new_database',
      :provider => described_class.name
    }
  )}

  let(:provider) { resource.provider }

  describe 'create' do
    it 'makes a database' do
      provider.expects(:mongo)
      provider.create
    end
  end

  describe 'destroy' do
    it 'removes a database' do
      provider.expects(:mongo)
      provider.destroy
    end
  end

  describe 'exists?' do
    it 'checks if database exists' do
      provider.expects(:mongo).at_least(2).returns("db1,new_database,db2")
      provider.exists?.should be_true
    end
  end

end
#
# Authors: Emilien Macchi <emilien.macchi@enovance.com>
#          Francois Charlier <francois.charlier@enovance.com>
#

require 'spec_helper'

describe Puppet::Type.type(:mongodb_replset).provider(:mongo) do

  valid_members = ['mongo1:27017', 'mongo2:27017', 'mongo3:27017']

  let(:resource) { Puppet::Type.type(:mongodb_replset).new(
    { :ensure        => :present,
      :name          => 'rs_test',
      :members       => valid_members,
      :provider      => :mongo
    }
  )}

  let(:resources) { { 'rs_test' => resource } }
  let(:provider) { described_class.new(resource) }

  describe '#create' do
    it 'should create a replicaset' do
      provider.class.stubs(:get_replset_properties)
      provider.stubs(:alive_members).returns(valid_members)
      provider.expects('rs_initiate').with("{ _id: \"rs_test\", members: [ { _id: 0, host: \"mongo1:27017\" },{ _id: 1, host: \"mongo2:27017\" },{ _id: 2, host: \"mongo3:27017\" } ] }", "mongo1:27017").returns(
        { "info" => "Config now saved locally.  Should come online in about a minute.",
          "ok"   => 1 } )
      provider.create
      provider.flush
    end
  end

  describe '#exists?' do
    describe 'when the replicaset does not exist' do
      it 'returns false' do
        provider.class.stubs(:mongo).returns(<<EOT)
{
	"startupStatus" : 3,
	"info" : "run rs.initiate(...) if not yet done for the set",
	"ok" : 0,
	"errmsg" : "can't get local.system.replset config from self or any seed (EMPTYCONFIG)"
}
EOT
        provider.class.prefetch(resources)
        resource.provider.exists?.should be_false
      end
    end

    describe 'when the replicaset exists' do
      it 'returns true' do
        provider.class.stubs(:mongo).returns(<<EOT)
{
	"_id" : "rs_test",
	"version" : 1,
	"members" : [ ]
}
EOT
        provider.class.prefetch(resources)
        resource.provider.exists?.should be_true
      end
    end
  end

  describe '#members' do
    it 'returns the members of a configured replicaset' do
      provider.class.stubs(:mongo).returns(<<EOT)
{
	"_id" : "rs_test",
	"version" : 1,
	"members" : [
		{
			"_id" : 0,
			"host" : "mongo1:27017"
		},
		{
			"_id" : 1,
			"host" : "mongo2:27017"
		},
		{
			"_id" : 2,
			"host" : "mongo3:27017"
		}
	]
}
EOT
      provider.class.prefetch(resources)
      resource.provider.members.should =~ valid_members
    end
  end

  describe 'members=' do
    before :each do
      provider.class.stubs(:mongo).returns(<<EOT)
{
	"setName" : "rs_test",
	"ismaster" : true,
	"secondary" : false,
	"hosts" : [
		"mongo1:27017"
	],
	"primary" : "mongo1:27017",
	"me" : "mongo1:27017",
	"maxBsonObjectSize" : 16777216,
	"maxMessageSizeBytes" : 48000000,
	"localTime" : ISODate("2014-01-10T19:31:51.281Z"),
	"ok" : 1
}
EOT
    end

    it 'adds missing members to an existing replicaset' do
      provider.stubs(:rs_status).returns({ "set" => "rs_test" })
      provider.expects('rs_add').times(2).returns({ 'ok' => 1 })
      provider.members=(valid_members)
      provider.flush
    end

    it 'raises an error when the master host is not available' do
      provider.stubs(:rs_status).returns({ "set" => "rs_test" })
      provider.stubs(:db_ismaster).returns({ "primary" => false })
      provider.members=(valid_members)
      expect { provider.flush }.to raise_error(Puppet::Error, "Can't find master host for replicaset #{resource[:name]}.")
    end

    it 'raises an error when at least one member is not running with --replSet' do
      provider.stubs(:rs_status).returns({ "ok" => 0, "errmsg" => "not running with --replSet" })
      provider.members=(valid_members)
      expect { provider.flush }.to raise_error(Puppet::Error, /is not supposed to be part of a replicaset\.$/)
    end

    it 'raises an error when at least one member is configured with another replicaset name' do
      provider.stubs(:rs_status).returns({ "set" => "rs_another" })
      provider.members=(valid_members)
      expect { provider.flush }.to raise_error(Puppet::Error, /is already part of another replicaset\.$/)
    end

    it 'raises an error when no member is available' do
      provider.class.stubs(:mongo_command).raises(Puppet::ExecutionFailure, <<EOT)
Fri Jan 10 20:20:33.995 Error: couldn't connect to server localhost:9999 at src/mongo/shell/mongo.js:147
exception: connect failed
EOT
      provider.members=(valid_members)
      expect { provider.flush }.to raise_error(Puppet::Error, "Can't connect to any member of replicaset #{resource[:name]}.")
    end
  end
end
require 'spec_helper'

describe Puppet::Type.type(:mongodb_user).provider(:mongodb) do

  let(:resource) { Puppet::Type.type(:mongodb_user).new(
    { :ensure        => :present,
      :name          => 'new_user',
      :database      => 'new_database',
      :password_hash => 'pass',
      :roles         => ['role1', 'role2'],
      :provider      => described_class.name
    }
  )}

  let(:provider) { resource.provider }

  describe 'create' do
    it 'creates a user' do
      provider.expects(:mongo)
      provider.create
    end
  end

  describe 'destroy' do
    it 'removes a user' do
      provider.expects(:mongo)
      provider.destroy
    end
  end

  describe 'exists?' do
    it 'checks if user exists' do
      provider.expects(:mongo).at_least(2).returns("1")
      provider.exists?.should be_true
    end
  end

  describe 'password_hash' do
    it 'returns a password_hash' do
      provider.expects(:mongo).returns("pass\n")
      provider.password_hash.should == "pass"
    end
  end

  describe 'password_hash=' do
    it 'changes a password_hash' do
      provider.expects(:mongo)
      provider.password_hash=("newpass")
    end
  end

  describe 'roles' do
    it 'returns a sorted roles' do
      provider.expects(:mongo).returns("role2,role1\n")
      provider.roles.should == ['role1','role2']
    end
  end

  describe 'roles=' do
    it 'changes a roles' do
      provider.expects(:mongo)
      provider.roles=(['role3','role4'])
    end
  end

end
require 'puppet'
require 'puppet/type/mongodb_database'
describe Puppet::Type.type(:mongodb_database) do

  before :each do
    @db = Puppet::Type.type(:mongodb_database).new(:name => 'test')
  end

  it 'should accept a database name' do
    @db[:name].should == 'test'
  end

  it 'should accept a tries parameter' do
    @db[:tries] = 5
    @db[:tries].should == 5
  end

  it 'should require a name' do
    expect {
      Puppet::Type.type(:mongodb_database).new({})
    }.to raise_error(Puppet::Error, 'Title or name must be provided')
  end

end
#
# Author: Emilien Macchi <emilien.macchi@enovance.com>
#

require 'puppet'
require 'puppet/type/mongodb_replset'
describe Puppet::Type.type(:mongodb_replset) do

  before :each do
    @replset = Puppet::Type.type(:mongodb_replset).new(:name => 'test')
  end

  it 'should accept a replica set name' do
    @replset[:name].should == 'test'
  end

  it 'should accept a members array' do
    @replset[:members] = ['mongo1:27017', 'mongo2:27017']
    @replset[:members].should == ['mongo1:27017', 'mongo2:27017']
  end

  it 'should require a name' do
    expect {
      Puppet::Type.type(:mongodb_replset).new({})
    }.to raise_error(Puppet::Error, 'Title or name must be provided')
  end

end
require 'puppet'
require 'puppet/type/mongodb_user'
describe Puppet::Type.type(:mongodb_user) do

  before :each do
    @user = Puppet::Type.type(:mongodb_user).new(
              :name => 'test',
              :database => 'testdb',
              :password_hash => 'pass')
  end

  it 'should accept a user name' do
    @user[:name].should == 'test'
  end

  it 'should accept a database name' do
    @user[:database].should == 'testdb'
  end

  it 'should accept a tries parameter' do
    @user[:tries] = 5
    @user[:tries].should == 5
  end

  it 'should accept a password' do
    @user[:password_hash] = 'foo'
    @user[:password_hash].should == 'foo'
  end

  it 'should use default role' do
    @user[:roles].should == ['dbAdmin']
  end

  it 'should accept a roles array' do
    @user[:roles] = ['role1', 'role2']
    @user[:roles].should == ['role1', 'role2']
  end

  it 'should require a name' do
    expect {
      Puppet::Type.type(:mongodb_user).new({})
    }.to raise_error(Puppet::Error, 'Title or name must be provided')
  end

  it 'should require a database' do
    expect {
      Puppet::Type.type(:mongodb_user).new({:name => 'test', :password_hash => 'pass'})
    }.to raise_error(Puppet::Error, 'Parameter \'database\' must be set')
  end

  it 'should require a password_hash' do
    expect {
      Puppet::Type.type(:mongodb_user).new({:name => 'test', :database => 'testdb'})
    }.to raise_error(Puppet::Error, 'Property \'password_hash\' must be set. Use mongodb_password() for creating hash.')
  end

  it 'should sort roles' do
    # Reinitialize type with explicit unsorted roles.
    @user = Puppet::Type.type(:mongodb_user).new(
              :name => 'test',
              :database => 'testdb',
              :password_hash => 'pass',
              :roles => ['b', 'a'])
    @user[:roles].should == ['a', 'b']
  end

end
# mongo.conf - generated from Puppet


<% if @logpath -%>
#where to log
logpath=<%= @logpath %>
<% if @logappend -%>
logappend=<%= @logappend %>
<% end -%>
<% end -%>
<% if @bind_ip -%>
# Set this option to configure the mongod or mongos process to bind to and
# listen for connections from applications on this address.
# You may concatenate a list of comma separated values to bind mongod to multiple IP addresses.
bind_ip = <%= Array(@bind_ip).join(',') %>
<% end -%>
<% if @fork -%>
# fork and run in background
fork=<%= @fork %>
<% end -%>
port = <%= @port %>
dbpath=<%= @dbpath %>
<% if @pidfilepath -%>
# location of pidfile
pidfilepath = <%= @pidfilepath %>
<% end -%>
<% if @nojournal and not @journal -%>
# Disables write-ahead journaling
nojournal = <%= @nojournal %>
<% end -%>
<% if @journal and not @nojournal -%>
# Enables journaling
journal = <%= @journal %>
<% end -%>
<% if @cpu -%>
# Enables periodic logging of CPU utilization and I/O wait
cpu = <%= @cpu %>
<% end -%>
# Turn on/off security.  Off is currently the default
<% if @noauth and not @auth -%>
noauth=<%= @noauth %>
<% end -%>
<% if @auth and not @noauth -%>
auth=<%= @auth %>
<% end -%>
<% if @verbose -%>
# Verbose logging output.
verbose = <%= @verbose %>
<% end -%>
<% if @verbositylevel -%>
<%= @verbositylevel -%> = true
<% end -%>
<% if @objcheck -%>
# Inspect all client data for validity on receipt (useful for
# developing drivers)
objcheck = <%= @objcheck %>
<% end -%>
<% if @maxconns -%>
maxConns = <%= @maxconns %>
<% end -%>
<% if @quota -%>
# Enable db quota management
quota = <%= @quota %>
<% if @quotafiles -%>
quotaFiles = <%= @quotafiles %>
<% end -%>
<% end -%>
<% if @diaglog -%>
# Set oplogging level where n is
#   0=off (default)
#   1=W
#   2=R
#   3=both
#   7=W+some reads
diaglog  = <%= @diaglog %>
<% end -%>
<% if @oplog_size -%>
# Specifies a maximum size in megabytes for the replication operation log
oplogSize = <%= @oplog_size %>
<% end -%>
<% if @nohints -%>
# Ignore query hints
nohints = <%= @nohints %>
<% end -%>
<% if @nohttpinterface -%>
# Disable the HTTP interface (Defaults to localhost:27018).
nohttpinterface = <%= @nohttpinterface %>
<% end -%>
<% if @noscripting -%>
# Turns off server-side scripting.  This will result in greatly limited
# functionality
noscripting = <%= @noscripting %>
<% end -%>
<% if @notablescan -%>
# Turns off table scans.  Any query that would do a table scan fails.
notablescan = <%= @notablescan %>
<% end -%>
<% if @noprealloc -%>
# Disable data file preallocation.
noprealloc = <%= @noprealloc %>
<% end -%>
<% if @nssize -%>
# Specify .ns file size for new databases in megabytes.
nssize = <%= @nssize %>
<% end -%>
<% if @mms_token -%>
# Accout token for Mongo monitoring server.
mms-token = <%= @mms_token %>
<% end -%>
<% if @mms_name -%>
# Server name for Mongo monitoring server.
mms-name = <%= @mms_name %>
<% end -%>
<% if @mms_interval -%>
# Ping interval for Mongo monitoring server.
mms-interval = <%= @mms_interval %>
<% end -%>
<% if @slave -%>
slave = <%= @slave %>
<% end -%>
<% if @source -%>
source = <%= @source %>
<% end -%>
<% if @only -%>
# Slave only: specify a single database to replicate
only = <%= @only %>
<% end -%>
<% if @master -%>
master = <%= @master %>
<% end -%>
<% if @directoryperdb -%>
# Alters the storage pattern of the data directory to store each database
# files in a distinct folder.
directoryperdb = <%= @directoryperdb %>
<% end -%>
<% if @replset -%>
# Configure ReplicaSet membership
replSet = <%= @replset %>
<% end -%>
<% if @smallfiles -%>
# Use a smaller default data file size.
smallfiles = <%= @smallfiles %>
<% end -%>
<% if @rest -%>
# Enable rest API (disabled by default)
rest = <%= @rest %>
<% end -%>
<% if @profile -%>
# Modify this value to changes the level of database profiling, which inserts
# information about operation performance into output of mongod or the log file.
#0 = Off. No profiling. default
#1 = On. Only includes slow operations.
#2 = On. Includes all operations.
profile = <%= @profile %>
<% end -%>
<% if @slowms -%>
# Sets the threshold in milliseconds for mongod to consider a query slow for the profiler.
slowms = <%= @slowms %>
<% end -%>
<% if @keyfile -%>
# Specify the path to a key file to store authentication information.
keyFile = <%= @keyfile %>
<% end -%>
<% if @directoryperdb -%>
directoryperdb = <%= @directoryperdb %>
<% end -%>
<% if @set_parameter -%>
setParameter = <%= @set_parameter %>
<% end -%>
<% if @syslog -%>
syslog = <%= @syslog %>
<% end -%>
class { 'mongodb::globals':
  manage_package_repo => true
}
class { '::mongodb': }
node default {
  class { '::mongodb::globals':
    manage_package_repo => true
  } ->
  class { '::mongodb::server':
    smallfiles => true,
    bind_ip    => ['0.0.0.0'],
    replset    => 'rsmain'
  }
}

node /mongo1/ inherits default {
  mongodb_replset{'rsmain':
    members => ['mongo1:27017', 'mongo2:27017', 'mongo3:27017']
  }
}
class { 'mongodb::globals': manage_package_repo => true }->
class { 'mongodb::server': }
name 'example42-monitor'
version '2.0.1'

author 'Alessandro Franceschi'
license 'Apache2'
project_page 'http://www.example42.com'
summary 'Puppet monitoring abstraction meta module'
description 'This module provides abstraction defines to monitor resources managed by Puppet modules. It is used in the Example42 modules set but can be imported and used in other setups. According to the monitor tool used it may have the relevant module as dependency'
dependency 'example42/puppi', '>=2.0.0'
# Puppet module: monitor

This is a Puppet abstraction module to manage monitoring.

Made by Alessandro Franceschi / Lab42 - http://www.example42.com

Released under the terms of Apache 2 License.

Check Modulefile for dependencies.

## Goal of this module
This module abstracts the monitoring definitions for an host or application, in order to add and use different monitoring methods, without changes on the single application modules.

It's used, as an option disabled by default, in the Example42 modules and provides:

* a common interface for different monitoring tools (Nagios, Monit, Munin....)

* an unified syntax for monitoring resources able to adapt to monitoring modules from different authors

* a standard way to define what an application or an host needs to be monitored

* reversable actions (you can remove a monitor resource previously defined)

## Usage
In order to activate automatic monitoring for the resources defined in a class you have to pass, at least, these parameters:

        class { "foo":
          monitor      => true,
          monitor_tool => [ "nagios" , "monit" , "munin" ],
        }

where monitor_tool is an array of the monitor tools you want to activate to automatically check the resources provided the defined class.

In Example42 modules, when monitoring is active,  for applications that provide network services, is activated the monitoring of the listening port and the running process, with a syntax like this:

        monitor::port { "foo_${foo::protocol}_${foo::port}": 
          protocol => "${foo::protocol}",
          port     => "${foo::port}",
          target   => "${foo::params::monitor_target_real}",
          tool     => "${foo::monitor_tool}",
          enable   => $foo::manage_monitor,
        }

        monitor::process { "foo_process":
          process  => "${foo::process}",
          service  => "${foo::service}",
          pidfile  => "${foo::pidfile}",
          tool     => "${foo::monitor_tool}",
          enable   => $foo::manage_monitor,
        }

Modules related to web applications generally have a monitor::url define that checks for a specifyed pattern string in an given url:

        monitor::url { "foo_webapp_url":
          url     => "${foo_webapp::url_check}",
          pattern => "${foo_webapp::url_pattern}",
          port    => "${foo_webapp::port}",
          target  => "${fqdn}",
          tool    => "${foo_webapp::monitor_tool}",
          enable  => $foo_webapp::manage_monitor,
        }

## Monitor module layout 
This monitor module is to be considered a (working) implementation, entirely based on Puppet's DSL of a (strongly needed) monitor abstraction type.
The generic monitor defines are placed in files like:

        monitor/manifests/process.pp
        monitor/manifests/port.pp
        monitor/manifests/url.pp

here according to the monitor_tool requested are called some specific defines relevant to the requested monitoring tools.
Note that here you can choose different implementations of monitoring modules, so you are free to change the whole module to be used for a specific monitoring tool editing just these few files.  

## Dependencies
This is a meta-module that needs dependencies according to the monitor tools modules you use.
It also requires Example42's puppi module.
IMPORTANT: You must have storeconfigs enabled on your PuppetMaster to use monitoring tools that involve a central server, like Nagios or Munin.
require 'rubygems'
require 'puppetlabs_spec_helper/rake_tasks'
require 'puppet-lint'
PuppetLint.configuration.send("disable_80chars")
PuppetLint.configuration.send('disable_class_parameter_defaults')
# Define monitor::mount
#
# You can use this define to manage monitored mounts.
# It automatically monitors the mount point you specify
# AND IT MAY MOUNT it using Puppet's native mount define.
# So, generically, you just have to use monitor::mount
# instead of mount to manage your mount points.
# The possible arguments are the same of the native mount
# define plus some ones what define if and how to create the mount
# directory, if to just check the mount without managing it
# with Puppet and the tool(s) to use for monitoring.
# If you want to check the mount point only, without actually
# mounting it via the mount define, set only_check=true
#
define monitor::mount (
  $name,
  $device,
  $fstype,
  $options    = '',
  $pass       = '0',
  $remounts   = true,
  $ensure     = 'mounted',
  $atboot     = true,
  $only_check = false,
  $create_dir = false,
  $owner      = 'root',
  $group      = 'root',
  $mode       = '0755',
  $template   = '',
  $enable     = true,
  $tool       = $::monitor_tool
  ) {

  $bool_enable=any2bool($enable)

  $computed_ensure = $bool_enable ? {
    false => 'absent',
    true  => 'present',
  }

  # Manage template
  $real_template = $template ? {
    ''      => undef,
    default => $template,
  }

  $escapedname=regsubst($name,'/','_','G')

  # The mount is actually done (if $only_check != true )
  if ( $only_check != true ) {
    mount { $name:
      ensure   => $ensure,
      name     => $name,
      device   => $device,
      fstype   => $fstype,
      options  => $options,
      pass     => $pass,
      remounts => $remounts,
      atboot   => true,
    }
  }

  if ( $create_dir == true ) and ( $only_check != true ) {
    file { $name:
      ensure  => directory,
      path    => $name,
      owner   => $owner,
      group   => $group,
      mode    => $mode,
      before  => Mount[$name],
    }
  }

  if ($tool =~ /nagios/) {
    nagios::service { "Mount_${escapedname}":
      ensure        => $computed_ensure,
      template      => $real_template,
      check_command => "check_nrpe!check_mount!${name}!${fstype}",
    }
  }

  if ($tool =~ /icinga/) {
    icinga::service { "Mount_${escapedname}":
      ensure        => $computed_ensure,
      template      => $real_template,
      check_command => "check_nrpe!check_mount!${name}!${fstype}",
    }
  }

  if ($tool =~ /puppi/) {
    puppi::check { "Mount_${escapedname}":
      enable   => $enable,
      hostwide => 'yes',
      command  => "check_mount -m ${name} -t ${fstype}" ,
    }
  }

}

# define monitor::plugin
#
# A monitor define to manage NAGIOS plugins
# It can be used to define monitoring via whatever Nagios plugin
# This define requires Example42 nrpe module
#
# == Parameters
#
# [*plugin*]
#   Name of the Nagios plugin. As it appears in the Nagios plugins path
#   (do not specify the full path, it's autocalculated for your OS)
#   Required argument
#
# [*tool*]
#   The monitoring tool to use. Currently supported: nagios, puppi
#   To add a monitoring tool (that supports the usage of Nagios plugins)
#   just add the relevant resources (local or exported) in the code
#
# [*arguments*]
#   The arguments to pass to the plugin.
#
# [*checksource*]
#   From where the check is executed:
#   local = Check is executed via Nrpe
#   remote = Check is executed from the Nagios server
#
# [*template*]
#   Template to use to manage configuration. Path is as used in
#   content => template ( $template )
#   Content actually depends on the monitoring tool used
#
# [*enable*]
#   Use this to enable or disable the check. Default: true
#
# == Example
#
#    monitor::plugin { "Fsi_Import_Errors":
#      plugin    => 'check_log' ,
#      arguments => '-F /var/log/app.log -O /var/tmp/app.log -q error',
#      tool      => [ 'puppi' , 'nagios' ],
#    }
#
define monitor::plugin (
  $plugin,
  $tool,
  $arguments   = '',
  $checksource = 'local', # Note: Remote checksource might not work properly
  $template    = '',
  $enable      = true
  ) {

  $bool_enable = any2bool($enable)
  $safe_name = regsubst($name, '(/| )', '_', 'G')
  $ensure = $bool_enable ? {
    false => 'absent',
    true  => 'present',
  }

  # Manage template
  $real_template = $template ? {
    ''      => undef,
    default => $template,
  }

  $check_command = $checksource ? {
    local   => "check_nrpe!${safe_name}!blank",
    remote  => "${plugin}!${arguments}",
  }

  if ($tool =~ /nagios/) {
    nagios::service { $safe_name:
      ensure        => $ensure,
      template      => $real_template,
      check_command => $check_command,
    }

    # If plugin check is via nrpe, we create a local configuration entry
    if $checksource == local {
      file { "nrpe-check_${safe_name}":
        ensure  => $ensure,
        path    => "${nrpe::config_dir}/check_${safe_name}.cfg",
        require => Package['nrpe'],
        notify  => $nrpe::manage_service_autorestart,
        replace => $nrpe::manage_file_replace,
        audit   => $nrpe::manage_audit,
        content => "command[${safe_name}]=${nrpe::pluginsdir}/${plugin} ${arguments}\n",
      }
    }
  }

  if ($tool =~ /icinga/) {
    icinga::service { $safe_name:
      ensure        => $ensure,
      template      => $real_template,
      check_command => $check_command,
    }

    # If plugin check is via nrpe, we create a local configuration entry
    if $checksource == local {
      file { "nrpe-check_${safe_name}":
        ensure  => $ensure,
        path    => "${nrpe::config_dir}/check_${safe_name}.cfg",
        require => Package['nrpe'],
        notify  => $nrpe::manage_service_autorestart,
        replace => $nrpe::manage_file_replace,
        audit   => $nrpe::manage_audit,
        content => "command[${safe_name}]=${nrpe::pluginsdir}/${plugin} ${arguments}\n",
      }
    }
  }

  if ($tool =~ /puppi/) {
    puppi::check { $safe_name:
      enable   => $bool_enable,
      hostwide => 'yes',
      command  => "${plugin} ${arguments}",
    }
  }

}
define monitor::port (
  $port,
  $protocol,
  $target,
  $tool,
  $checksource  = '',
  $template     = '',
  $enable=true
  ) {

  $bool_enable=any2bool($enable)

  $real_checksource = $checksource ? {
    ''      => $target ? {
      'localhost' => 'local',
      '127.0.0.1' => 'local',
      default     => 'remote',
    },
    default => $checksource,
  }

  # Manage template
  $real_template = $template ? {
    ''      => undef,
    default => $template,
  }

  $ensure = $bool_enable ? {
    false => 'absent',
    true  => 'present',
  }

  if ($tool =~ /munin/) {
  }

  if ($tool =~ /collectd/) {
  }

  if ($tool =~ /monit/) {
  }

  $tcp_check_command = $real_checksource ? {
    local   => "check_nrpe!check_port_tcp!${target}!${port}",
    default => "check_tcp!${port}",
  }

  $udp_check_command = $real_checksource ? {
    local   => "check_nrpe!check_port_udp!${target}!${port}",
    default => "check_udp!${port}",
  }

  $check_command = $protocol ? {
    tcp => $tcp_check_command,
    udp => $udp_check_command,
  }

  if ($tool =~ /nagios/) {
    nagios::service { $name:
      ensure        => $ensure,
      template      => $real_template,
      check_command => $check_command,
    }
  }

  if ($tool =~ /icinga/) {
    icinga::service { $name:
      ensure        => $ensure,
      template      => $real_template,
      check_command => $check_command,
    }
  }

  $puppi_command = $protocol ? {
    'tcp' => "check_tcp -H ${target} -p ${port}" ,
    'udp' => "check_udp -H ${target} -p ${port}" ,
  }
  if ($tool =~ /puppi/) {
    puppi::check { $name:
      enable   => $bool_enable,
      hostwide => 'yes',
      command  => $puppi_command,
    }
  }
}
define monitor::process (
  $process,
  $service,
  $pidfile,
  $tool,
  $enable       = true,
  $argument     = '',
  $user         = '',
  $template     = '',
  $config_hash  = {}
  ) {

  $bool_enable=any2bool($enable)

  $real_template = $template ? {
    ''      => undef,
    default => $template,
  }

  $ensure = $bool_enable ? {
    false => 'absent',
    true  => 'present',
  }

  if ($tool =~ /munin/) {
  }

  if ($tool =~ /collectd/) {
  }

  if ($tool =~ /monit/) {
    monit::checkpid { $name:
      pidfile      => $pidfile,
      process      => "${process}${argument}",
      startprogram => "/etc/init.d/${service} start",
      stopprogram  => "/etc/init.d/${service} stop",
      enable       => $bool_enable,
    }
  }

  if ($tool =~ /bluepill/) {
    bluepill::process { $name:
      pidfile      => $pidfile,
      process      => "${process}${argument}",
      startprogram => "/etc/init.d/${service} start",
      stopprogram  => "/etc/init.d/${service} stop",
      enable       => $bool_enable,
      config_hash  => $config_hash,
    }
  }

  if ($tool =~ /eye/) {
    eye::process { $name:
      pidfile      => $pidfile,
      process      => "${process}${argument}",
      startprogram => "/etc/init.d/${service} start",
      stopprogram  => "/etc/init.d/${service} stop",
      enable       => $bool_enable,
      config_hash  => $config_hash,
    }
  }

  $default_check_command = $argument ? {
    undef   => "check_nrpe!check_process!${process}",
    ''      => "check_nrpe!check_process!${process}",
    default => "check_nrpe!check_processwitharg!${process}!${argument}",
  }

  $check_command = $process ? {
    undef   => "check_nrpe!check_process!${name}",
    default => $default_check_command,
  }

  if ($tool =~ /nagios/) {
    nagios::service { $name:
      ensure        => $ensure,
      template      => $real_template,
      check_command => $check_command,
    }
  }

  if ($tool =~ /icinga/) {
    icinga::service { $name:
      ensure        => $ensure,
      template      => $real_template,
      check_command => $check_command,
    }
  }

  $puppi_default_command = $argument ? {
    undef   => "check_procs -c 1: -C ${process}",
    ''      => "check_procs -c 1: -C ${process}",
    default => "check_procs -c 1: -C ${process} -a ${argument}",
  }

  $puppi_command = $process ? {
    undef   => "check_procs -c 1: -C ${name}",
    default => $puppi_default_command,
  }

  if ($tool =~ /puppi/) {
    puppi::check { $name:
      enable   => $bool_enable,
      hostwide => 'yes',
      command  => $puppi_command,
    }
  }
}
define monitor::url (
  $tool,
  $url          = 'http://127.0.0.1',
  $target       = '',
  $host         = '',
  $port         = '80',
  $pattern      = '',
  $username     = '',
  $password     = '',
  $monitorgroup = '',
  $template     = '',
  $useragent    = 'UrlCheck',
  $checksource  = 'remote',
  $enable       = true
  ) {

  $bool_enable=any2bool($enable)

  $ensure = $bool_enable ? {
    false => 'absent',
    true  => 'present',
  }

  # If target is not provided we get it from the Url
  $computed_target = $target ? {
    ''      => url_parse($url,host),
    default => $target,
  }

  # If host is not provided we get it from the Url
  $computed_host = $host ? {
    ''      => url_parse($url,host),
    default => $host,
  }

  # Manage template
  $real_template = $template ? {
    ''      => undef,
    default => $template,
  }

  # Needed to create flag todo files seamlessly
  $urlq = regsubst($url , '/' , '-' , 'G')

  if ($tool =~ /munin/) {
  }

  if ($tool =~ /collectd/) {
  }

  if ($tool =~ /monit/) {
  }

  $local_check_command = $username ? { # CHECK VIA NRPE STILL DOESN'T WORK WITH & and ? in URLS!
    undef   => "check_nrpe!check_url!${computed_target}!${port}!${url}!${pattern}!${useragent}!${computed_host}" ,
    ''      => "check_nrpe!check_url!${computed_target}!${port}!${url}!${pattern}!${useragent}!${computed_host}" ,
    default => "check_nrpe!check_url_auth!${computed_target}!${port}!${url}!${pattern}!${username}:${password}!${useragent}!${computed_host}" ,
  }

  $default_check_command = $username ? {
    undef   => "check_url!${computed_target}!${port}!${url}!${pattern}!${useragent}" ,
    ''      => "check_url!${computed_target}!${port}!${url}!${pattern}!${useragent}" ,
    default => "check_url_auth!${computed_target}!${port}!${url}!${pattern}!${username}:${password}!${useragent}" ,
  }

  $check_command = $checksource ? {
    local   => $local_check_command,
    default => $default_check_command
  }

  if ($tool =~ /nagios/) {
    # Use for Example42 service checks
    # (note: are used custom Nagios and nrpe commands)
    nagios::service { $name:
      ensure        => $ensure,
      template      => $real_template,
      check_command => $check_command,
    }
  }

  if ($tool =~ /icinga/) {
    icinga::service { $name:
      ensure        => $ensure,
      template      => $real_template,
      check_command => $check_command,
    }
  }

  $puppi_hostwide = $monitorgroup ? {
    undef   => 'yes' ,
    ''      => 'yes' ,
    default => 'no' ,
  }

  $puppi_command = $username ? {
    undef   => "check_http -I '${computed_target}' -p '${port}' -u '${url}' -H '${computed_host}' -r '${pattern}' -A '${useragent}'" ,
    ''      => "check_http -I '${computed_target}' -p '${port}' -u '${url}' -H '${computed_host}' -r '${pattern}' -A '${useragent}'" ,
    default => "check_http -I '${computed_target}' -p '${port}' -u '${url}' -H '${computed_host}' -r '${pattern}' -a ${username}:${password} -A '${useragent}'" ,
  }

  if ($tool =~ /puppi/) {
    # Use for Example42 puppi checks
    puppi::check { $name:
      enable   => $enable,
      hostwide => $puppi_hostwide,
      project  => $monitorgroup ,
      command  => $puppi_command,
    }
  }
}
{
  "name": "example42-monitor",
  "version": "2.0.1",
  "source": "UNKNOWN",
  "author": "Alessandro Franceschi",
  "license": "Apache2",
  "summary": "Puppet monitoring abstraction meta module",
  "description": "This module provides abstraction defines to monitor resources managed by Puppet modules. It is used in the Example42 modules set but can be imported and used in other setups. According to the monitor tool used it may have the relevant module as dependency",
  "project_page": "http://www.example42.com",
  "dependencies": [
    {
      "name": "example42/puppi",
      "version_requirement": ">=2.0.0"
    }
  ],
  "types": [

  ],
  "checksums": {
    "Modulefile": "90526fde2048db7a15f324086b5dd7aa",
    "README.md": "3905b3902659a53f7536327984714beb",
    "Rakefile": "e90d68823ff237c89224eb139f8926ad",
    "manifests/mount.pp": "4ea23824d3c7c1ca75a0004f05c3530f",
    "manifests/plugin.pp": "985207d9dd6bb39c12b71cd0be243e00",
    "manifests/port.pp": "b77e774831764008d8db2ac548478b1b",
    "manifests/process.pp": "aa61f2caee5066212cbc393030dc7ba4",
    "manifests/url.pp": "b90d428c6d537bfe0e379124f8453a40",
    "spec/fixtures/manifests/site.pp": "d41d8cd98f00b204e9800998ecf8427e"
  }
}
fixtures:
  repositories:
    "stdlib": "https://github.com/puppetlabs/puppetlabs-stdlib"
  symlinks:
    "mysql": "#{source_dir}"
default_set: 'centos-64-x64'
sets:
  'centos-59-x64':
    nodes:
      "main.foo.vm":
        prefab: 'centos-59-x64'
  'centos-64-x64':
    nodes:
      "main.foo.vm":
        prefab: 'centos-64-x64'
  'fedora-18-x64':
    nodes:
      "main.foo.vm":
        prefab: 'fedora-18-x64'
  'debian-607-x64':
    nodes:
      "main.foo.vm":
        prefab: 'debian-607-x64'
  'debian-70rc1-x64':
    nodes:
      "main.foo.vm":
        prefab: 'debian-70rc1-x64'
  'ubuntu-server-10044-x64':
    nodes:
      "main.foo.vm":
        prefab: 'ubuntu-server-10044-x64'
  'ubuntu-server-12042-x64':
    nodes:
      "main.foo.vm":
        prefab: 'ubuntu-server-12042-x64'
branches:
  only:
    - master
language: ruby
bundler_args: --without development
script: "bundle exec rake spec SPEC_OPTS='--format documentation'"
rvm:
  - 1.8.7
  - 1.9.3
  - 2.0.0
env:
  matrix:
    - PUPPET_GEM_VERSION="~> 2.7.0"
    - PUPPET_GEM_VERSION="~> 3.3.0"
    - PUPPET_GEM_VERSION="~> 3.4.0"
matrix:
  fast_finish: true
  exclude:
    - rvm: 1.9.3
      env: PUPPET_GEM_VERSION="~> 2.7.0"
    - rvm: 2.0.0
      env: PUPPET_GEM_VERSION="~> 2.7.0"
notifications:
  email: false
##2014-07-15 - Supported Release 2.3.1
###Summary

This release merely updates metadata.json so the module can be uninstalled and
upgraded via the puppet module command.

##2014-05-14 - Supported Release 2.3.0

This release primarily adds support for RHEL7 and Ubuntu 14.04 but it
also adds a couple of new parameters to allow for further customization,
as well as ensuring backups can backup stored procedures properly.

####Features
Added `execpath` to allow a custom executable path for non-standard mysql installations.
Added `dbname` to mysql::db and use ensure_resource to create the resource.
Added support for RHEL7 and Fedora Rawhide.
Added support for Ubuntu 14.04.
Create a warning for if you disable SSL.
Ensure the error logfile is owned by MySQL.
Disable ssl on FreeBSD.
Add PROCESS privilege for backups.

####Bugfixes

####Known Bugs
* No known bugs

##2014-03-04 - Supported Release 2.2.3
###Summary

This is a supported release.  This release removes a testing symlink that can
cause trouble on systems where /var is on a seperate filesystem from the
modulepath.

####Features
####Bugfixes
####Known Bugs
* No known bugs

##2014-03-04 - Supported Release 2.2.2
###Summary
This is a supported release. Mostly comprised of enhanced testing, plus a
bugfix for Suse.

####Bugfixes
- PHP bindings on Suse
- Test fixes

####Known Bugs
* No known bugs

##2014-02-19 - Version 2.2.1

###Summary

Minor release that repairs mysql_database{} so that it sees the correct
collation settings (it was only checking the global mysql ones, not the
actual database and constantly setting it over and over since January 22nd).

Also fixes a bunch of tests on various platforms.


##2014-02-13 - Version 2.2.0

###Summary

####Features
- Add `backupdirmode`, `backupdirowner`, `backupdirgroup` to
  mysql::server::backup to allow customizing the mysqlbackupdir.
- Support multiple options of the same name, allowing you to
  do 'replicate-do-db' => ['base1', 'base2', 'base3'] in order to get three
  lines of replicate-do-db = base1, replicate-do-db = base2 etc.

####Bugfixes
- Fix `restart` so it actually stops mysql restarting if set to false.
- DRY out the defaults_file functionality in the providers.
- mysql_grant fixed to work with root@localhost/@.
- mysql_grant fixed for WITH MAX_QUERIES_PER_HOUR
- mysql_grant fixed so revoking all privileges accounts for GRANT OPTION
- mysql_grant fixed to remove duplicate privileges.
- mysql_grant fixed to handle PROCEDURES when removing privileges.
- mysql_database won't try to create existing databases, breaking replication.
- bind_address renamed bind-address in 'mysqld' options.
- key_buffer renamed to key_buffer_size.
- log_error renamed to log-error.
- pid_file renamed to pid-file.
- Ensure mysql::server:root_password runs before mysql::server::backup
- Fix options_override -> override_options in the README.
- Extensively rewrite the README to be accurate and awesome.
- Move to requiring stdlib 3.2.0, shipped in PE3.0
- Add many new tests.


##2013-11-13 - Version 2.1.0

###Summary

The most important changes in 2.1.0 are improvements to the my.cnf creation,
as well as providers.  Setting options to = true strips them to be just the
key name itself, which is required for some options.

The provider updates fix a number of bugs, from lowercase privileges to
deprecation warnings.

Last, the new hiera integration functionality should make it easier to
externalize all your grants, users, and, databases.  Another great set of
community submissions helped to make this release.

####Features
- Some options can not take a argument. Gets rid of the '= true' when an
option is set to true.
- Easier hiera integration:  Add hash parameters to mysql::server to allow
specifying grants, users, and databases.

####Bugfixes
- Fix an issue with lowercase privileges in mysql_grant{} causing them to be reapplied needlessly.
- Changed defaults-file to defaults-extra-file in providers.
- Ensure /root/.my.cnf is 0600 and root owned.
- database_user deprecation warning was incorrect.
- Add anchor pattern for client.pp
- Documentation improvements.
- Various test fixes.


##2013-10-21 - Version 2.0.1

###Summary

This is a bugfix release to handle an issue where unsorted mysql_grant{}
privileges could cause Puppet to incorrectly reapply the permissions on
each run.

####Bugfixes
- Mysql_grant now sorts privileges in the type and provider for comparison.
- Comment and test tweak for PE3.1.


##2013-10-14 - Version 2.0.0

###Summary

(Previously detailed in the changelog for 2.0.0-rc1)

This module has been completely refactored and works significantly different.
The changes are broad and touch almost every piece of the module.

See the README.md for full details of all changes and syntax.
Please remain on 1.0.0 if you don't have time to fully test this in dev.

* mysql::server, mysql::client, and mysql::bindings are the primary interface
classes.
* mysql::server takes an `override_options` parameter to set my.cnf options,
with the hash format: { 'section' => { 'thing' => 'value' }}
* mysql attempts backwards compatibility by forwarding all parameters to
mysql::server.


##2013-10-09 - Version 2.0.0-rc5

###Summary

Hopefully the final rc!  Further fixes to mysql_grant (stripping out the
cleverness so we match a much wider range of input.)

####Bugfixes
- Make mysql_grant accept '.*'@'.*' in terms of input for user@host.


##2013-10-09 - Version 2.0.0-rc4

###Summary

Bugfixes to mysql_grant and mysql_user form the bulk of this rc, as well as
ensuring that values in the override_options hash that contain a value of ''
are created as just "key" in the conf rather than "key =" or "key = false".

####Bugfixes
- Improve mysql_grant to work with IPv6 addresses (both long and short).
- Ensure @host users work as well as user@host users.
- Updated my.cnf template to support items with no values.


##2013-10-07 - Version 2.0.0-rc3

###Summary
Fix mysql::server::monitor's use of mysql_user{}.

####Bugfixes
- Fix myql::server::monitor's use of mysql_user{} to grant the proper
permissions.  Add specs as well.  (Thanks to treydock!)


##2013-10-03 - Version 2.0.0-rc2

###Summary
Bugfixes

####Bugfixes
- Fix a duplicate parameter in mysql::server


##2013-10-03 - Version 2.0.0-rc1

###Summary

This module has been completely refactored and works significantly different.
The changes are broad and touch almost every piece of the module.

See the README.md for full details of all changes and syntax.
Please remain on 1.0.0 if you don't have time to fully test this in dev.

* mysql::server, mysql::client, and mysql::bindings are the primary interface
classes.
* mysql::server takes an `override_options` parameter to set my.cnf options,
with the hash format: { 'section' => { 'thing' => 'value' }}
* mysql attempts backwards compatibility by forwarding all parameters to
mysql::server.

##2013-09-23 - Version 1.0.0

###Summary

This release introduces a number of new type/providers, to eventually
replace the database_ ones.  The module has been converted to call the
new providers rather than the previous ones as they have a number of
fixes, additional options, and work with puppet resource.

This 1.0.0 release precedes a large refactoring that will be released
almost immediately after as 2.0.0.

####Features
- Added mysql_grant, mysql_database, and mysql_user.
- Add `mysql::bindings` class and refactor all other bindings to be contained underneath mysql::bindings:: namespace.
- Added support to back up specified databases only with 'mysqlbackup' parameter.
- Add option to mysql::backup to set the backup script to perform a mysqldump on each database to its own file

####Bugfixes
- Update my.cnf.pass.erb to allow custom socket support
- Add environment variable for .my.cnf in mysql::db.
- Add HOME environment variable for .my.cnf to mysqladmin command when
(re)setting root password

##2013-07-15 - Version 0.9.0
####Features
- Add `mysql::backup::backuprotate` parameter
- Add `mysql::backup::delete_before_dump` parameter
- Add `max_user_connections` attribute to `database_user` type

####Bugfixes
- Add client package dependency for `mysql::db`
- Remove duplicate `expire_logs_days` and `max_binlog_size` settings
- Make root's `.my.cnf` file path dynamic
- Update pidfile path for Suse variants
- Fixes for lint

##2013-07-05 - Version 0.8.1
####Bugfixes
 - Fix a typo in the Fedora 19 support.

##2013-07-01 - Version 0.8.0
####Features
 - mysql::perl class to install perl-DBD-mysql.
 - minor improvements to the providers to improve reliability
 - Install the MariaDB packages on Fedora 19 instead of MySQL.
 - Add new `mysql` class parameters:
   -  `max_connections`: The maximum number of allowed connections.
   -  `manage_config_file`: Opt out of puppetized control of my.cnf.
   -  `ft_min_word_len`: Fine tune the full text search.
   -  `ft_max_word_len`: Fine tune the full text search.
 - Add new `mysql` class performance tuning parameters:
   -  `key_buffer`
   -  `thread_stack`
   -  `thread_cache_size`
   -  `myisam-recover`
   -  `query_cache_limit`
   -  `query_cache_size`
   -  `max_connections`
   -  `tmp_table_size`
   -  `table_open_cache`
   -  `long_query_time`
 - Add new `mysql` class replication parameters:
   -  `server_id`
   -  `sql_log_bin`
   -  `log_bin`
   -  `max_binlog_size`
   -  `binlog_do_db`
   -  `expire_logs_days`
   -  `log_bin_trust_function_creators`
   -  `replicate_ignore_table`
   -  `replicate_wild_do_table`
   -  `replicate_wild_ignore_table`
   -  `expire_logs_days`
   -  `max_binlog_size`

####Bugfixes
 - No longer restart MySQL when /root/.my.cnf changes.
 - Ensure mysql::config runs before any mysql::db defines.

##2013-06-26 - Version 0.7.1
####Bugfixes
- Single-quote password for special characters
- Update travis testing for puppet 3.2.x and missing Bundler gems

##2013-06-25 - Version 0.7.0
This is a maintenance release for community bugfixes and exposing
configuration variables.

* Add new `mysql` class parameters:
  -  `basedir`: The base directory mysql uses
  -  `bind_address`: The IP mysql binds to
  -  `client_package_name`: The name of the mysql client package
  -  `config_file`: The location of the server config file
  -  `config_template`: The template to use to generate my.cnf
  -  `datadir`: The directory MySQL's datafiles are stored
  -  `default_engine`: The default engine to use for tables
  -  `etc_root_password`: Whether or not to add the mysql root password to
 /etc/my.cnf
  -  `java_package_name`: The name of the java package containing the java
 connector
  -  `log_error`: Where to log errors
  -  `manage_service`: Boolean dictating if mysql::server should manage the
 service
  -  `max_allowed_packet`: Maximum network packet size mysqld will accept
  -  `old_root_password`: Previous root user password
  -  `php_package_name`: The name of the phpmysql package to install
  -  `pidfile`: The location mysql will expect the pidfile to be
  -  `port`: The port mysql listens on
  -  `purge_conf_dir`: Value fed to recurse and purge parameters of the
 /etc/mysql/conf.d resource
  -  `python_package_name`: The name of the python mysql package to install
  -  `restart`: Whether to restart mysqld
  -  `root_group`: Use specified group for root-owned files
  -  `root_password`: The root MySQL password to use
  -  `ruby_package_name`: The name of the ruby mysql package to install
  -  `ruby_package_provider`: The installation suite to use when installing the
 ruby package
  -  `server_package_name`: The name of the server package to install
  -  `service_name`: The name of the service to start
  -  `service_provider`: The name of the service provider
  -  `socket`: The location of the MySQL server socket file
  -  `ssl_ca`: The location of the SSL CA Cert
  -  `ssl_cert`: The location of the SSL Certificate to use
  -  `ssl_key`: The SSL key to use
  -  `ssl`: Whether or not to enable ssl
  -  `tmpdir`: The directory MySQL's tmpfiles are stored
* Deprecate `mysql::package_name` parameter in favor of
`mysql::client_package_name`
* Fix local variable template deprecation
* Fix dependency ordering in `mysql::db`
* Fix ANSI quoting in queries
* Fix travis support (but still messy)
* Fix typos

##2013-01-11 - Version 0.6.1
* Fix providers when /root/.my.cnf is absent

##2013-01-09 - Version 0.6.0
* Add `mysql::server::config` define for specific config directives
* Add `mysql::php` class for php support
* Add `backupcompress` parameter to `mysql::backup`
* Add `restart` parameter to `mysql::config`
* Add `purge_conf_dir` parameter to `mysql::config`
* Add `manage_service` parameter to `mysql::server`
* Add syslog logging support via the `log_error` parameter
* Add initial SuSE support
* Fix remove non-localhost root user when fqdn != hostname
* Fix dependency in `mysql::server::monitor`
* Fix .my.cnf path for root user and root password
* Fix ipv6 support for users
* Fix / update various spec tests
* Fix typos
* Fix lint warnings

##2012-08-23 - Version 0.5.0
* Add puppetlabs/stdlib as requirement
* Add validation for mysql privs in provider
* Add `pidfile` parameter to mysql::config
* Add `ensure` parameter to mysql::db
* Add Amazon linux support
* Change `bind_address` parameter to be optional in my.cnf template
* Fix quoting root passwords

##2012-07-24 - Version 0.4.0
* Fix various bugs regarding database names
* FreeBSD support
* Allow specifying the storage engine
* Add a backup class
* Add a security class to purge default accounts

##2012-05-03 - Version 0.3.0
* 14218 Query the database for available privileges
* Add mysql::java class for java connector installation
* Use correct error log location on different distros
* Fix set_mysql_rootpw to properly depend on my.cnf

##2012-04-11 - Version 0.2.0

##2012-03-19 - William Van Hevelingen <blkperl@cat.pdx.edu>
* (#13203) Add ssl support (f7e0ea5)

##2012-03-18 - Nan Liu <nan@puppetlabs.com>
* Travis ci before script needs success exit code. (0ea463b)

##2012-03-18 - Nan Liu <nan@puppetlabs.com>
* Fix Puppet 2.6 compilation issues. (9ebbbc4)

##2012-03-16 - Nan Liu <nan@puppetlabs.com>
* Add travis.ci for testing multiple puppet versions. (33c72ef)

##2012-03-15 - William Van Hevelingen <blkperl@cat.pdx.edu>
* (#13163) Datadir should be configurable (f353fc6)

##2012-03-16 - Nan Liu <nan@puppetlabs.com>
* Document create_resources dependency. (558a59c)

##2012-03-16 - Nan Liu <nan@puppetlabs.com>
* Fix spec test issues related to error message. (eff79b5)

##2012-03-16 - Nan Liu <nan@puppetlabs.com>
* Fix mysql service on Ubuntu. (72da2c5)

##2012-03-16 - Dan Bode <dan@puppetlabs.com>
* Add more spec test coverage (55e399d)

##2012-03-16 - Nan Liu <nan@puppetlabs.com>
* (#11963) Fix spec test due to path changes. (1700349)

##2012-03-07 - François Charlier <fcharlier@ploup.net>
* Add a test to check path for 'mysqld-restart' (b14c7d1)

##2012-03-07 - François Charlier <fcharlier@ploup.net>
* Fix path for 'mysqld-restart' (1a9ae6b)

##2012-03-15 - Dan Bode <dan@puppetlabs.com>
* Add rspec-puppet tests for mysql::config (907331a)

##2012-03-15 - Dan Bode <dan@puppetlabs.com>
* Moved class dependency between sever and config to server (da62ad6)

##2012-03-14 - Dan Bode <dan@puppetlabs.com>
* Notify mysql restart from set_mysql_rootpw exec (0832a2c)

##2012-03-15 - Nan Liu <nan@puppetlabs.com>
* Add documentation related to osfamily fact. (8265d28)

##2012-03-14 - Dan Bode <dan@puppetlabs.com>
* Mention osfamily value in failure message (e472d3b)

##2012-03-14 - Dan Bode <dan@puppetlabs.com>
* Fix bug when querying for all database users (015490c)

##2012-02-09 - Nan Liu <nan@puppetlabs.com>
* Major refactor of mysql module. (b1f90fd)

##2012-01-11 - Justin Ellison <justin.ellison@buckle.com>
* Ruby and Python's MySQL libraries are named differently on different distros. (1e926b4)

##2012-01-11 - Justin Ellison <justin.ellison@buckle.com>
* Per @ghoneycutt, we should fail explicitly and explain why. (09af083)

##2012-01-11 - Justin Ellison <justin.ellison@buckle.com>
* Removing duplicate declaration (7513d03)

##2012-01-10 - Justin Ellison <justin.ellison@buckle.com>
* Use socket value from params class instead of hardcoding. (663e97c)

##2012-01-10 - Justin Ellison <justin.ellison@buckle.com>
* Instead of hardcoding the config file target, pull it from mysql::params (031a47d)

##2012-01-10 - Justin Ellison <justin.ellison@buckle.com>
* Moved $socket to within the case to toggle between distros.  Added a $config_file variable to allow per-distro config file destinations. (360eacd)

##2012-01-10 - Justin Ellison <justin.ellison@buckle.com>
* Pretty sure this is a bug, 99% of Linux distros out there won't ever hit the default. (3462e6b)

##2012-02-09 - William Van Hevelingen <blkperl@cat.pdx.edu>
* Changed the README to use markdown (3b7dfeb)

##2012-02-04 - Daniel Black <grooverdan@users.sourceforge.net>
* (#12412) mysqltuner.pl update (b809e6f)

##2011-11-17 - Matthias Pigulla <mp@webfactory.de>
* (#11363) Add two missing privileges to grant: event_priv, trigger_priv (d15c9d1)

##2011-12-20 - Jeff McCune <jeff@puppetlabs.com>
* (minor) Fixup typos in Modulefile metadata (a0ed6a1)

##2011-12-19 - Carl Caum <carl@carlcaum.com>
* Only notify Exec to import sql if sql is given (0783c74)

##2011-12-19 - Carl Caum <carl@carlcaum.com>
* (#11508) Only load sql_scripts on DB creation (e3b9fd9)

##2011-12-13 - Justin Ellison <justin.ellison@buckle.com>
* Require not needed due to implicit dependencies (3058feb)

##2011-12-13 - Justin Ellison <justin.ellison@buckle.com>
* Bug #11375: puppetlabs-mysql fails on CentOS/RHEL (a557b8d)

##2011-06-03 - Dan Bode <dan@puppetlabs.com> - 0.0.1
* initial commit
source ENV['GEM_SOURCE'] || 'https://rubygems.org'

group :development, :test do
  gem 'mime-types', '<2.0',      :require => false
  gem 'rake',  '10.1.1',         :require => false
  gem 'rspec', '~> 2.11',        :require => false
  gem 'rspec-puppet',            :require => false
  gem 'puppetlabs_spec_helper',  :require => false
  gem 'serverspec',              :require => false
  gem 'puppet-lint',             :require => false
  gem 'pry',                     :require => false
  gem 'simplecov',               :require => false
  gem 'beaker',                  :require => false
  gem 'beaker-rspec', '>= 2.2',  :require => false
end

if puppetversion = ENV['PUPPET_GEM_VERSION']
  gem 'puppet', puppetversion, :require => false
else
  gem 'puppet', :require => false
end

# vim:ft=ruby
                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!) The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright 2013 Puppet Labs

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
#MySQL

####Table of Contents

1. [Overview](#overview)
2. [Module Description - What the module does and why it is useful](#module-description)
3. [Setup - The basics of getting started with mysql](#setup)
    * [What mysql affects](#what-mysql-affects)
    * [Setup requirements](#setup-requirements)
    * [Beginning with mysql](#beginning-with-mysql)
4. [Usage - Configuration options and additional functionality](#usage)
5. [Reference - An under-the-hood peek at what the module is doing and how](#reference)
5. [Limitations - OS compatibility, etc.](#limitations)
6. [Development - Guide for contributing to the module](#development)

##Overview

The mysql module installs, configures, and manages the MySQL service.

##Module Description

The mysql module manages both the installation and configuration of MySQL as
well as extends Puppet to allow management of MySQL resources, such as
databases, users, and grants.

##Backwards Compatibility

This module has just undergone a very large rewrite.  Some new classes have been added, and many previous classes and configurations work differently than before.  We've attempted to handle backwards compatibility automatically by adding a
`attempt_compatibility_mode` parameter to the main mysql class.  If you set
this to 'true' it will attempt to map your previous parameters into the new
`mysql::server` class.

#####WARNING

Compatibility mode may fail. It may eat your MySQL server. PLEASE test it before running it live, even if the test is just a no-op and manual comparison. Please be careful!

##Setup

###What MySQL affects

* MySQL package
* MySQL configuration files
* MySQL service

###Beginning with MySQL

If you just want a server installed with the default options you can run
`include '::mysql::server'`.  

If you need to customize options, such as the root
password or `/etc/my.cnf` settings, then you must also pass in an override hash:

```puppet
class { '::mysql::server':
  root_password    => 'strongpassword',
  override_options => { 'mysqld' => { 'max_connections' => '1024' } }
}
```

##Usage

All interaction for the server is done via `mysql::server`.  To install the
client you use `mysql::client`, and to install bindings you can use
`mysql::bindings`.

###Overrides

The hash structure for overrides in `mysql::server` is as follows:

```puppet
$override_options = {
  'section' => {
    'item'             => 'thing',
  }
}
```

For items that you would traditionally represent as:

<pre>
[section]
thing = X
</pre>

You can just make an entry like `thing => true`, `thing => value`, or `thing => "` in the hash. You can also pass an array `thing => ['value', 'value2']` or even list each `thing => value` separately on separate lines. MySQL doesn't care if 'thing' is alone or set to a value; it'll happily accept both.  To keep an option out of the my.cnf file, e.g. when using override_options to revert to a default value, you can pass thing => undef.
If an option needs multiple instances, you can pass an array. For example

```puppet
$override_options = {
  'mysqld' => {
    'replicate-do-db' => ['base1', 'base2'],
  }
}
```

will produce

<pre>
[mysql]
replicate-do-db = base1
replicate-do-db = base2
</pre>

###Custom configuration

To add custom MySQL configuration, drop additional files into
`/etc/mysql/conf.d/`. Dropping files into conf.d allows you to override settings or add additional ones, which is helpful if you choose not to use `override_options` in `mysql::server`. The conf.d location is hardcoded into the my.cnf template file.

##Reference

###Classes

####Public classes
* `mysql::server`: Installs and configures MySQL.
* `mysql::server::account_security`: Deletes default MySQL accounts.
* `mysql::server::monitor`: Sets up a monitoring user.
* `mysql::server::mysqltuner`: Installs MySQL tuner script.
* `mysql::server::backup`: Sets up MySQL backups via cron.
* `mysql::bindings`: Installs various MySQL language bindings.
* `mysql::client`: Installs MySQL client (for non-servers).

####Private classes
* `mysql::server::install`: Installs packages.
* `mysql::server::config`: Configures MYSQL.
* `mysql::server::service`: Manages service.
* `mysql::server::root_password`: Sets MySQL root password.
* `mysql::server::providers`: Creates users, grants, and databases.
* `mysql::bindings::java`: Installs Java bindings.
* `mysql::bindings::perl`: Installs Perl bindings.
* `mysql::bindings::python`: Installs Python bindings.
* `mysql::bindings::ruby`: Installs Ruby bindings.
* `mysql::client::install`:  Installs MySQL client.

###Parameters

####mysql::server

#####`root_password`

The MySQL root password.  Puppet will attempt to set the root password and update `/root/.my.cnf` with it.

#####`old_root_password`

The previous root password (**REQUIRED** if you wish to change the root password via Puppet.)

#####`override_options`

The hash of override options to pass into MySQL.  It can be structured
like a hash in the my.cnf file, so entries look like

```puppet
$override_options = {
  'section' => {
    'item'             => 'thing',
  }
}
```

For items that you would traditionally represent as:

<pre>
[section]
thing = X
</pre>

You can just make an entry like `thing => true`, `thing => value`, or `thing => "` in the hash. You can also pass an array `thing => ['value', 'value2']` or even list each `thing => value` separately on separate lines. MySQL doesn't care if 'thing' is alone or set to a value; it'll happily accept both.  To keep an option out of the my.cnf file, e.g. when using override_options to revert to a default value, you can pass thing => undef.

#####`config_file`

The location of the MySQL configuration file.

#####`manage_config_file`

Whether the MySQL configuration file should be managed.

#####`purge_conf_dir`

Whether the conf.d directory should be purged.

#####`restart`

Whether the service should be restarted when things change.

#####`root_group`

What is the group used for root?

#####`package_ensure`

What to set the package to.  Can be 'present', 'absent', or 'x.y.z'.

#####`package_name`

The name of the mysql server package to install.

#####`remove_default_accounts`

Boolean to decide if we should automatically include
`mysql::server::account_security`.

#####`service_enabled`

Boolean to decide if the service should be enabled.

#####`service_manage`

Boolean to decide if the service should be managed.

#####`service_name`

The name of the mysql server service.

#####`service_provider`

The provider to use to manage the service.

#####`users`

Optional hash of users to create, which are passed to [mysql_user](#mysql_user). 

```puppet
$users = {
  'someuser@localhost' => {
    ensure                   => 'present',
    max_connections_per_hour => '0',
    max_queries_per_hour     => '0',
    max_updates_per_hour     => '0',
    max_user_connections     => '0',
    password_hash            => '*F3A2A51A9B0F2BE2468926B4132313728C250DBF',
  },
}
```

#####`grants`

Optional hash of grants, which are passed to [mysql_grant](#mysql_grant). 

```puppet
$grants = {
  'someuser@localhost/somedb.*' => {
    ensure     => 'present',
    options    => ['GRANT'],
    privileges => ['SELECT', 'INSERT', 'UPDATE', 'DELETE'],
    table      => 'somedb.*',
    user       => 'someuser@localhost',
  },
}
```

#####`databases`

Optional hash of databases to create, which are passed to [mysql_database](#mysql_database).

```puppet
$databases = {
  'somedb' => {
    ensure  => 'present',
    charset => 'utf8',
  },
}
```

####mysql::server::backup

#####`backupuser`

MySQL user to create for backups.

#####`backuppassword`

MySQL user password for backups.

#####`backupdir`

Directory to back up into.

#####`backupdirmode`

Permissions applied to the backup directory. This parameter is passed directly
to the `file` resource.

#####`backupdirowner`

Owner for the backup directory. This parameter is passed directly to the `file`
resource.

#####`backupdirgroup`

Group owner for the backup directory. This parameter is passed directly to the
`file` resource.

#####`backupcompress`

Boolean to determine if backups should be compressed.

#####`backuprotate`

How many days to keep backups for.

#####`delete_before_dump`

Boolean to determine if you should cleanup before backing up or after.

#####`backupdatabases`

Array of databases to specifically back up.

#####`file_per_database`

Whether a separate file be used per database.

#####`ensure`

Allows you to remove the backup scripts. Can be 'present' or 'absent'.

#####`execpath`

Allows you to set a custom PATH should your mysql installation be non-standard places. Defaults to `/usr/bin:/usr/sbin:/bin:/sbin`

#####`time`

An array of two elements to set the backup time.  Allows ['23', '5'] or ['3', '45'] for HH:MM times.

#####`postscript`

A script that is executed at when the backup is finished. This could be used to (r)sync the backup to a central store. This script can be either a single line that is directly executed or a number of lines, when supplied as an array. It could also be one or more externally managed (executable) files.

####mysql::server::monitor

#####`mysql_monitor_username`

The username to create for MySQL monitoring.

#####`mysql_monitor_password`

The password to create for MySQL monitoring.

#####`mysql_monitor_hostname`

The hostname to allow to access the MySQL monitoring user.

####mysql::bindings

#####`java_enable`

Boolean to decide if the Java bindings should be installed.

#####`perl_enable`

Boolean to decide if the Perl bindings should be installed.

#####`php_enable`

Boolean to decide if the PHP bindings should be installed.

#####`python_enable`

Boolean to decide if the Python bindings should be installed.

#####`ruby_enable`

Boolean to decide if the Ruby bindings should be installed.

#####`java_package_ensure`

What to set the package to.  Can be 'present', 'absent', or 'x.y.z'.

#####`java_package_name`

The name of the package to install.

#####`java_package_provider`

What provider should be used to install the package.

#####`perl_package_ensure`

What to set the package to.  Can be 'present', 'absent', or 'x.y.z'.

#####`perl_package_name`

The name of the package to install.

#####`perl_package_provider`

What provider should be used to install the package.

#####`python_package_ensure`

What to set the package to.  Can be 'present', 'absent', or 'x.y.z'.

#####`python_package_name`

The name of the package to install.

#####`python_package_provider`

What provider should be used to install the package.

#####`ruby_package_ensure`

What to set the package to.  Can be 'present', 'absent', or 'x.y.z'.

#####`ruby_package_name`

The name of the package to install.

#####`ruby_package_provider`

What provider should be used to install the package.

####mysql::client

#####`bindings_enable`

Boolean to automatically install all bindings.

#####`package_ensure`

What to set the package to.  Can be 'present', 'absent', or 'x.y.z'.

#####`package_name`

What is the name of the mysql client package to install.

###Defines

####mysql::db

Creates a database with a user and assigns some privileges.

```puppet
    mysql::db { 'mydb':
      user     => 'myuser',
      password => 'mypass',
      host     => 'localhost',
      grant    => ['SELECT', 'UPDATE'],
    }
```

Or using a different resource name with exported resources,

```puppet
    @@mysql::db { "mydb_${fqdn}":
      user     => 'myuser',
      password => 'mypass',
      dbname   => 'mydb',
      host     => ${fqdn},
      grant    => ['SELECT', 'UPDATE'],
      tag      => $domain,
    }
```

Then collect it on the remote DB server.

```puppet
    Mysql::Db <<| tag == $domain |>>
```

###Providers

####mysql_database

`mysql_database` can be used to create and manage databases within MySQL.

```puppet
mysql_database { 'information_schema':
  ensure  => 'present',
  charset => 'utf8',
  collate => 'utf8_swedish_ci',
}
mysql_database { 'mysql':
  ensure  => 'present',
  charset => 'latin1',
  collate => 'latin1_swedish_ci',
}
```

####mysql_user

`mysql_user` can be used to create and manage user grants within MySQL.

```puppet
mysql_user { 'root@127.0.0.1':
  ensure                   => 'present',
  max_connections_per_hour => '0',
  max_queries_per_hour     => '0',
  max_updates_per_hour     => '0',
  max_user_connections     => '0',
}
```

####mysql_grant

`mysql_grant` can be used to create grant permissions to access databases within
MySQL.  To use it you must create the title of the resource as shown below,
following the pattern of `username@hostname/database.table`:

```puppet
mysql_grant { 'root@localhost/*.*':
  ensure     => 'present',
  options    => ['GRANT'],
  privileges => ['ALL'],
  table      => '*.*',
  user       => 'root@localhost',
}
```

##Limitations

This module has been tested on:

* RedHat Enterprise Linux 5/6
* Debian 6/7
* CentOS 5/6
* Ubuntu 12.04

Testing on other platforms has been light and cannot be guaranteed.

#Development

Puppet Labs modules on the Puppet Forge are open projects, and community
contributions are essential for keeping them great. We can’t access the
huge number of platforms and myriad of hardware, software, and deployment
configurations that Puppet is intended to serve.

We want to keep it as easy as possible to contribute changes so that our
modules work in your environment. There are a few guidelines that we need
contributors to follow so that we can have a chance of keeping on top of things.

You can read the complete module contribution guide [on the Puppet Labs wiki.](http://projects.puppetlabs.com/projects/module-site/wiki/Module_contributing)

### Authors

This module is based on work by David Schmitt. The following contributors have contributed patches to this module (beyond Puppet Labs):

* Larry Ludwig
* Christian G. Warden
* Daniel Black
* Justin Ellison
* Lowe Schmidt
* Matthias Pigulla
* William Van Hevelingen
* Michael Arnold
* Chris Weyl

require 'puppetlabs_spec_helper/rake_tasks'
The best that I can tell is that this code traces back to David Schmitt. It has been forked many times since then :)

1. you cannot add databases to an instance that has a root password
2. you have to specify username as USER@BLAH or it cannot be found
3. mysql_grant does not complain if user does not exist
4. Needs support for pre-seeding on debian
5. the types may need to take user/password
6. rather or not to configure /etc/.my.cnf should be configurable
#!/usr/bin/perl -w
# mysqltuner.pl - Version 1.2.0
# High Performance MySQL Tuning Script
# Copyright (C) 2006-2011 Major Hayden - major@mhtx.net
#
# For the latest updates, please visit http://mysqltuner.com/
# Git repository available at http://github.com/rackerhacker/MySQLTuner-perl
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
# This project would not be possible without help from:
#   Matthew Montgomery     Paul Kehrer          Dave Burgess
#   Jonathan Hinds         Mike Jackson         Nils Breunese
#   Shawn Ashlee           Luuk Vosslamber      Ville Skytta
#   Trent Hornibrook       Jason Gill           Mark Imbriaco
#   Greg Eden              Aubin Galinotti      Giovanni Bechis
#   Bill Bradford          Ryan Novosielski     Michael Scheidell
#   Blair Christensen      Hans du Plooy        Victor Trac
#   Everett Barnes         Tom Krouper          Gary Barrueto
#   Simon Greenaway        Adam Stein           Isart Montane
#   Baptiste M.
#
# Inspired by Matthew Montgomery's tuning-primer.sh script:
# http://forge.mysql.com/projects/view.php?id=44
#
use strict;
use warnings;
use diagnostics;
use File::Spec;
use Getopt::Long;

# Set up a few variables for use in the script
my $tunerversion = "1.2.0";
my (@adjvars, @generalrec);

# Set defaults
my %opt = (
		"nobad" 		=> 0,
		"nogood" 		=> 0,
		"noinfo" 		=> 0,
		"nocolor" 		=> 0,
		"forcemem" 		=> 0,
		"forceswap" 	=> 0,
		"host" 			=> 0,
		"socket" 		=> 0,
		"port" 			=> 0,
		"user" 			=> 0,
		"pass"			=> 0,
		"skipsize" 		=> 0,
		"checkversion" 	=> 0,
	);

# Gather the options from the command line
GetOptions(\%opt,
		'nobad',
		'nogood',
		'noinfo',
		'nocolor',
		'forcemem=i',
		'forceswap=i',
		'host=s',
		'socket=s',
		'port=i',
		'user=s',
		'pass=s',
		'skipsize',
		'checkversion',
		'help',
	);

if (defined $opt{'help'} && $opt{'help'} == 1) { usage(); }

sub usage {
	# Shown with --help option passed
	print "\n".
		"   MySQLTuner $tunerversion - MySQL High Performance Tuning Script\n".
		"   Bug reports, feature requests, and downloads at http://mysqltuner.com/\n".
		"   Maintained by Major Hayden (major\@mhtx.net) - Licensed under GPL\n".
		"\n".
		"   Important Usage Guidelines:\n".
		"      To run the script with the default options, run the script without arguments\n".
		"      Allow MySQL server to run for at least 24-48 hours before trusting suggestions\n".
		"      Some routines may require root level privileges (script will provide warnings)\n".
		"      You must provide the remote server's total memory when connecting to other servers\n".
		"\n".
		"   Connection and Authentication\n".
		"      --host <hostname>    Connect to a remote host to perform tests (default: localhost)\n".
		"      --socket <socket>    Use a different socket for a local connection\n".
		"      --port <port>        Port to use for connection (default: 3306)\n".
		"      --user <username>    Username to use for authentication\n".
		"      --pass <password>    Password to use for authentication\n".
		"\n".
		"   Performance and Reporting Options\n".
		"      --skipsize           Don't enumerate tables and their types/sizes (default: on)\n".
		"                             (Recommended for servers with many tables)\n".
		"      --checkversion       Check for updates to MySQLTuner (default: don't check)\n".
		"      --forcemem <size>    Amount of RAM installed in megabytes\n".
		"      --forceswap <size>   Amount of swap memory configured in megabytes\n".
		"\n".
		"   Output Options:\n".
		"      --nogood             Remove OK responses\n".
		"      --nobad              Remove negative/suggestion responses\n".
		"      --noinfo             Remove informational responses\n".
		"      --nocolor            Don't print output in color\n".
		"\n";
	exit;
}

my $devnull = File::Spec->devnull();

# Setting up the colors for the print styles
my $good = ($opt{nocolor} == 0)? "[\e[0;32mOK\e[0m]" : "[OK]" ;
my $bad = ($opt{nocolor} == 0)? "[\e[0;31m!!\e[0m]" : "[!!]" ;
my $info = ($opt{nocolor} == 0)? "[\e[0;34m--\e[0m]" : "[--]" ;

# Functions that handle the print styles
sub goodprint { print $good." ".$_[0] unless ($opt{nogood} == 1); }
sub infoprint { print $info." ".$_[0] unless ($opt{noinfo} == 1); }
sub badprint { print $bad." ".$_[0] unless ($opt{nobad} == 1); }
sub redwrap { return ($opt{nocolor} == 0)? "\e[0;31m".$_[0]."\e[0m" : $_[0] ; }
sub greenwrap { return ($opt{nocolor} == 0)? "\e[0;32m".$_[0]."\e[0m" : $_[0] ; }

# Calculates the parameter passed in bytes, and then rounds it to one decimal place
sub hr_bytes {
	my $num = shift;
	if ($num >= (1024**3)) { #GB
		return sprintf("%.1f",($num/(1024**3)))."G";
	} elsif ($num >= (1024**2)) { #MB
		return sprintf("%.1f",($num/(1024**2)))."M";
	} elsif ($num >= 1024) { #KB
		return sprintf("%.1f",($num/1024))."K";
	} else {
		return $num."B";
	}
}

# Calculates the parameter passed in bytes, and then rounds it to the nearest integer
sub hr_bytes_rnd {
	my $num = shift;
	if ($num >= (1024**3)) { #GB
		return int(($num/(1024**3)))."G";
	} elsif ($num >= (1024**2)) { #MB
		return int(($num/(1024**2)))."M";
	} elsif ($num >= 1024) { #KB
		return int(($num/1024))."K";
	} else {
		return $num."B";
	}
}

# Calculates the parameter passed to the nearest power of 1000, then rounds it to the nearest integer
sub hr_num {
	my $num = shift;
	if ($num >= (1000**3)) { # Billions
		return int(($num/(1000**3)))."B";
	} elsif ($num >= (1000**2)) { # Millions
		return int(($num/(1000**2)))."M";
	} elsif ($num >= 1000) { # Thousands
		return int(($num/1000))."K";
	} else {
		return $num;
	}
}

# Calculates uptime to display in a more attractive form
sub pretty_uptime {
	my $uptime = shift;
	my $seconds = $uptime % 60;
	my $minutes = int(($uptime % 3600) / 60);
	my $hours = int(($uptime % 86400) / (3600));
	my $days = int($uptime / (86400));
	my $uptimestring;
	if ($days > 0) {
		$uptimestring = "${days}d ${hours}h ${minutes}m ${seconds}s";
	} elsif ($hours > 0) {
		$uptimestring = "${hours}h ${minutes}m ${seconds}s";
	} elsif ($minutes > 0) {
		$uptimestring = "${minutes}m ${seconds}s";
	} else {
		$uptimestring = "${seconds}s";
	}
	return $uptimestring;
}

# Retrieves the memory installed on this machine
my ($physical_memory,$swap_memory,$duflags);
sub os_setup {
	sub memerror {
		badprint "Unable to determine total memory/swap; use '--forcemem' and '--forceswap'\n";
		exit;
	}
	my $os = `uname`;
	$duflags = ($os =~ /Linux/) ? '-b' : '';
	if ($opt{'forcemem'} > 0) {
		$physical_memory = $opt{'forcemem'} * 1048576;
		infoprint "Assuming $opt{'forcemem'} MB of physical memory\n";
		if ($opt{'forceswap'} > 0) {
			$swap_memory = $opt{'forceswap'} * 1048576;
			infoprint "Assuming $opt{'forceswap'} MB of swap space\n";
		} else {
			$swap_memory = 0;
			badprint "Assuming 0 MB of swap space (use --forceswap to specify)\n";
		}
	} else {
		if ($os =~ /Linux/) {
			$physical_memory = `free -b | grep Mem | awk '{print \$2}'` or memerror;
			$swap_memory = `free -b | grep Swap | awk '{print \$2}'` or memerror;
		} elsif ($os =~ /Darwin/) {
			$physical_memory = `sysctl -n hw.memsize` or memerror;
			$swap_memory = `sysctl -n vm.swapusage | awk '{print \$3}' | sed 's/\..*\$//'` or memerror;
		} elsif ($os =~ /NetBSD|OpenBSD/) {
			$physical_memory = `sysctl -n hw.physmem` or memerror;
			if ($physical_memory < 0) {
				$physical_memory = `sysctl -n hw.physmem64` or memerror;
			}
			$swap_memory = `swapctl -l | grep '^/' | awk '{ s+= \$2 } END { print s }'` or memerror;
		} elsif ($os =~ /BSD/) {
			$physical_memory = `sysctl -n hw.realmem`;
			$swap_memory = `swapinfo | grep '^/' | awk '{ s+= \$2 } END { print s }'`;
		} elsif ($os =~ /SunOS/) {
			$physical_memory = `/usr/sbin/prtconf | grep Memory | cut -f 3 -d ' '` or memerror;
			chomp($physical_memory);
			$physical_memory = $physical_memory*1024*1024;
		} elsif ($os =~ /AIX/) {
			$physical_memory = `lsattr -El sys0 | grep realmem | awk '{print \$2}'` or memerror;
			chomp($physical_memory);
			$physical_memory = $physical_memory*1024;
			$swap_memory = `lsps -as | awk -F"(MB| +)" '/MB /{print \$2}'` or memerror;
			chomp($swap_memory);
			$swap_memory = $swap_memory*1024*1024;
		}
	}
	chomp($physical_memory);
}

# Checks to see if a MySQL login is possible
my ($mysqllogin,$doremote,$remotestring);
sub mysql_setup {
	$doremote = 0;
	$remotestring = '';
	my $command = `which mysqladmin`;
	chomp($command);
	if (! -e $command) {
		badprint "Unable to find mysqladmin in your \$PATH.  Is MySQL installed?\n";
		exit;
	}
	# Are we being asked to connect via a socket?
	if ($opt{socket} ne 0) {
		$remotestring = " -S $opt{socket}";
	}
	# Are we being asked to connect to a remote server?
	if ($opt{host} ne 0) {
		chomp($opt{host});
		$opt{port} = ($opt{port} eq 0)? 3306 : $opt{port} ;
		# If we're doing a remote connection, but forcemem wasn't specified, we need to exit
		if ($opt{'forcemem'} eq 0) {
			badprint "The --forcemem option is required for remote connections\n";
			exit;
		}
		infoprint "Performing tests on $opt{host}:$opt{port}\n";
		$remotestring = " -h $opt{host} -P $opt{port}";
		$doremote = 1;
	}
	# Did we already get a username and password passed on the command line?
	if ($opt{user} ne 0 and $opt{pass} ne 0) {
		$mysqllogin = "-u $opt{user} -p'$opt{pass}'".$remotestring;
		my $loginstatus = `mysqladmin ping $mysqllogin 2>&1`;
		if ($loginstatus =~ /mysqld is alive/) {
			goodprint "Logged in using credentials passed on the command line\n";
			return 1;
		} else {
			badprint "Attempted to use login credentials, but they were invalid\n";
			exit 0;
		}
	}
	if ( -r "/etc/psa/.psa.shadow" and $doremote == 0 ) {
		# It's a Plesk box, use the available credentials
		$mysqllogin = "-u admin -p`cat /etc/psa/.psa.shadow`";
		my $loginstatus = `mysqladmin ping $mysqllogin 2>&1`;
		unless ($loginstatus =~ /mysqld is alive/) {
			badprint "Attempted to use login credentials from Plesk, but they failed.\n";
			exit 0;
		}
	} elsif ( -r "/etc/mysql/debian.cnf" and $doremote == 0 ){
		# We have a debian maintenance account, use it
		$mysqllogin = "--defaults-extra-file=/etc/mysql/debian.cnf";
		my $loginstatus = `mysqladmin $mysqllogin ping 2>&1`;
		if ($loginstatus =~ /mysqld is alive/) {
			goodprint "Logged in using credentials from debian maintenance account.\n";
			return 1;
		} else {
			badprint "Attempted to use login credentials from debian maintenance account, but they failed.\n";
			exit 0;
		}
	} else {
		# It's not Plesk or debian, we should try a login
		my $loginstatus = `mysqladmin $remotestring ping 2>&1`;
		if ($loginstatus =~ /mysqld is alive/) {
			# Login went just fine
			$mysqllogin = " $remotestring ";
			# Did this go well because of a .my.cnf file or is there no password set?
			my $userpath = `printenv HOME`;
			if (length($userpath) > 0) {
				chomp($userpath);
			}
			unless ( -e "${userpath}/.my.cnf" ) {
				badprint "Successfully authenticated with no password - SECURITY RISK!\n";
			}
			return 1;
		} else {
			print STDERR "Please enter your MySQL administrative login: ";
			my $name = <>;
			print STDERR "Please enter your MySQL administrative password: ";
			system("stty -echo >$devnull 2>&1");
			my $password = <>;
			system("stty echo >$devnull 2>&1");
			chomp($password);
			chomp($name);
			$mysqllogin = "-u $name";
			if (length($password) > 0) {
				$mysqllogin .= " -p'$password'";
			}
			$mysqllogin .= $remotestring;
			my $loginstatus = `mysqladmin ping $mysqllogin 2>&1`;
			if ($loginstatus =~ /mysqld is alive/) {
				print STDERR "\n";
				if (! length($password)) {
					# Did this go well because of a .my.cnf file or is there no password set?
					my $userpath = `ls -d ~`;
					chomp($userpath);
					unless ( -e "$userpath/.my.cnf" ) {
						badprint "Successfully authenticated with no password - SECURITY RISK!\n";
					}
				}
				return 1;
			} else {
				print "\n".$bad." Attempted to use login credentials, but they were invalid.\n";
				exit 0;
			}
			exit 0;
		}
	}
}

# Populates all of the variable and status hashes
my (%mystat,%myvar,$dummyselect);
sub get_all_vars {
	# We need to initiate at least one query so that our data is useable
	$dummyselect = `mysql $mysqllogin -Bse "SELECT VERSION();"`;
	my @mysqlvarlist = `mysql $mysqllogin -Bse "SHOW /*!50000 GLOBAL */ VARIABLES;"`;
	foreach my $line (@mysqlvarlist) {
		$line =~ /([a-zA-Z_]*)\s*(.*)/;
		$myvar{$1} = $2;
	}
	my @mysqlstatlist = `mysql $mysqllogin -Bse "SHOW /*!50000 GLOBAL */ STATUS;"`;
	foreach my $line (@mysqlstatlist) {
		$line =~ /([a-zA-Z_]*)\s*(.*)/;
		$mystat{$1} = $2;
	}
	# Workaround for MySQL bug #59393 wrt. ignore-builtin-innodb
	if (($myvar{'ignore_builtin_innodb'} || "") eq "ON") {
		$myvar{'have_innodb'} = "NO";
	}
	# have_* for engines is deprecated and will be removed in MySQL 5.6;
	# check SHOW ENGINES and set corresponding old style variables.
	# Also works around MySQL bug #59393 wrt. skip-innodb
	my @mysqlenginelist = `mysql $mysqllogin -Bse "SHOW ENGINES;" 2>$devnull`;
	foreach my $line (@mysqlenginelist) {
		if ($line =~ /^([a-zA-Z_]+)\s+(\S+)/) {
			my $engine = lc($1);
			if ($engine eq "federated" || $engine eq "blackhole") {
				$engine .= "_engine";
			} elsif ($engine eq "berkeleydb") {
				$engine = "bdb";
			}
			my $val = ($2 eq "DEFAULT") ? "YES" : $2;
			$myvar{"have_$engine"} = $val;
		}
	}
}

sub security_recommendations {
	print "\n-------- Security Recommendations  -------------------------------------------\n";
	my @mysqlstatlist = `mysql $mysqllogin -Bse "SELECT CONCAT(user, '\@', host) FROM mysql.user WHERE password = '' OR password IS NULL;"`;
	if (@mysqlstatlist) {
		foreach my $line (sort @mysqlstatlist) {
			chomp($line);
			badprint "User '".$line."' has no password set.\n";
		}
	} else {
		goodprint "All database users have passwords assigned\n";
	}
}

sub get_replication_status {
	my $slave_status = `mysql $mysqllogin -Bse "show slave status\\G"`;
	my ($io_running) = ($slave_status =~ /slave_io_running\S*\s+(\S+)/i);
	my ($sql_running) = ($slave_status =~ /slave_sql_running\S*\s+(\S+)/i);
	if ($io_running eq 'Yes' && $sql_running eq 'Yes') {
		if ($myvar{'read_only'} eq 'OFF') {
			badprint "This replication slave is running with the read_only option disabled.";
		} else {
			goodprint "This replication slave is running with the read_only option enabled.";
		}
	}
}

# Checks for updates to MySQLTuner
sub validate_tuner_version {
	print "\n-------- General Statistics --------------------------------------------------\n";
	if ($opt{checkversion} eq 0) {
		infoprint "Skipped version check for MySQLTuner script\n";
		return;
	}
	my $update;
	my $url = "http://mysqltuner.com/versioncheck.php?v=$tunerversion";
	if (-e "/usr/bin/curl") {
		$update = `/usr/bin/curl --connect-timeout 5 '$url' 2>$devnull`;
		chomp($update);
	} elsif (-e "/usr/bin/wget") {
		$update = `/usr/bin/wget -e timestamping=off -T 5 -O - '$url' 2>$devnull`;
		chomp($update);
	}
	if ($update eq 1) {
		badprint "There is a new version of MySQLTuner available\n";
	} elsif ($update eq 0) {
		goodprint "You have the latest version of MySQLTuner\n";
	} else {
		infoprint "Unable to check for the latest MySQLTuner version\n";
	}
}

# Checks for supported or EOL'ed MySQL versions
my ($mysqlvermajor,$mysqlverminor);
sub validate_mysql_version {
	($mysqlvermajor,$mysqlverminor) = $myvar{'version'} =~ /(\d)\.(\d)/;
	if (!mysql_version_ge(5)) {
		badprint "Your MySQL version ".$myvar{'version'}." is EOL software!  Upgrade soon!\n";
	} elsif (mysql_version_ge(6)) {
		badprint "Currently running unsupported MySQL version ".$myvar{'version'}."\n";
	} else {
		goodprint "Currently running supported MySQL version ".$myvar{'version'}."\n";
	}
}

# Checks if MySQL version is greater than equal to (major, minor)
sub mysql_version_ge {
	my ($maj, $min) = @_;
	return $mysqlvermajor > $maj || ($mysqlvermajor == $maj && $mysqlverminor >= ($min || 0));
}

# Checks for 32-bit boxes with more than 2GB of RAM
my ($arch);
sub check_architecture {
	if ($doremote eq 1) { return; }
	if (`uname` =~ /SunOS/ && `isainfo -b` =~ /64/) {
		$arch = 64;
		goodprint "Operating on 64-bit architecture\n";
	} elsif (`uname` !~ /SunOS/ && `uname -m` =~ /64/) {
		$arch = 64;
		goodprint "Operating on 64-bit architecture\n";
	} elsif (`uname` =~ /AIX/ && `bootinfo -K` =~ /64/) {
		$arch = 64;
		goodprint "Operating on 64-bit architecture\n";
	} else {
		$arch = 32;
		if ($physical_memory > 2147483648) {
			badprint "Switch to 64-bit OS - MySQL cannot currently use all of your RAM\n";
		} else {
			goodprint "Operating on 32-bit architecture with less than 2GB RAM\n";
		}
	}
}

# Start up a ton of storage engine counts/statistics
my (%enginestats,%enginecount,$fragtables);
sub check_storage_engines {
	if ($opt{skipsize} eq 1) {
		print "\n-------- Storage Engine Statistics -------------------------------------------\n";
		infoprint "Skipped due to --skipsize option\n";
		return;
	}
	print "\n-------- Storage Engine Statistics -------------------------------------------\n";
	infoprint "Status: ";
	my $engines;
	$engines .= (defined $myvar{'have_archive'} && $myvar{'have_archive'} eq "YES")? greenwrap "+Archive " : redwrap "-Archive " ;
	$engines .= (defined $myvar{'have_bdb'} && $myvar{'have_bdb'} eq "YES")? greenwrap "+BDB " : redwrap "-BDB " ;
	$engines .= (defined $myvar{'have_federated_engine'} && $myvar{'have_federated_engine'} eq "YES")? greenwrap "+Federated " : redwrap "-Federated " ;
	$engines .= (defined $myvar{'have_innodb'} && $myvar{'have_innodb'} eq "YES")? greenwrap "+InnoDB " : redwrap "-InnoDB " ;
	$engines .= (defined $myvar{'have_isam'} && $myvar{'have_isam'} eq "YES")? greenwrap "+ISAM " : redwrap "-ISAM " ;
	$engines .= (defined $myvar{'have_ndbcluster'} && $myvar{'have_ndbcluster'} eq "YES")? greenwrap "+NDBCluster " : redwrap "-NDBCluster " ;
	print "$engines\n";
	if (mysql_version_ge(5)) {
		# MySQL 5 servers can have table sizes calculated quickly from information schema
		my @templist = `mysql $mysqllogin -Bse "SELECT ENGINE,SUM(DATA_LENGTH),COUNT(ENGINE) FROM information_schema.TABLES WHERE TABLE_SCHEMA NOT IN ('information_schema','mysql') AND ENGINE IS NOT NULL GROUP BY ENGINE ORDER BY ENGINE ASC;"`;
		foreach my $line (@templist) {
			my ($engine,$size,$count);
			($engine,$size,$count) = $line =~ /([a-zA-Z_]*)\s+(\d+)\s+(\d+)/;
			if (!defined($size)) { next; }
			$enginestats{$engine} = $size;
			$enginecount{$engine} = $count;
		}
		$fragtables = `mysql $mysqllogin -Bse "SELECT COUNT(TABLE_NAME) FROM information_schema.TABLES WHERE TABLE_SCHEMA NOT IN ('information_schema','mysql') AND Data_free > 0 AND NOT ENGINE='MEMORY';"`;
		chomp($fragtables);
	} else {
		# MySQL < 5 servers take a lot of work to get table sizes
		my @tblist;
		# Now we build a database list, and loop through it to get storage engine stats for tables
		my @dblist = `mysql $mysqllogin -Bse "SHOW DATABASES"`;
		foreach my $db (@dblist) {
			chomp($db);
			if ($db eq "information_schema") { next; }
			my @ixs = (1, 6, 9);
			if (!mysql_version_ge(4, 1)) {
				# MySQL 3.23/4.0 keeps Data_Length in the 5th (0-based) column
				@ixs = (1, 5, 8);
			}
			push(@tblist, map { [ (split)[@ixs] ] } `mysql $mysqllogin -Bse "SHOW TABLE STATUS FROM \\\`$db\\\`"`);
		}
		# Parse through the table list to generate storage engine counts/statistics
		$fragtables = 0;
		foreach my $tbl (@tblist) {
			my ($engine, $size, $datafree) = @$tbl;
			if (defined $enginestats{$engine}) {
				$enginestats{$engine} += $size;
				$enginecount{$engine} += 1;
			} else {
				$enginestats{$engine} = $size;
				$enginecount{$engine} = 1;
			}
			if ($datafree > 0) {
				$fragtables++;
			}
		}
	}
	while (my ($engine,$size) = each(%enginestats)) {
		infoprint "Data in $engine tables: ".hr_bytes_rnd($size)." (Tables: ".$enginecount{$engine}.")"."\n";
	}
	# If the storage engine isn't being used, recommend it to be disabled
	if (!defined $enginestats{'InnoDB'} && defined $myvar{'have_innodb'} && $myvar{'have_innodb'} eq "YES") {
		badprint "InnoDB is enabled but isn't being used\n";
		push(@generalrec,"Add skip-innodb to MySQL configuration to disable InnoDB");
	}
	if (!defined $enginestats{'BerkeleyDB'} && defined $myvar{'have_bdb'} && $myvar{'have_bdb'} eq "YES") {
		badprint "BDB is enabled but isn't being used\n";
		push(@generalrec,"Add skip-bdb to MySQL configuration to disable BDB");
	}
	if (!defined $enginestats{'ISAM'} && defined $myvar{'have_isam'} && $myvar{'have_isam'} eq "YES") {
		badprint "ISAM is enabled but isn't being used\n";
		push(@generalrec,"Add skip-isam to MySQL configuration to disable ISAM (MySQL > 4.1.0)");
	}
	# Fragmented tables
	if ($fragtables > 0) {
		badprint "Total fragmented tables: $fragtables\n";
		push(@generalrec,"Run OPTIMIZE TABLE to defragment tables for better performance");
	} else {
		goodprint "Total fragmented tables: $fragtables\n";
	}
}

my %mycalc;
sub calculations {
	if ($mystat{'Questions'} < 1) {
		badprint "Your server has not answered any queries - cannot continue...";
		exit 0;
	}
	# Per-thread memory
	if (mysql_version_ge(4)) {
		$mycalc{'per_thread_buffers'} = $myvar{'read_buffer_size'} + $myvar{'read_rnd_buffer_size'} + $myvar{'sort_buffer_size'} + $myvar{'thread_stack'} + $myvar{'join_buffer_size'};
	} else {
		$mycalc{'per_thread_buffers'} = $myvar{'record_buffer'} + $myvar{'record_rnd_buffer'} + $myvar{'sort_buffer'} + $myvar{'thread_stack'} + $myvar{'join_buffer_size'};
	}
	$mycalc{'total_per_thread_buffers'} = $mycalc{'per_thread_buffers'} * $myvar{'max_connections'};
	$mycalc{'max_total_per_thread_buffers'} = $mycalc{'per_thread_buffers'} * $mystat{'Max_used_connections'};

	# Server-wide memory
	$mycalc{'max_tmp_table_size'} = ($myvar{'tmp_table_size'} > $myvar{'max_heap_table_size'}) ? $myvar{'max_heap_table_size'} : $myvar{'tmp_table_size'} ;
	$mycalc{'server_buffers'} = $myvar{'key_buffer_size'} + $mycalc{'max_tmp_table_size'};
	$mycalc{'server_buffers'} += (defined $myvar{'innodb_buffer_pool_size'}) ? $myvar{'innodb_buffer_pool_size'} : 0 ;
	$mycalc{'server_buffers'} += (defined $myvar{'innodb_additional_mem_pool_size'}) ? $myvar{'innodb_additional_mem_pool_size'} : 0 ;
	$mycalc{'server_buffers'} += (defined $myvar{'innodb_log_buffer_size'}) ? $myvar{'innodb_log_buffer_size'} : 0 ;
	$mycalc{'server_buffers'} += (defined $myvar{'query_cache_size'}) ? $myvar{'query_cache_size'} : 0 ;

	# Global memory
	$mycalc{'max_used_memory'} = $mycalc{'server_buffers'} + $mycalc{"max_total_per_thread_buffers"};
	$mycalc{'total_possible_used_memory'} = $mycalc{'server_buffers'} + $mycalc{'total_per_thread_buffers'};
	$mycalc{'pct_physical_memory'} = int(($mycalc{'total_possible_used_memory'} * 100) / $physical_memory);

	# Slow queries
	$mycalc{'pct_slow_queries'} = int(($mystat{'Slow_queries'}/$mystat{'Questions'}) * 100);

	# Connections
	$mycalc{'pct_connections_used'} = int(($mystat{'Max_used_connections'}/$myvar{'max_connections'}) * 100);
	$mycalc{'pct_connections_used'} = ($mycalc{'pct_connections_used'} > 100) ? 100 : $mycalc{'pct_connections_used'} ;

	# Key buffers
	if (mysql_version_ge(4, 1)) {
		$mycalc{'pct_key_buffer_used'} = sprintf("%.1f",(1 - (($mystat{'Key_blocks_unused'} * $myvar{'key_cache_block_size'}) / $myvar{'key_buffer_size'})) * 100);
	}
	if ($mystat{'Key_read_requests'} > 0) {
		$mycalc{'pct_keys_from_mem'} = sprintf("%.1f",(100 - (($mystat{'Key_reads'} / $mystat{'Key_read_requests'}) * 100)));
	} else {
	    $mycalc{'pct_keys_from_mem'} = 0;
	}
	if ($doremote eq 0 and !mysql_version_ge(5)) {
		my $size = 0;
		$size += (split)[0] for `find $myvar{'datadir'} -name "*.MYI" 2>&1 | xargs du -L $duflags 2>&1`;
		$mycalc{'total_myisam_indexes'} = $size;
	} elsif (mysql_version_ge(5)) {
		$mycalc{'total_myisam_indexes'} = `mysql $mysqllogin -Bse "SELECT IFNULL(SUM(INDEX_LENGTH),0) FROM information_schema.TABLES WHERE TABLE_SCHEMA NOT IN ('information_schema') AND ENGINE = 'MyISAM';"`;
	}
	if (defined $mycalc{'total_myisam_indexes'} and $mycalc{'total_myisam_indexes'} == 0) {
		$mycalc{'total_myisam_indexes'} = "fail";
	} elsif (defined $mycalc{'total_myisam_indexes'}) {
		chomp($mycalc{'total_myisam_indexes'});
	}

	# Query cache
	if (mysql_version_ge(4)) {
		$mycalc{'query_cache_efficiency'} = sprintf("%.1f",($mystat{'Qcache_hits'} / ($mystat{'Com_select'} + $mystat{'Qcache_hits'})) * 100);
		if ($myvar{'query_cache_size'}) {
			$mycalc{'pct_query_cache_used'} = sprintf("%.1f",100 - ($mystat{'Qcache_free_memory'} / $myvar{'query_cache_size'}) * 100);
		}
	if ($mystat{'Qcache_lowmem_prunes'} == 0) {
			$mycalc{'query_cache_prunes_per_day'} = 0;
		} else {
			$mycalc{'query_cache_prunes_per_day'} = int($mystat{'Qcache_lowmem_prunes'} / ($mystat{'Uptime'}/86400));
		}
	}

	# Sorting
	$mycalc{'total_sorts'} = $mystat{'Sort_scan'} + $mystat{'Sort_range'};
	if ($mycalc{'total_sorts'} > 0) {
		$mycalc{'pct_temp_sort_table'} = int(($mystat{'Sort_merge_passes'} / $mycalc{'total_sorts'}) * 100);
	}

	# Joins
	$mycalc{'joins_without_indexes'} = $mystat{'Select_range_check'} + $mystat{'Select_full_join'};
	$mycalc{'joins_without_indexes_per_day'} = int($mycalc{'joins_without_indexes'} / ($mystat{'Uptime'}/86400));

	# Temporary tables
	if ($mystat{'Created_tmp_tables'} > 0) {
		if ($mystat{'Created_tmp_disk_tables'} > 0) {
			$mycalc{'pct_temp_disk'} = int(($mystat{'Created_tmp_disk_tables'} / ($mystat{'Created_tmp_tables'} + $mystat{'Created_tmp_disk_tables'})) * 100);
		} else {
			$mycalc{'pct_temp_disk'} = 0;
		}
	}

	# Table cache
	if ($mystat{'Opened_tables'} > 0) {
		$mycalc{'table_cache_hit_rate'} = int($mystat{'Open_tables'}*100/$mystat{'Opened_tables'});
	} else {
		$mycalc{'table_cache_hit_rate'} = 100;
	}

	# Open files
	if ($myvar{'open_files_limit'} > 0) {
		$mycalc{'pct_files_open'} = int($mystat{'Open_files'}*100/$myvar{'open_files_limit'});
	}

	# Table locks
	if ($mystat{'Table_locks_immediate'} > 0) {
		if ($mystat{'Table_locks_waited'} == 0) {
			$mycalc{'pct_table_locks_immediate'} = 100;
		} else {
			$mycalc{'pct_table_locks_immediate'} = int($mystat{'Table_locks_immediate'}*100/($mystat{'Table_locks_waited'} + $mystat{'Table_locks_immediate'}));
		}
	}

	# Thread cache
	$mycalc{'thread_cache_hit_rate'} = int(100 - (($mystat{'Threads_created'} / $mystat{'Connections'}) * 100));

	# Other
	if ($mystat{'Connections'} > 0) {
		$mycalc{'pct_aborted_connections'} = int(($mystat{'Aborted_connects'}/$mystat{'Connections'}) * 100);
	}
	if ($mystat{'Questions'} > 0) {
		$mycalc{'total_reads'} = $mystat{'Com_select'};
		$mycalc{'total_writes'} = $mystat{'Com_delete'} + $mystat{'Com_insert'} + $mystat{'Com_update'} + $mystat{'Com_replace'};
		if ($mycalc{'total_reads'} == 0) {
			$mycalc{'pct_reads'} = 0;
			$mycalc{'pct_writes'} = 100;
		} else {
			$mycalc{'pct_reads'} = int(($mycalc{'total_reads'}/($mycalc{'total_reads'}+$mycalc{'total_writes'})) * 100);
			$mycalc{'pct_writes'} = 100-$mycalc{'pct_reads'};
		}
	}

	# InnoDB
	if ($myvar{'have_innodb'} eq "YES") {
		$mycalc{'innodb_log_size_pct'} = ($myvar{'innodb_log_file_size'} * 100 / $myvar{'innodb_buffer_pool_size'});
	}
}

sub mysql_stats {
	print "\n-------- Performance Metrics -------------------------------------------------\n";
	# Show uptime, queries per second, connections, traffic stats
	my $qps;
	if ($mystat{'Uptime'} > 0) { $qps = sprintf("%.3f",$mystat{'Questions'}/$mystat{'Uptime'}); }
	if ($mystat{'Uptime'} < 86400) { push(@generalrec,"MySQL started within last 24 hours - recommendations may be inaccurate"); }
	infoprint "Up for: ".pretty_uptime($mystat{'Uptime'})." (".hr_num($mystat{'Questions'}).
		" q [".hr_num($qps)." qps], ".hr_num($mystat{'Connections'})." conn,".
		" TX: ".hr_num($mystat{'Bytes_sent'}).", RX: ".hr_num($mystat{'Bytes_received'}).")\n";
	infoprint "Reads / Writes: ".$mycalc{'pct_reads'}."% / ".$mycalc{'pct_writes'}."%\n";

	# Memory usage
	infoprint "Total buffers: ".hr_bytes($mycalc{'server_buffers'})." global + ".hr_bytes($mycalc{'per_thread_buffers'})." per thread ($myvar{'max_connections'} max threads)\n";
	if ($mycalc{'total_possible_used_memory'} > 2*1024*1024*1024 && $arch eq 32) {
		badprint "Allocating > 2GB RAM on 32-bit systems can cause system instability\n";
		badprint "Maximum possible memory usage: ".hr_bytes($mycalc{'total_possible_used_memory'})." ($mycalc{'pct_physical_memory'}% of installed RAM)\n";
	} elsif ($mycalc{'pct_physical_memory'} > 85) {
		badprint "Maximum possible memory usage: ".hr_bytes($mycalc{'total_possible_used_memory'})." ($mycalc{'pct_physical_memory'}% of installed RAM)\n";
		push(@generalrec,"Reduce your overall MySQL memory footprint for system stability");
	} else {
		goodprint "Maximum possible memory usage: ".hr_bytes($mycalc{'total_possible_used_memory'})." ($mycalc{'pct_physical_memory'}% of installed RAM)\n";
	}

	# Slow queries
	if ($mycalc{'pct_slow_queries'} > 5) {
		badprint "Slow queries: $mycalc{'pct_slow_queries'}% (".hr_num($mystat{'Slow_queries'})."/".hr_num($mystat{'Questions'}).")\n";
	} else {
		goodprint "Slow queries: $mycalc{'pct_slow_queries'}% (".hr_num($mystat{'Slow_queries'})."/".hr_num($mystat{'Questions'}).")\n";
	}
	if ($myvar{'long_query_time'} > 10) { push(@adjvars,"long_query_time (<= 10)"); }
	if (defined($myvar{'log_slow_queries'})) {
		if ($myvar{'log_slow_queries'} eq "OFF") { push(@generalrec,"Enable the slow query log to troubleshoot bad queries"); }
	}

	# Connections
	if ($mycalc{'pct_connections_used'} > 85) {
		badprint "Highest connection usage: $mycalc{'pct_connections_used'}%  ($mystat{'Max_used_connections'}/$myvar{'max_connections'})\n";
		push(@adjvars,"max_connections (> ".$myvar{'max_connections'}.")");
		push(@adjvars,"wait_timeout (< ".$myvar{'wait_timeout'}.")","interactive_timeout (< ".$myvar{'interactive_timeout'}.")");
		push(@generalrec,"Reduce or eliminate persistent connections to reduce connection usage")
	} else {
		goodprint "Highest usage of available connections: $mycalc{'pct_connections_used'}% ($mystat{'Max_used_connections'}/$myvar{'max_connections'})\n";
	}

	# Key buffer
	if (!defined($mycalc{'total_myisam_indexes'}) and $doremote == 1) {
		push(@generalrec,"Unable to calculate MyISAM indexes on remote MySQL server < 5.0.0");
	} elsif ($mycalc{'total_myisam_indexes'} =~ /^fail$/) {
		badprint "Cannot calculate MyISAM index size - re-run script as root user\n";
	} elsif ($mycalc{'total_myisam_indexes'} == "0") {
		badprint "None of your MyISAM tables are indexed - add indexes immediately\n";
	} else {
		if ($myvar{'key_buffer_size'} < $mycalc{'total_myisam_indexes'} && $mycalc{'pct_keys_from_mem'} < 95) {
			badprint "Key buffer size / total MyISAM indexes: ".hr_bytes($myvar{'key_buffer_size'})."/".hr_bytes($mycalc{'total_myisam_indexes'})."\n";
			push(@adjvars,"key_buffer_size (> ".hr_bytes($mycalc{'total_myisam_indexes'}).")");
		} else {
			goodprint "Key buffer size / total MyISAM indexes: ".hr_bytes($myvar{'key_buffer_size'})."/".hr_bytes($mycalc{'total_myisam_indexes'})."\n";
		}
		if ($mystat{'Key_read_requests'} > 0) {
			if ($mycalc{'pct_keys_from_mem'} < 95) {
				badprint "Key buffer hit rate: $mycalc{'pct_keys_from_mem'}% (".hr_num($mystat{'Key_read_requests'})." cached / ".hr_num($mystat{'Key_reads'})." reads)\n";
			} else {
				goodprint "Key buffer hit rate: $mycalc{'pct_keys_from_mem'}% (".hr_num($mystat{'Key_read_requests'})." cached / ".hr_num($mystat{'Key_reads'})." reads)\n";
			}
		} else {
			# No queries have run that would use keys
		}
	}

	# Query cache
	if (!mysql_version_ge(4)) {
		# MySQL versions < 4.01 don't support query caching
		push(@generalrec,"Upgrade MySQL to version 4+ to utilize query caching");
	} elsif ($myvar{'query_cache_size'} < 1) {
		badprint "Query cache is disabled\n";
		push(@adjvars,"query_cache_size (>= 8M)");
	} elsif ($mystat{'Com_select'} == 0) {
		badprint "Query cache cannot be analyzed - no SELECT statements executed\n";
	} else {
		if ($mycalc{'query_cache_efficiency'} < 20) {
			badprint "Query cache efficiency: $mycalc{'query_cache_efficiency'}% (".hr_num($mystat{'Qcache_hits'})." cached / ".hr_num($mystat{'Qcache_hits'}+$mystat{'Com_select'})." selects)\n";
			push(@adjvars,"query_cache_limit (> ".hr_bytes_rnd($myvar{'query_cache_limit'}).", or use smaller result sets)");
		} else {
			goodprint "Query cache efficiency: $mycalc{'query_cache_efficiency'}% (".hr_num($mystat{'Qcache_hits'})." cached / ".hr_num($mystat{'Qcache_hits'}+$mystat{'Com_select'})." selects)\n";
		}
		if ($mycalc{'query_cache_prunes_per_day'} > 98) {
			badprint "Query cache prunes per day: $mycalc{'query_cache_prunes_per_day'}\n";
			if ($myvar{'query_cache_size'} > 128*1024*1024) {
			    push(@generalrec,"Increasing the query_cache size over 128M may reduce performance");
		        push(@adjvars,"query_cache_size (> ".hr_bytes_rnd($myvar{'query_cache_size'}).") [see warning above]");
			} else {
		        push(@adjvars,"query_cache_size (> ".hr_bytes_rnd($myvar{'query_cache_size'}).")");
			}
		} else {
			goodprint "Query cache prunes per day: $mycalc{'query_cache_prunes_per_day'}\n";
		}
	}

	# Sorting
	if ($mycalc{'total_sorts'} == 0) {
		# For the sake of space, we will be quiet here
		# No sorts have run yet
	} elsif ($mycalc{'pct_temp_sort_table'} > 10) {
		badprint "Sorts requiring temporary tables: $mycalc{'pct_temp_sort_table'}% (".hr_num($mystat{'Sort_merge_passes'})." temp sorts / ".hr_num($mycalc{'total_sorts'})." sorts)\n";
		push(@adjvars,"sort_buffer_size (> ".hr_bytes_rnd($myvar{'sort_buffer_size'}).")");
		push(@adjvars,"read_rnd_buffer_size (> ".hr_bytes_rnd($myvar{'read_rnd_buffer_size'}).")");
	} else {
		goodprint "Sorts requiring temporary tables: $mycalc{'pct_temp_sort_table'}% (".hr_num($mystat{'Sort_merge_passes'})." temp sorts / ".hr_num($mycalc{'total_sorts'})." sorts)\n";
	}

	# Joins
	if ($mycalc{'joins_without_indexes_per_day'} > 250) {
		badprint "Joins performed without indexes: $mycalc{'joins_without_indexes'}\n";
		push(@adjvars,"join_buffer_size (> ".hr_bytes($myvar{'join_buffer_size'}).", or always use indexes with joins)");
		push(@generalrec,"Adjust your join queries to always utilize indexes");
	} else {
		# For the sake of space, we will be quiet here
		# No joins have run without indexes
	}

	# Temporary tables
	if ($mystat{'Created_tmp_tables'} > 0) {
		if ($mycalc{'pct_temp_disk'} > 25 && $mycalc{'max_tmp_table_size'} < 256*1024*1024) {
			badprint "Temporary tables created on disk: $mycalc{'pct_temp_disk'}% (".hr_num($mystat{'Created_tmp_disk_tables'})." on disk / ".hr_num($mystat{'Created_tmp_disk_tables'} + $mystat{'Created_tmp_tables'})." total)\n";
			push(@adjvars,"tmp_table_size (> ".hr_bytes_rnd($myvar{'tmp_table_size'}).")");
			push(@adjvars,"max_heap_table_size (> ".hr_bytes_rnd($myvar{'max_heap_table_size'}).")");
			push(@generalrec,"When making adjustments, make tmp_table_size/max_heap_table_size equal");
			push(@generalrec,"Reduce your SELECT DISTINCT queries without LIMIT clauses");
		} elsif ($mycalc{'pct_temp_disk'} > 25 && $mycalc{'max_tmp_table_size'} >= 256) {
			badprint "Temporary tables created on disk: $mycalc{'pct_temp_disk'}% (".hr_num($mystat{'Created_tmp_disk_tables'})." on disk / ".hr_num($mystat{'Created_tmp_disk_tables'} + $mystat{'Created_tmp_tables'})." total)\n";
			push(@generalrec,"Temporary table size is already large - reduce result set size");
			push(@generalrec,"Reduce your SELECT DISTINCT queries without LIMIT clauses");
		} else {
			goodprint "Temporary tables created on disk: $mycalc{'pct_temp_disk'}% (".hr_num($mystat{'Created_tmp_disk_tables'})." on disk / ".hr_num($mystat{'Created_tmp_disk_tables'} + $mystat{'Created_tmp_tables'})." total)\n";
		}
	} else {
		# For the sake of space, we will be quiet here
		# No temporary tables have been created
	}

	# Thread cache
	if ($myvar{'thread_cache_size'} eq 0) {
		badprint "Thread cache is disabled\n";
		push(@generalrec,"Set thread_cache_size to 4 as a starting value");
		push(@adjvars,"thread_cache_size (start at 4)");
	} else {
		if ($mycalc{'thread_cache_hit_rate'} <= 50) {
			badprint "Thread cache hit rate: $mycalc{'thread_cache_hit_rate'}% (".hr_num($mystat{'Threads_created'})." created / ".hr_num($mystat{'Connections'})." connections)\n";
			push(@adjvars,"thread_cache_size (> $myvar{'thread_cache_size'})");
		} else {
			goodprint "Thread cache hit rate: $mycalc{'thread_cache_hit_rate'}% (".hr_num($mystat{'Threads_created'})." created / ".hr_num($mystat{'Connections'})." connections)\n";
		}
	}

	# Table cache
	if ($mystat{'Open_tables'} > 0) {
		if ($mycalc{'table_cache_hit_rate'} < 20) {
			badprint "Table cache hit rate: $mycalc{'table_cache_hit_rate'}% (".hr_num($mystat{'Open_tables'})." open / ".hr_num($mystat{'Opened_tables'})." opened)\n";
			if (mysql_version_ge(5, 1)) {
				push(@adjvars,"table_cache (> ".$myvar{'table_open_cache'}.")");
			} else {
				push(@adjvars,"table_cache (> ".$myvar{'table_cache'}.")");
			}
			push(@generalrec,"Increase table_cache gradually to avoid file descriptor limits");
		} else {
			goodprint "Table cache hit rate: $mycalc{'table_cache_hit_rate'}% (".hr_num($mystat{'Open_tables'})." open / ".hr_num($mystat{'Opened_tables'})." opened)\n";
		}
	}

	# Open files
	if (defined $mycalc{'pct_files_open'}) {
		if ($mycalc{'pct_files_open'} > 85) {
			badprint "Open file limit used: $mycalc{'pct_files_open'}% (".hr_num($mystat{'Open_files'})."/".hr_num($myvar{'open_files_limit'}).")\n";
			push(@adjvars,"open_files_limit (> ".$myvar{'open_files_limit'}.")");
		} else {
			goodprint "Open file limit used: $mycalc{'pct_files_open'}% (".hr_num($mystat{'Open_files'})."/".hr_num($myvar{'open_files_limit'}).")\n";
		}
	}

	# Table locks
	if (defined $mycalc{'pct_table_locks_immediate'}) {
		if ($mycalc{'pct_table_locks_immediate'} < 95) {
			badprint "Table locks acquired immediately: $mycalc{'pct_table_locks_immediate'}%\n";
			push(@generalrec,"Optimize queries and/or use InnoDB to reduce lock wait");
		} else {
			goodprint "Table locks acquired immediately: $mycalc{'pct_table_locks_immediate'}% (".hr_num($mystat{'Table_locks_immediate'})." immediate / ".hr_num($mystat{'Table_locks_waited'}+$mystat{'Table_locks_immediate'})." locks)\n";
		}
	}

	# Performance options
	if (!mysql_version_ge(4, 1)) {
		push(@generalrec,"Upgrade to MySQL 4.1+ to use concurrent MyISAM inserts");
	} elsif ($myvar{'concurrent_insert'} eq "OFF") {
		push(@generalrec,"Enable concurrent_insert by setting it to 'ON'");
	} elsif ($myvar{'concurrent_insert'} eq 0) {
		push(@generalrec,"Enable concurrent_insert by setting it to 1");
	}
	if ($mycalc{'pct_aborted_connections'} > 5) {
		badprint "Connections aborted: ".$mycalc{'pct_aborted_connections'}."%\n";
		push(@generalrec,"Your applications are not closing MySQL connections properly");
	}

	# InnoDB
	if (defined $myvar{'have_innodb'} && $myvar{'have_innodb'} eq "YES" && defined $enginestats{'InnoDB'}) {
		if ($myvar{'innodb_buffer_pool_size'} > $enginestats{'InnoDB'}) {
			goodprint "InnoDB data size / buffer pool: ".hr_bytes($enginestats{'InnoDB'})."/".hr_bytes($myvar{'innodb_buffer_pool_size'})."\n";
		} else {
			badprint "InnoDB data size / buffer pool: ".hr_bytes($enginestats{'InnoDB'})."/".hr_bytes($myvar{'innodb_buffer_pool_size'})."\n";
			push(@adjvars,"innodb_buffer_pool_size (>= ".hr_bytes_rnd($enginestats{'InnoDB'}).")");
		}
	}
}

# Take the two recommendation arrays and display them at the end of the output
sub make_recommendations {
	print "\n-------- Recommendations -----------------------------------------------------\n";
	if (@generalrec > 0) {
		print "General recommendations:\n";
		foreach (@generalrec) { print "    ".$_."\n"; }
	}
	if (@adjvars > 0) {
		print "Variables to adjust:\n";
		if ($mycalc{'pct_physical_memory'} > 90) {
			print "  *** MySQL's maximum memory usage is dangerously high ***\n".
				  "  *** Add RAM before increasing MySQL buffer variables ***\n";
		}
		foreach (@adjvars) { print "    ".$_."\n"; }
	}
	if (@generalrec == 0 && @adjvars ==0) {
		print "No additional performance recommendations are available.\n"
	}
	print "\n";
}

# ---------------------------------------------------------------------------
# BEGIN 'MAIN'
# ---------------------------------------------------------------------------
print	"\n >>  MySQLTuner $tunerversion - Major Hayden <major\@mhtx.net>\n".
		" >>  Bug reports, feature requests, and downloads at http://mysqltuner.com/\n".
		" >>  Run with '--help' for additional options and output filtering\n";
mysql_setup;					# Gotta login first
os_setup;						# Set up some OS variables
get_all_vars;					# Toss variables/status into hashes
validate_tuner_version;			# Check current MySQLTuner version
validate_mysql_version;			# Check current MySQL version
check_architecture;				# Suggest 64-bit upgrade
check_storage_engines;			# Show enabled storage engines
security_recommendations;		# Display some security recommendations
calculations;					# Calculate everything we need
mysql_stats;					# Print the server stats
make_recommendations;			# Make recommendations based on stats
# ---------------------------------------------------------------------------
# END 'MAIN'
# ---------------------------------------------------------------------------

# Local variables:
# indent-tabs-mode: t
# cperl-indent-level: 8
# perl-indent-level: 8
# End:
module Puppet::Parser::Functions
  newfunction(:mysql_deepmerge, :type => :rvalue, :doc => <<-'ENDHEREDOC') do |args|
    Recursively merges two or more hashes together and returns the resulting hash.

    For example:

        $hash1 = {'one' => 1, 'two' => 2, 'three' => { 'four' => 4 } }
        $hash2 = {'two' => 'dos', 'three' => { 'five' => 5 } }
        $merged_hash = mysql_deepmerge($hash1, $hash2)
        # The resulting hash is equivalent to:
        # $merged_hash = { 'one' => 1, 'two' => 'dos', 'three' => { 'four' => 4, 'five' => 5 } }

    When there is a duplicate key that is a hash, they are recursively merged.
    When there is a duplicate key that is not a hash, the key in the rightmost hash will "win."
    When there are conficting uses of dashes and underscores in two keys (which mysql would otherwise equate),
      the rightmost style will win.

    ENDHEREDOC

    if args.length < 2
      raise Puppet::ParseError, ("mysql_deepmerge(): wrong number of arguments (#{args.length}; must be at least 2)")
    end

    result = Hash.new
    args.each do |arg|
      next if arg.is_a? String and arg.empty? # empty string is synonym for puppet's undef
      # If the argument was not a hash, skip it.
      unless arg.is_a?(Hash)
        raise Puppet::ParseError, "mysql_deepmerge: unexpected argument type #{arg.class}, only expects hash arguments"
      end

      # Now we have to traverse our hash assigning our non-hash values
      # to the matching keys in our result while following our hash values
      # and repeating the process.
      overlay( result, arg )
    end
    return( result )
  end
end

def has_normalized!(hash, key)
  return true if hash.has_key?( key )
  return false unless key.match(/-|_/)
  other_key = key.include?('-') ? key.gsub( '-', '_' ) : key.gsub( '_', '-' )
  return false unless hash.has_key?( other_key )
  hash[key] = hash.delete( other_key )
  return true;
end

def overlay( hash1, hash2 )
  hash2.each do |key, value|
    if(has_normalized!( hash1, key ) and value.is_a?(Hash) and hash1[key].is_a?(Hash))
      overlay( hash1[key], value )
    else
      hash1[key] = value
    end
  end
end
# hash a string as mysql's "PASSWORD()" function would do it
require 'digest/sha1'

module Puppet::Parser::Functions
  newfunction(:mysql_password, :type => :rvalue, :doc => <<-EOS
    Returns the mysql password hash from the clear text password.
    EOS
  ) do |args|

    raise(Puppet::ParseError, 'mysql_password(): Wrong number of arguments ' +
      "given (#{args.size} for 1)") if args.size != 1

    '*' + Digest::SHA1.hexdigest(Digest::SHA1.digest(args[0])).upcase
  end
end
module Puppet::Parser::Functions
  newfunction(:mysql_strip_hash, :type => :rvalue, :arity => 1, :doc => <<-EOS
TEMPORARY FUNCTION: EXPIRES 2014-03-10
When given a hash this function strips out all blank entries.
EOS
  ) do |args|

    hash = args[0]
    unless hash.is_a?(Hash)
      raise(Puppet::ParseError, 'mysql_strip_hash(): Requires hash to work with')
    end

    # Filter out all the top level blanks.
    hash.reject{|k,v| v == ''}.each do |k,v|
      if v.is_a?(Hash)
        v.reject!{|ki,vi| vi == '' }
      end
    end

  end
end
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'mysql'))
Puppet::Type.type(:database).provide(:mysql, :parent => Puppet::Provider::Mysql) do
  desc 'Manages MySQL database.'

  defaultfor :kernel => 'Linux'

  optional_commands :mysql      => 'mysql'
  optional_commands :mysqladmin => 'mysqladmin'

  def self.instances
    mysql([defaults_file, '-NBe', 'show databases'].compact).split("\n").collect do |name|
      new(:name => name)
    end
  end

  def create
    mysql([defaults_file, '-NBe', "create database `#{@resource[:name]}` character set #{resource[:charset]}"].compact)
  end

  def destroy
    mysqladmin([defaults_file, '-f', 'drop', @resource[:name]].compact)
  end

  def charset
    mysql([defaults_file, '-NBe', "show create database `#{resource[:name]}`"].compact).match(/.*?(\S+)\s(?:COLLATE.*)?\*\//)[1]
  end

  def charset=(value)
    mysql([defaults_file, '-NBe', "alter database `#{resource[:name]}` CHARACTER SET #{value}"].compact)
  end

  def exists?
    begin
      mysql([defaults_file, '-NBe', 'show databases'].compact).match(/^#{@resource[:name]}$/)
    rescue => e
      debug(e.message)
      return nil
    end
  end

end
# A grant is either global or per-db. This can be distinguished by the syntax
# of the name:
#   user@host => global
#   user@host/db => per-db

require File.expand_path(File.join(File.dirname(__FILE__), '..', 'mysql'))
Puppet::Type.type(:database_grant).provide(:mysql, :parent => Puppet::Provider::Mysql) do

  desc 'Uses mysql as database.'

  defaultfor :kernel => 'Linux'

  optional_commands :mysql      => 'mysql'
  optional_commands :mysqladmin => 'mysqladmin'

  def self.prefetch(resources)
    @user_privs = query_user_privs
    @db_privs = query_db_privs
  end

  def self.user_privs
    @user_privs || query_user_privs
  end

  def self.db_privs
    @db_privs || query_db_privs
  end

  def user_privs
    self.class.user_privs
  end

  def db_privs
    self.class.db_privs
  end

  def self.query_user_privs
    results = mysql([defaults_file, 'mysql', '-Be', 'describe user'].compact)
    column_names = results.split(/\n/).map { |l| l.chomp.split(/\t/)[0] }
    @user_privs = column_names.delete_if { |e| !( e =~/_priv$/) }
  end

  def self.query_db_privs
    results = mysql([defaults_file, 'mysql', '-Be', 'describe db'].compact)
    column_names = results.split(/\n/).map { |l| l.chomp.split(/\t/)[0] }
    @db_privs = column_names.delete_if { |e| !(e =~/_priv$/) }
  end

  def mysql_flush
    mysqladmin([defaults_file, 'flush-privileges'].compact)
  end

  # this parses the
  def split_name(string)
    matches = /^([^@]*)@([^\/]*)(\/(.*))?$/.match(string).captures.compact
    case matches.length
    when 2
      {
        :type => :user,
        :user => matches[0],
        :host => matches[1]
      }
    when 4
      {
        :type => :db,
        :user => matches[0],
        :host => matches[1],
        :db => matches[3]
      }
    end
  end

  def create_row
    unless @resource.should(:privileges).empty?
      name = split_name(@resource[:name])
      case name[:type]
      when :user
        mysql([defaults_file, 'mysql', '-e', "INSERT INTO user (host, user) VALUES ('%s', '%s')" % [
          name[:host], name[:user],
        ]].compact)
      when :db
        mysql([defaults_file, 'mysql', '-e', "INSERT INTO db (host, user, db) VALUES ('%s', '%s', '%s')" % [
          name[:host], name[:user], name[:db],
        ]].compact)
      end
      mysql_flush
    end
  end

  def destroy
    mysql([defaults_file, 'mysql', '-e', "REVOKE ALL ON '%s'.* FROM '%s@%s'" % [ @resource[:privileges], @resource[:database], @resource[:name], @resource[:host] ]].compact)
  end

  def row_exists?
    name = split_name(@resource[:name])
    fields = [:user, :host]
    if name[:type] == :db
      fields << :db
    end
    not mysql([defaults_file, 'mysql', '-NBe', "SELECT '1' FROM %s WHERE %s" % [ name[:type], fields.map do |f| "%s='%s'" % [f, name[f]] end.join(' AND ')]].compact).empty?
  end

  def all_privs_set?
    all_privs = case split_name(@resource[:name])[:type]
                when :user
                  user_privs
                when :db
                  db_privs
                end
    all_privs = all_privs.collect do |p| p.downcase end.sort.join('|')
    privs = privileges.collect do |p| p.downcase end.sort.join('|')

    all_privs == privs
  end

  def privileges
    name = split_name(@resource[:name])
    privs = ''

    case name[:type]
    when :user
      privs = mysql([defaults_file, 'mysql', '-Be', "select * from mysql.user where user='%s' and host='%s'" % [ name[:user], name[:host] ]].compact)
    when :db
      privs = mysql([defaults_file, 'mysql', '-Be', "select * from mysql.db where user='%s' and host='%s' and db='%s'" % [ name[:user], name[:host], name[:db] ]].compact)
    end

    if privs.match(/^$/)
      privs = [] # no result, no privs
    else
      # returns a line with field names and a line with values, each tab-separated
      privs = privs.split(/\n/).map! do |l| l.chomp.split(/\t/) end
      # transpose the lines, so we have key/value pairs
      privs = privs[0].zip(privs[1])
      privs = privs.select do |p| p[0].match(/_priv$/) and p[1] == 'Y' end
    end

    privs.collect do |p| p[0] end
  end

  def privileges=(privs)
    unless row_exists?
      create_row
    end

    # puts "Setting privs: ", privs.join(", ")
    name = split_name(@resource[:name])
    stmt = ''
    where = ''
    all_privs = []
    case name[:type]
    when :user
      stmt = 'update user set '
      where = " where user='%s' and host='%s'" % [ name[:user], name[:host] ]
      all_privs = user_privs
    when :db
      stmt = 'update db set '
      where = " where user='%s' and host='%s' and db='%s'" % [ name[:user], name[:host], name[:db] ]
      all_privs = db_privs
    end

    if privs[0].downcase == 'all'
      privs = all_privs
    end

    # Downcase the requested priviliges for case-insensitive selection
    # we don't map! here because the all_privs object has to remain in
    # the same case the DB gave it to us in
    privs = privs.map { |p| p.downcase }

    # puts "stmt:", stmt
    set = all_privs.collect do |p| "%s = '%s'" % [p, privs.include?(p.downcase) ? 'Y' : 'N'] end.join(', ')
    # puts "set:", set
    stmt = stmt << set << where

    validate_privs privs, all_privs
    mysql([defaults_file, 'mysql', '-Be', stmt].compact)
    mysql_flush
  end

  def validate_privs(set_privs, all_privs)
    all_privs = all_privs.collect { |p| p.downcase }
    set_privs = set_privs.collect { |p| p.downcase }
    invalid_privs = Array.new
    hints = Array.new
    # Test each of the user provided privs to see if they exist in all_privs
    set_privs.each do |priv|
      invalid_privs << priv unless all_privs.include?(priv)
      hints << "#{priv}_priv" if all_privs.include?("#{priv}_priv")
    end
    unless invalid_privs.empty?
      # Print a decently helpful and gramatically correct error message
      hints = "Did you mean '#{hints.join(',')}'?" unless hints.empty?
      p = invalid_privs.size > 1 ? ['s', 'are not valid'] : ['', 'is not valid']
      detail = ["The privilege#{p[0]} '#{invalid_privs.join(',')}' #{p[1]}."]
      fail [detail, hints].join(' ')
    end
  end

end
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'mysql'))
Puppet::Type.type(:database_user).provide(:mysql, :parent => Puppet::Provider::Mysql) do

  desc 'manage users for a mysql database.'

  defaultfor :kernel => 'Linux'

  commands :mysql      => 'mysql'
  commands :mysqladmin => 'mysqladmin'

  def self.instances
    users = mysql([defaults_file, 'mysql', '-BNe' "select concat(User, '@',Host) as User from mysql.user"].compact).split("\n")
    users.select{ |user| user =~ /.+@/ }.collect do |name|
      new(:name => name)
    end
  end

  def create
    merged_name          = self.class.cmd_user(@resource[:name])
    password_hash        = @resource.value(:password_hash)
    max_user_connections = @resource.value(:max_user_connections) || 0

    mysql([defaults_file, 'mysql', '-e', "grant usage on *.* to #{merged_name} identified by PASSWORD
      '#{password_hash}' with max_user_connections #{max_user_connections}"].compact)

    exists? ? (return true) : (return false)
  end

  def destroy
    merged_name   = self.class.cmd_user(@resource[:name])
    mysql([defaults_file, 'mysql', '-e', "drop user #{merged_name}"].compact)

    exists? ? (return false) : (return true)
  end

  def password_hash
    mysql([defaults_file, 'mysql', '-NBe', "select password from mysql.user where CONCAT(user, '@', host) = '#{@resource[:name]}'"].compact).chomp
  end

  def password_hash=(string)
    mysql([defaults_file, 'mysql', '-e', "SET PASSWORD FOR #{self.class.cmd_user(@resource[:name])} = '#{string}'"].compact)

    password_hash == string ? (return true) : (return false)
  end

  def max_user_connections
    mysql([defaults_file, "mysql", "-NBe", "select max_user_connections from mysql.user where CONCAT(user, '@', host) = '#{@resource[:name]}'"].compact).chomp
  end

  def max_user_connections=(int)
    mysql([defaults_file, "mysql", "-e", "grant usage on *.* to %s with max_user_connections #{int}" % [ self.class.cmd_user(@resource[:name])] ].compact).chomp

    max_user_connections == int ? (return true) : (return false)
  end

  def exists?
    not mysql([defaults_file, 'mysql', '-NBe', "select '1' from mysql.user where CONCAT(user, '@', host) = '%s'" % @resource.value(:name)].compact).empty?
  end

  def flush
    @property_hash.clear
    mysqladmin([defaults_file, 'flush-privileges'].compact)
  end

end
class Puppet::Provider::Mysql < Puppet::Provider

  # Without initvars commands won't work.
  initvars
  commands :mysql      => 'mysql'
  commands :mysqladmin => 'mysqladmin'

  # Optional defaults file
  def self.defaults_file
    if File.file?("#{Facter.value(:root_home)}/.my.cnf")
      "--defaults-extra-file=#{Facter.value(:root_home)}/.my.cnf"
    else
      nil
    end
  end
  
  def defaults_file
    self.class.defaults_file
  end

  def self.users
    mysql([defaults_file, '-NBe', "SELECT CONCAT(User, '@',Host) AS User FROM mysql.user"].compact).split("\n")
  end

  # Take root@localhost and munge it to 'root'@'localhost'
  def self.cmd_user(user)
    "'#{user.sub('@', "'@'")}'"
  end

  # Take root.* and return ON `root`.*
  def self.cmd_table(table)
    table_string = ''

    # We can't escape *.* so special case this.
    if table == '*.*'
      table_string << '*.*'
    # Special case also for PROCEDURES
    elsif table.start_with?('PROCEDURE ')
      table_string << table.sub(/^PROCEDURE (.*)(\..*)/, 'PROCEDURE `\1`\2')
    else
      table_string << table.sub(/^(.*)(\..*)/, '`\1`\2')
    end
    table_string
  end

  def self.cmd_privs(privileges)
    if privileges.include?('ALL')
      return 'ALL PRIVILEGES'
    else
      priv_string = ''
      privileges.each do |priv|
        priv_string << "#{priv}, "
      end
    end
    # Remove trailing , from the last element.
    priv_string.sub(/, $/, '')
  end

  # Take in potential options and build up a query string with them.
  def self.cmd_options(options)
    option_string = ''
    options.each do |opt|
      if opt == 'GRANT'
        option_string << ' WITH GRANT OPTION'
      end
    end
    option_string
  end

end
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'mysql'))
Puppet::Type.type(:mysql_database).provide(:mysql, :parent => Puppet::Provider::Mysql) do
  desc 'Manages MySQL databases.'

  commands :mysql => 'mysql'

  def self.instances
    mysql([defaults_file, '-NBe', 'show databases'].compact).split("\n").collect do |name|
      attributes = {}
      mysql([defaults_file, '-NBe', "show variables like '%_database'", name].compact).split("\n").each do |line|
        k,v = line.split(/\s/)
        attributes[k] = v
      end
      new(:name    => name,
          :ensure  => :present,
          :charset => attributes['character_set_database'],
          :collate => attributes['collation_database']
         )
    end
  end

  # We iterate over each mysql_database entry in the catalog and compare it against
  # the contents of the property_hash generated by self.instances
  def self.prefetch(resources)
    databases = instances
    resources.keys.each do |database|
      if provider = databases.find { |db| db.name == database }
        resources[database].provider = provider
      end
    end
  end

  def create
    mysql([defaults_file, '-NBe', "create database if not exists `#{@resource[:name]}` character set #{@resource[:charset]} collate #{@resource[:collate]}"].compact)

    @property_hash[:ensure]  = :present
    @property_hash[:charset] = @resource[:charset]
    @property_hash[:collate] = @resource[:collate]

    exists? ? (return true) : (return false)
  end

  def destroy
    mysql([defaults_file, '-NBe', "drop database `#{@resource[:name]}`"].compact)

    @property_hash.clear
    exists? ? (return false) : (return true)
  end

  def exists?
    @property_hash[:ensure] == :present || false
  end

  mk_resource_methods

  def charset=(value)
    mysql([defaults_file, '-NBe', "alter database `#{resource[:name]}` CHARACTER SET #{value}"].compact)
    @property_hash[:charset] = value
    charset == value ? (return true) : (return false)
  end

  def collate=(value)
    mysql([defaults_file, '-NBe', "alter database `#{resource[:name]}` COLLATE #{value}"].compact)
    @property_hash[:collate] = value
    collate == value ? (return true) : (return false)
  end

end
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'mysql'))
Puppet::Type.type(:mysql_grant).provide(:mysql, :parent => Puppet::Provider::Mysql) do

  desc 'Set grants for users in MySQL.'

  def self.instances
    instances = []
    users.select{ |user| user =~ /.+@/ }.collect do |user|
      user_string = self.cmd_user(user)
      query = "SHOW GRANTS FOR #{user_string};"
      grants = mysql([defaults_file, "-NBe", query].compact)
      # Once we have the list of grants generate entries for each.
      grants.each_line do |grant|
        # Match the munges we do in the type.
        munged_grant = grant.delete("'").delete("`")
        # Matching: GRANT (SELECT, UPDATE) PRIVILEGES ON (*.*) TO ('root')@('127.0.0.1') (WITH GRANT OPTION)
        if match = munged_grant.match(/^GRANT\s(.+)\sON\s(.+)\sTO\s(.*)@(.*?)(\s.*)$/)
          privileges, table, user, host, rest = match.captures
          # Once we split privileges up on the , we need to make sure we
          # shortern ALL PRIVILEGES to just all.
          stripped_privileges = privileges.split(',').map do |priv|
            priv == 'ALL PRIVILEGES' ? 'ALL' : priv.lstrip.rstrip
          end
          # Same here, but to remove OPTION leaving just GRANT.
          options = ['GRANT'] if rest.match(/WITH\sGRANT\sOPTION/)
          # We need to return an array of instances so capture these
          instances << new(
              :name       => "#{user}@#{host}/#{table}",
              :ensure     => :present,
              :privileges => stripped_privileges.sort,
              :table      => table,
              :user       => "#{user}@#{host}",
              :options    => options
          )
        end
      end
    end
    return instances
  end

  def self.prefetch(resources)
    users = instances
    resources.keys.each do |name|
      if provider = users.find { |user| user.name == name }
        resources[name].provider = provider
      end
    end
  end

  def grant(user, table, privileges, options)
    user_string = self.class.cmd_user(user)
    priv_string = self.class.cmd_privs(privileges)
    table_string = self.class.cmd_table(table)
    query = "GRANT #{priv_string}"
    query << " ON #{table_string}"
    query << " TO #{user_string}"
    query << self.class.cmd_options(options) unless options.nil?
    mysql([defaults_file, '-e', query].compact)
  end

  def create
    grant(@resource[:user], @resource[:table], @resource[:privileges], @resource[:options])

    @property_hash[:ensure]     = :present
    @property_hash[:table]      = @resource[:table]
    @property_hash[:user]       = @resource[:user]
    @property_hash[:options]    = @resource[:options] if @resource[:options]
    @property_hash[:privileges] = @resource[:privileges]

    exists? ? (return true) : (return false)
  end

  def revoke(user, table)
    user_string = self.class.cmd_user(user)
    table_string = self.class.cmd_table(table)

    query = "REVOKE ALL ON #{table_string} FROM #{user_string}"
    mysql([defaults_file, '-e', query].compact)
    # revoke grant option needs to be a extra query, because
    # "REVOKE ALL PRIVILEGES, GRANT OPTION [..]" is only valid mysql syntax
    # if no ON clause is used.
    query = "REVOKE GRANT OPTION ON #{table_string} FROM #{user_string}"
    mysql([defaults_file, '-e', query].compact)
  end

  def destroy
    revoke(@property_hash[:user], @property_hash[:table])
    @property_hash.clear

    exists? ? (return false) : (return true)
  end

  def exists?
    @property_hash[:ensure] == :present || false
  end

  def flush
    @property_hash.clear
    mysql([defaults_file, '-NBe', 'FLUSH PRIVILEGES'].compact)
  end

  mk_resource_methods

  def privileges=(privileges)
    revoke(@property_hash[:user], @property_hash[:table])
    grant(@property_hash[:user], @property_hash[:table], privileges, @property_hash[:options])
    @property_hash[:privileges] = privileges

    self.privileges
  end

  def options=(options)
    revoke(@property_hash[:user], @property_hash[:table])
    grant(@property_hash[:user], @property_hash[:table], @property_hash[:privileges], options)
    @property_hash[:options] = options

    self.options
  end

end
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'mysql'))
Puppet::Type.type(:mysql_user).provide(:mysql, :parent => Puppet::Provider::Mysql) do

  desc 'manage users for a mysql database.'
  commands :mysql => 'mysql'

  # Build a property_hash containing all the discovered information about MySQL
  # users.
  def self.instances
    users = mysql([defaults_file, '-NBe',
      "SELECT CONCAT(User, '@',Host) AS User FROM mysql.user"].compact).split("\n")
    # To reduce the number of calls to MySQL we collect all the properties in
    # one big swoop.
    users.collect do |name|
      query = "SELECT MAX_USER_CONNECTIONS, MAX_CONNECTIONS, MAX_QUESTIONS, MAX_UPDATES, PASSWORD FROM mysql.user WHERE CONCAT(user, '@', host) = '#{name}'"
      @max_user_connections, @max_connections_per_hour, @max_queries_per_hour,
      @max_updates_per_hour, @password = mysql([defaults_file, "-NBe", query].compact).split(/\s/)

      new(:name                     => name,
          :ensure                   => :present,
          :password_hash            => @password,
          :max_user_connections     => @max_user_connections,
          :max_connections_per_hour => @max_connections_per_hour,
          :max_queries_per_hour     => @max_queries_per_hour,
          :max_updates_per_hour     => @max_updates_per_hour
         )
    end
  end

  # We iterate over each mysql_user entry in the catalog and compare it against
  # the contents of the property_hash generated by self.instances
  def self.prefetch(resources)
    users = instances
    resources.keys.each do |name|
      if provider = users.find { |user| user.name == name }
        resources[name].provider = provider
      end
    end
  end

  def create
    merged_name             = @resource[:name].sub('@', "'@'")
    password_hash            = @resource.value(:password_hash)
    max_user_connections     = @resource.value(:max_user_connections) || 0
    max_connections_per_hour = @resource.value(:max_connections_per_hour) || 0
    max_queries_per_hour     = @resource.value(:max_queries_per_hour) || 0
    max_updates_per_hour     = @resource.value(:max_updates_per_hour) || 0

    mysql([defaults_file, '-e', "GRANT USAGE ON *.* TO '#{merged_name}' IDENTIFIED BY PASSWORD '#{password_hash}' WITH MAX_USER_CONNECTIONS #{max_user_connections} MAX_CONNECTIONS_PER_HOUR #{max_connections_per_hour} MAX_QUERIES_PER_HOUR #{max_queries_per_hour} MAX_UPDATES_PER_HOUR #{max_updates_per_hour}"].compact)

    @property_hash[:ensure] = :present
    @property_hash[:password_hash] = password_hash
    @property_hash[:max_user_connections] = max_user_connections
    @property_hash[:max_connections_per_hour] = max_connections_per_hour
    @property_hash[:max_queries_per_hour] = max_queries_per_hour
    @property_hash[:max_updates_per_hour] = max_updates_per_hour

    exists? ? (return true) : (return false)
  end

  def destroy
    merged_name = @resource[:name].sub('@', "'@'")
    mysql([defaults_file, '-e', "DROP USER '#{merged_name}'"].compact)

    @property_hash.clear
    exists? ? (return false) : (return true)
  end

  def exists?
    @property_hash[:ensure] == :present || false
  end

  ##
  ## MySQL user properties
  ##

  # Generates method for all properties of the property_hash
  mk_resource_methods

  def password_hash=(string)
    merged_name = self.class.cmd_user(@resource[:name])
    mysql([defaults_file, '-e', "SET PASSWORD FOR #{merged_name} = '#{string}'"].compact)

    password_hash == string ? (return true) : (return false)
  end

  def max_user_connections=(int)
    merged_name = self.class.cmd_user(@resource[:name])
    mysql([defaults_file, '-e', "GRANT USAGE ON *.* TO #{merged_name} WITH MAX_USER_CONNECTIONS #{int}"].compact).chomp

    max_user_connections == int ? (return true) : (return false)
  end

  def max_connections_per_hour=(int)
    merged_name = self.class.cmd_user(@resource[:name])
    mysql([defaults_file, '-e', "GRANT USAGE ON *.* TO #{merged_name} WITH MAX_CONNECTIONS_PER_HOUR #{int}"].compact).chomp

    max_connections_per_hour == int ? (return true) : (return false)
  end

  def max_queries_per_hour=(int)
    merged_name = self.class.cmd_user(@resource[:name])
    mysql([defaults_file, '-e', "GRANT USAGE ON *.* TO #{merged_name} WITH MAX_QUERIES_PER_HOUR #{int}"].compact).chomp

    max_queries_per_hour == int ? (return true) : (return false)
  end

  def max_updates_per_hour=(int)
    merged_name = self.class.cmd_user(@resource[:name])
    mysql([defaults_file, '-e', "GRANT USAGE ON *.* TO #{merged_name} WITH MAX_UPDATES_PER_HOUR #{int}"].compact).chomp

    max_updates_per_hour == int ? (return true) : (return false)
  end

end
# This has to be a separate type to enable collecting
Puppet::Type.newtype(:database) do
  @doc = 'Manage databases.'

  ensurable

  newparam(:name, :namevar=>true) do
    desc 'The name of the database.'
    validate do |value|
      Puppet.warning("database has been deprecated in favor of mysql_database.")
      true
    end
  end

  newproperty(:charset) do
    desc 'The characterset to use for a database'
    defaultto :utf8
    newvalue(/^\S+$/)
  end

end
# This has to be a separate type to enable collecting
Puppet::Type.newtype(:database_grant) do
  @doc = "Manage a database user's rights."
  #ensurable

  autorequire :database do
    # puts "Starting db autoreq for %s" % self[:name]
    reqs = []
    matches = self[:name].match(/^([^@]+)@([^\/]+)\/(.+)$/)
    unless matches.nil?
      reqs << matches[3]
    end
    # puts "Autoreq: '%s'" % reqs.join(" ")
    reqs
  end

  autorequire :database_user do
    # puts "Starting user autoreq for %s" % self[:name]
    reqs = []
    matches = self[:name].match(/^([^@]+)@([^\/]+).*$/)
    unless matches.nil?
      reqs << '%s@%s' % [ matches[1], matches[2] ]
    end
    # puts "Autoreq: '%s'" % reqs.join(" ")
    reqs
  end

  newparam(:name, :namevar=>true) do
    desc 'The primary key: either user@host for global privilges or user@host/database for database specific privileges'
    validate do |value|
      Puppet.warning("database_grant has been deprecated in favor of mysql_grant.")
      true
    end
  end

  newproperty(:privileges, :array_matching => :all) do
    desc 'The privileges the user should have. The possible values are implementation dependent.'

    def should_to_s(newvalue = @should)
      if newvalue
        unless newvalue.is_a?(Array)
          newvalue = [ newvalue ]
        end
        newvalue.collect do |v| v.downcase end.sort.join ', '
      else
        nil
      end
    end

    def is_to_s(currentvalue = @is)
      if currentvalue
        unless currentvalue.is_a?(Array)
          currentvalue = [ currentvalue ]
        end
        currentvalue.collect do |v| v.downcase end.sort.join ', '
      else
        nil
      end
    end

    # use the sorted outputs for comparison
    def insync?(is)
      if defined? @should and @should
        case self.should_to_s
        when 'all'
          self.provider.all_privs_set?
        when self.is_to_s(is)
          true
        else
          false
        end
      else
        true
      end
    end
  end

end

# This has to be a separate type to enable collecting
Puppet::Type.newtype(:database_user) do
  @doc = 'Manage a database user. This includes management of users password as well as privileges'

  ensurable

  newparam(:name, :namevar=>true) do
    desc "The name of the user. This uses the 'username@hostname' or username@hostname."
    validate do |value|
      Puppet.warning("database has been deprecated in favor of mysql_user.")
      # https://dev.mysql.com/doc/refman/5.1/en/account-names.html
      # Regex should problably be more like this: /^[`'"]?[^`'"]*[`'"]?@[`'"]?[\w%\.]+[`'"]?$/
      raise(ArgumentError, "Invalid database user #{value}") unless value =~ /[\w-]*@[\w%\.:]+/
      username = value.split('@')[0]
      if username.size > 16
        raise ArgumentError, 'MySQL usernames are limited to a maximum of 16 characters'
      end
    end
  end

  newproperty(:password_hash) do
    desc 'The password hash of the user. Use mysql_password() for creating such a hash.'
    newvalue(/\w+/)
  end

  newproperty(:max_user_connections) do
    desc "Max concurrent connections for the user. 0 means no (or global) limit."
    newvalue(/\d+/)
  end

end
Puppet::Type.newtype(:mysql_database) do
  @doc = 'Manage MySQL databases.'

  ensurable

  newparam(:name, :namevar => true) do
    desc 'The name of the MySQL database to manage.'
  end

  newproperty(:charset) do
    desc 'The CHARACTER SET setting for the database'
    defaultto :utf8
    newvalue(/^\S+$/)
  end

  newproperty(:collate) do
    desc 'The COLLATE setting for the database'
    defaultto :utf8_general_ci
    newvalue(/^\S+$/)
  end

end
# This has to be a separate type to enable collecting
Puppet::Type.newtype(:mysql_grant) do
  @doc = "Manage a MySQL user's rights."
  ensurable

  autorequire(:file) { '/root/.my.cnf' }

  def initialize(*args)
    super
    # Forcibly munge any privilege with 'ALL' in the array to exist of just
    # 'ALL'.  This can't be done in the munge in the property as that iterates
    # over the array and there's no way to replace the entire array before it's
    # returned to the provider.
    if self[:ensure] == :present and Array(self[:privileges]).count > 1 and self[:privileges].to_s.include?('ALL')
      self[:privileges] = 'ALL'
    end
    # Sort the privileges array in order to ensure the comparision in the provider
    # self.instances method match.  Otherwise this causes it to keep resetting the
    # privileges.
    self[:privileges] = Array(self[:privileges]).map(&:upcase).uniq.reject{|k| k == 'GRANT' or k == 'GRANT OPTION'}.sort!
  end

  validate do
    fail('privileges parameter is required.') if self[:ensure] == :present and self[:privileges].nil?
    fail('table parameter is required.') if self[:ensure] == :present and self[:table].nil?
    fail('user parameter is required.') if self[:ensure] == :present and self[:user].nil?
  end

  newparam(:name, :namevar => true) do
    desc 'Name to describe the grant.'

    munge do |value|
      value.delete("'")
    end
  end

  newproperty(:privileges, :array_matching => :all) do
    desc 'Privileges for user'

    munge do |value|
      value.upcase
    end
  end

  newproperty(:table) do
    desc 'Table to apply privileges to.'

    munge do |value|
      value.delete("`")
    end

    newvalues(/.*\..*/,/@/)
  end

  newproperty(:user) do
    desc 'User to operate on.'
    validate do |value|
      # https://dev.mysql.com/doc/refman/5.1/en/account-names.html
      # Regex should problably be more like this: /^[`'"]?[^`'"]*[`'"]?@[`'"]?[\w%\.]+[`'"]?$/
      raise(ArgumentError, "Invalid user #{value}") unless value =~ /[\w-]*@[\w%\.:]+/
      username = value.split('@')[0]
      if username.size > 16
        raise ArgumentError, 'MySQL usernames are limited to a maximum of 16 characters'
      end
    end
  end

  newproperty(:options, :array_matching => :all) do
    desc 'Options to grant.'
  end

end
# This has to be a separate type to enable collecting
Puppet::Type.newtype(:mysql_user) do
  @doc = 'Manage a MySQL user. This includes management of users password as well as privileges.'

  ensurable

  newparam(:name, :namevar => true) do
    desc "The name of the user. This uses the 'username@hostname' or username@hostname."
    validate do |value|
      # https://dev.mysql.com/doc/refman/5.1/en/account-names.html
      # Regex should problably be more like this: /^[`'"]?[^`'"]*[`'"]?@[`'"]?[\w%\.]+[`'"]?$/
      raise(ArgumentError, "Invalid database user #{value}") unless value =~ /[\w-]*@[\w%\.:]+/
      username = value.split('@')[0]
      if username.size > 16
        raise ArgumentError, 'MySQL usernames are limited to a maximum of 16 characters'
      end
    end
  end

  newproperty(:password_hash) do
    desc 'The password hash of the user. Use mysql_password() for creating such a hash.'
    newvalue(/\w+/)
  end

  newproperty(:max_user_connections) do
    desc "Max concurrent connections for the user. 0 means no (or global) limit."
    newvalue(/\d+/)
  end

  newproperty(:max_connections_per_hour) do
    desc "Max connections per hour for the user. 0 means no (or global) limit."
    newvalue(/\d+/)
  end

  newproperty(:max_queries_per_hour) do
    desc "Max queries per hour for the user. 0 means no (or global) limit."
    newvalue(/\d+/)
  end

  newproperty(:max_updates_per_hour) do
    desc "Max updates per hour for the user. 0 means no (or global) limit."
    newvalue(/\d+/)
  end

end
# Deprecated class
class mysql::backup (
  $backupuser,
  $backuppassword,
  $backupdir,
  $backupcompress = true,
  $backuprotate = 30,
  $delete_before_dump = false,
  $backupdatabases = [],
  $file_per_database = false,
  $ensure = 'present',
  $time = ['23', '5'],
) {

  crit("This class has been deprecated and callers should directly call
  mysql::server::backup now.")

  class { 'mysql::server::backup':
    ensure             => $ensure,
    backupuser         => $backupuser,
    backuppassword     => $backuppassword,
    backupdir          => $backupdir,
    backupcompress     => $backupcompress,
    backuprotate       => $backuprotate,
    delete_before_dump => $delete_before_dump,
    backupdatabases    => $backupdatabases,
    file_per_database  => $file_per_database,
    time               => $time,
  }

}
# See README.md.
class mysql::bindings (
  # Boolean to determine if we should include the classes.
  $java_enable   = false,
  $perl_enable   = false,
  $php_enable    = false,
  $python_enable = false,
  $ruby_enable   = false,
  # Settings for the various classes.
  $java_package_ensure     = $mysql::params::java_package_ensure,
  $java_package_name       = $mysql::params::java_package_name,
  $java_package_provider   = $mysql::params::java_package_provider,
  $perl_package_ensure     = $mysql::params::perl_package_ensure,
  $perl_package_name       = $mysql::params::perl_package_name,
  $perl_package_provider   = $mysql::params::perl_package_provider,
  $php_package_ensure      = $mysql::params::php_package_ensure,
  $php_package_name        = $mysql::params::php_package_name,
  $php_package_provider    = $mysql::params::php_package_provider,
  $python_package_ensure   = $mysql::params::python_package_ensure,
  $python_package_name     = $mysql::params::python_package_name,
  $python_package_provider = $mysql::params::python_package_provider,
  $ruby_package_ensure     = $mysql::params::ruby_package_ensure,
  $ruby_package_name       = $mysql::params::ruby_package_name,
  $ruby_package_provider   = $mysql::params::ruby_package_provider
) inherits mysql::params {

  if $java_enable   { include '::mysql::bindings::java' }
  if $perl_enable   { include '::mysql::bindings::perl' }
  if $php_enable    { include '::mysql::bindings::php' }
  if $python_enable { include '::mysql::bindings::python' }
  if $ruby_enable   { include '::mysql::bindings::ruby' }

}
# Private class
class mysql::bindings::java {

  package { 'mysql-connector-java':
    ensure   => $mysql::bindings::java_package_ensure,
    name     => $mysql::bindings::java_package_name,
    provider => $mysql::bindings::java_package_provider,
  }

}
# Private class
class mysql::bindings::perl {

  package{ 'perl_mysql':
    ensure   => $mysql::bindings::perl_package_ensure,
    name     => $mysql::bindings::perl_package_name,
    provider => $mysql::bindings::perl_package_provider,
  }

}
# Private class: See README.md
class mysql::bindings::php {

  package { 'php-mysql':
    ensure   => $mysql::bindings::php_package_ensure,
    name     => $mysql::bindings::php_package_name,
    provider => $mysql::bindings::php_package_provider,
  }

}
# Private class
class mysql::bindings::python {

  package { 'python-mysqldb':
    ensure   => $mysql::bindings::python_package_ensure,
    name     => $mysql::bindings::python_package_name,
    provider => $mysql::bindings::python_package_provider,
  }

}
# Private class
class mysql::bindings::ruby {

  package{ 'ruby_mysql':
    ensure   => $mysql::bindings::ruby_package_ensure,
    name     => $mysql::bindings::ruby_package_name,
    provider => $mysql::bindings::ruby_package_provider,
  }

}
#
class mysql::client (
  $bindings_enable = $mysql::params::bindings_enable,
  $package_ensure  = $mysql::params::client_package_ensure,
  $package_name    = $mysql::params::client_package_name,
) inherits mysql::params {

  include '::mysql::client::install'

  if $bindings_enable {
    class { 'mysql::bindings':
      java_enable   => true,
      perl_enable   => true,
      php_enable    => true,
      python_enable => true,
      ruby_enable   => true,
    }
  }


  # Anchor pattern workaround to avoid resources of mysql::client::install to
  # "float off" outside mysql::client
  anchor { 'mysql::client::start': } ->
    Class['mysql::client::install'] ->
  anchor { 'mysql::client::end': }

}
class mysql::client::install {

  package { 'mysql_client':
    ensure => $mysql::client::package_ensure,
    name   => $mysql::client::package_name,
  }

}
# See README.md for details.
define mysql::db (
  $user,
  $password,
  $dbname      = $name,
  $charset     = 'utf8',
  $collate     = 'utf8_general_ci',
  $host        = 'localhost',
  $grant       = 'ALL',
  $sql         = '',
  $enforce_sql = false,
  $ensure      = 'present'
) {
  #input validation
  validate_re($ensure, '^(present|absent)$',
  "${ensure} is not supported for ensure. Allowed values are 'present' and 'absent'.")
  $table = "${dbname}.*"

  include '::mysql::client'

  $db_resource = {
    ensure   => $ensure,
    charset  => $charset,
    collate  => $collate,
    provider => 'mysql',
    require  => [ Class['mysql::server'], Class['mysql::client'] ],
  }
  ensure_resource('mysql_database', $dbname, $db_resource)

  $user_resource = {
    ensure        => $ensure,
    password_hash => mysql_password($password),
    provider      => 'mysql',
    require       => Class['mysql::server'],
  }
  ensure_resource('mysql_user', "${user}@${host}", $user_resource)

  if $ensure == 'present' {
    mysql_grant { "${user}@${host}/${table}":
      privileges => $grant,
      provider   => 'mysql',
      user       => "${user}@${host}",
      table      => $table,
      require    => [Mysql_database[$dbname], Mysql_user["${user}@${host}"], Class['mysql::server'] ],
    }

    $refresh = ! $enforce_sql

    if $sql {
      exec{ "${dbname}-import":
        command     => "/usr/bin/mysql ${dbname} < ${sql}",
        logoutput   => true,
        environment => "HOME=${::root_home}",
        refreshonly => $refresh,
        require     => Mysql_grant["${user}@${host}/${table}"],
        subscribe   => Mysql_database[$dbname],
      }
    }
  }
}
#
class mysql(
  $basedir               = '',
  $bind_address          = '',
  $client_package_ensure = '',
  $client_package_name   = '',
  $config_file           = '',
  $config_template       = '',
  $datadir               = '',
  $default_engine        = '',
  $etc_root_password     = '',
  $log_error             = '',
  $manage_config_file    = '',
  $manage_service        = '',
  $max_allowed_packet    = '',
  $max_connections       = '',
  $old_root_password     = '',
  $package_ensure        = '',
  $php_package_name      = '',
  $pidfile               = '',
  $port                  = '',
  $purge_conf_dir        = '',
  $restart               = '',
  $root_group            = '',
  $root_password         = '',
  $server_package_name   = '',
  $service_name          = '',
  $service_provider      = '',
  $socket                = '',
  $ssl                   = '',
  $ssl_ca                = '',
  $ssl_cert              = '',
  $ssl_key               = '',
  $tmpdir                = '',
  $attempt_compatibility_mode = false,
) {

  if $attempt_compatibility_mode {
    notify { "An attempt has been made below to automatically apply your custom
    settings to mysql::server. Please verify this works in a safe test
    environment.": }

    $override_options = {
      'client'                 => {
        'port'                 => $port,
        'socket'               => $socket
      },
      'mysqld_safe'            => {
        'log_error'            => $log_error,
        'socket'               => $socket,
      },
      'mysqld'               => {
        'basedir'            => $basedir,
        'bind_address'       => $bind_address,
        'datadir'            => $datadir,
        'log_error'          => $log_error,
        'max_allowed_packet' => $max_allowed_packet,
        'max_connections'    => $max_connections,
        'pid_file'           => $pidfile,
        'port'               => $port,
        'socket'             => $socket,
        'ssl-ca'             => $ssl_ca,
        'ssl-cert'           => $ssl_cert,
        'ssl-key'            => $ssl_key,
        'tmpdir'             => $tmpdir,
      },
      'mysqldump'              => {
        'max_allowed_packet'  => $max_allowed_packet,
      },
      'config_file'          => $config_file,
      'etc_root_password'    => $etc_root_password,
      'manage_config_file'   => $manage_config_file,
      'old_root_password'    => $old_root_password,
      'purge_conf_dir'       => $purge_conf_dir,
      'restart'              => $restart,
      'root_group'           => $root_group,
      'root_password'        => $root_password,
      'service_name'         => $service_name,
      'ssl'                  => $ssl
    }
    $filtered_options = mysql_strip_hash($override_options)
    validate_hash($filtered_options)
    notify { $filtered_options: }
    class { 'mysql::server':
      override_options => $filtered_options,
    }

  } else {
    fail("ERROR:  This class has been deprecated and the functionality moved
    into mysql::server.  If you run mysql::server without correctly calling
    mysql:: server with the new override_options hash syntax you will revert
    your MySQL to the stock settings.  Do not proceed without removing this
    class and using mysql::server correctly.

    If you are brave you may set attempt_compatibility_mode in this class which
    attempts to automap the previous settings to appropriate calls to
    mysql::server")
  }

}
# Private class: See README.md.
class mysql::params {

  $manage_config_file     = true
  $old_root_password      = ''
  $purge_conf_dir         = false
  $restart                = false
  $root_password          = 'UNSET'
  $server_package_ensure  = 'present'
  $server_service_manage  = true
  $server_service_enabled = true
  # mysql::bindings
  $bindings_enable         = false
  $java_package_ensure     = 'present'
  $java_package_provider   = undef
  $perl_package_ensure     = 'present'
  $perl_package_provider   = undef
  $php_package_ensure      = 'present'
  $php_package_provider    = undef
  $python_package_ensure   = 'present'
  $python_package_provider = undef
  $ruby_package_ensure     = 'present'
  $ruby_package_provider   = undef


  case $::osfamily {
    'RedHat': {
      case $::operatingsystem {
        'Fedora': {
          if is_integer($::operatingsystemrelease) and $::operatingsystemrelease >= 19 or $::operatingsystemrelease == "Rawhide" {
            $provider = 'mariadb'
          } else {
            $provider = 'mysql'
          }
        }
        'RedHat': {
          if $::operatingsystemrelease >= 7 {
            $provider = 'mariadb'
          } else {
            $provider = 'mysql'
          }
        }
        default: {
          $provider = 'mysql'
        }
      }

      if $provider == 'mariadb' {
        $client_package_name = 'mariadb'
        $server_package_name = 'mariadb-server'
        $server_service_name = 'mariadb'
        $log_error           = '/var/log/mariadb/mariadb.log'
        $config_file         = '/etc/my.cnf'
        $pidfile             = '/var/run/mariadb/mariadb.pid'
      } else {
        $client_package_name = 'mysql'
        $server_package_name = 'mysql-server'
        $server_service_name = 'mysqld'
        $log_error           = '/var/log/mysqld.log'
        $config_file         = '/etc/my.cnf'
        $pidfile             = '/var/run/mysqld/mysqld.pid'
      }

      $basedir             = '/usr'
      $datadir             = '/var/lib/mysql'
      $root_group          = 'root'
      $socket              = '/var/lib/mysql/mysql.sock'
      $ssl_ca              = '/etc/mysql/cacert.pem'
      $ssl_cert            = '/etc/mysql/server-cert.pem'
      $ssl_key             = '/etc/mysql/server-key.pem'
      $tmpdir              = '/tmp'
      # mysql::bindings
      $java_package_name   = 'mysql-connector-java'
      $perl_package_name   = 'perl-DBD-MySQL'
      $php_package_name    = 'php-mysql'
      $python_package_name = 'MySQL-python'
      $ruby_package_name   = 'ruby-mysql'
    }

    'Suse': {
      $client_package_name   = $::operatingsystem ? {
        /OpenSuSE/           => 'mysql-community-server-client',
        /(SLES|SLED)/        => 'mysql-client',
      }
      $server_package_name   = $::operatingsystem ? {
        /OpenSuSE/           => 'mysql-community-server',
        /(SLES|SLED)/        => 'mysql',
      }
      $basedir             = '/usr'
      $config_file         = '/etc/my.cnf'
      $datadir             = '/var/lib/mysql'
      $log_error           = $::operatingsystem ? {
        /OpenSuSE/         => '/var/log/mysql/mysqld.log',
        /(SLES|SLED)/      => '/var/log/mysqld.log',
      }
      $pidfile             = $::operatingsystem ? {
        /OpenSuSE/         => '/var/run/mysql/mysqld.pid',
        /(SLES|SLED)/      => '/var/lib/mysql/mysqld.pid',
      }
      $root_group          = 'root'
      $server_service_name = 'mysql'
      $socket              = $::operatingsystem ? {
        /OpenSuSE/         => '/var/run/mysql/mysql.sock',
        /(SLES|SLED)/      => '/var/lib/mysql/mysql.sock',
      }
      $ssl_ca              = '/etc/mysql/cacert.pem'
      $ssl_cert            = '/etc/mysql/server-cert.pem'
      $ssl_key             = '/etc/mysql/server-key.pem'
      $tmpdir              = '/tmp'
      # mysql::bindings
      $java_package_name   = 'mysql-connector-java'
      $perl_package_name   = 'perl-DBD-mysql'
      $php_package_name    = 'apache2-mod_php53'
      $python_package_name = 'python-mysql'
      $ruby_package_name   = $::operatingsystem ? {
        /OpenSuSE/         => 'rubygem-mysql',
        /(SLES|SLED)/      => 'ruby-mysql',
      }
    }

    'Debian': {
      $client_package_name = 'mysql-client'
      $server_package_name = 'mysql-server'

      $basedir             = '/usr'
      $config_file         = '/etc/mysql/my.cnf'
      $datadir             = '/var/lib/mysql'
      $log_error           = '/var/log/mysql/error.log'
      $pidfile             = '/var/run/mysqld/mysqld.pid'
      $root_group          = 'root'
      $server_service_name = 'mysql'
      $socket              = '/var/run/mysqld/mysqld.sock'
      $ssl_ca              = '/etc/mysql/cacert.pem'
      $ssl_cert            = '/etc/mysql/server-cert.pem'
      $ssl_key             = '/etc/mysql/server-key.pem'
      $tmpdir              = '/tmp'
      # mysql::bindings
      $java_package_name   = 'libmysql-java'
      $perl_package_name   = 'libdbd-mysql-perl'
      $php_package_name    = 'php5-mysql'
      $python_package_name = 'python-mysqldb'
      $ruby_package_name   = $::lsbdistcodename ? {
        'trusty'           => 'ruby-mysql',
        default            => 'libmysql-ruby',
      }
    }

    'FreeBSD': {
      $client_package_name = 'databases/mysql55-client'
      $server_package_name = 'databases/mysql55-server'
      $basedir             = '/usr/local'
      $config_file         = '/var/db/mysql/my.cnf'
      $datadir             = '/var/db/mysql'
      $log_error           = "/var/db/mysql/${::hostname}.err"
      $pidfile             = '/var/db/mysql/mysql.pid'
      $root_group          = 'wheel'
      $server_service_name = 'mysql-server'
      $socket              = '/tmp/mysql.sock'
      $ssl_ca              = undef
      $ssl_cert            = undef
      $ssl_key             = undef
      $tmpdir              = '/tmp'
      # mysql::bindings
      $java_package_name   = 'databases/mysql-connector-java'
      $perl_package_name   = 'p5-DBD-mysql'
      $php_package_name    = 'php5-mysql'
      $python_package_name = 'databases/py-MySQLdb'
      $ruby_package_name   = 'databases/ruby-mysql'
    }

    default: {
      case $::operatingsystem {
        'Amazon': {
          $client_package_name = 'mysql'
          $server_package_name = 'mysql-server'
          $basedir             = '/usr'
          $config_file         = '/etc/my.cnf'
          $datadir             = '/var/lib/mysql'
          $log_error           = '/var/log/mysqld.log'
          $pidfile             = '/var/run/mysqld/mysqld.pid'
          $root_group          = 'root'
          $server_service_name = 'mysqld'
          $socket              = '/var/lib/mysql/mysql.sock'
          $ssl_ca              = '/etc/mysql/cacert.pem'
          $ssl_cert            = '/etc/mysql/server-cert.pem'
          $ssl_key             = '/etc/mysql/server-key.pem'
          $tmpdir              = '/tmp'
          # mysql::bindings
          $java_package_name   = 'mysql-connector-java'
          $perl_package_name   = 'perl-DBD-MySQL'
          $php_package_name    = 'php-mysql'
          $python_package_name = 'MySQL-python'
          $ruby_package_name   = 'ruby-mysql'
        }

        default: {
          fail("Unsupported osfamily: ${::osfamily} operatingsystem: ${::operatingsystem}, module ${module_name} only support osfamily RedHat, Debian, and FreeBSD, or operatingsystem Amazon")
        }
      }
    }
  }

  case $::operatingsystem {
    'Ubuntu': {
      $server_service_provider = upstart
    }
    default: {
      $server_service_provider = undef
    }
  }

  $default_options = {
    'client'          => {
      'port'          => '3306',
      'socket'        => $mysql::params::socket,
    },
    'mysqld_safe'        => {
      'nice'             => '0',
      'log-error'        => $mysql::params::log_error,
      'socket'           => $mysql::params::socket,
    },
    'mysqld'                  => {
      'basedir'               => $mysql::params::basedir,
      'bind-address'          => '127.0.0.1',
      'datadir'               => $mysql::params::datadir,
      'expire_logs_days'      => '10',
      'key_buffer_size'       => '16M',
      'log-error'             => $mysql::params::log_error,
      'max_allowed_packet'    => '16M',
      'max_binlog_size'       => '100M',
      'max_connections'       => '151',
      'myisam_recover'        => 'BACKUP',
      'pid-file'              => $mysql::params::pidfile,
      'port'                  => '3306',
      'query_cache_limit'     => '1M',
      'query_cache_size'      => '16M',
      'skip-external-locking' => true,
      'socket'                => $mysql::params::socket,
      'ssl'                   => false,
      'ssl-ca'                => $mysql::params::ssl_ca,
      'ssl-cert'              => $mysql::params::ssl_cert,
      'ssl-key'               => $mysql::params::ssl_key,
      'ssl-disable'           => false,
      'thread_cache_size'     => '8',
      'thread_stack'          => '256K',
      'tmpdir'                => $mysql::params::tmpdir,
      'user'                  => 'mysql',
    },
    'mysqldump'             => {
      'max_allowed_packet'  => '16M',
      'quick'               => true,
      'quote-names'         => true,
    },
    'isamchk'      => {
      'key_buffer_size' => '16M',
    },
  }

}
# Class: mysql::server:  See README.md for documentation.
class mysql::server (
  $config_file             = $mysql::params::config_file,
  $manage_config_file      = $mysql::params::manage_config_file,
  $old_root_password       = $mysql::params::old_root_password,
  $override_options        = {},
  $package_ensure          = $mysql::params::server_package_ensure,
  $package_name            = $mysql::params::server_package_name,
  $purge_conf_dir          = $mysql::params::purge_conf_dir,
  $remove_default_accounts = false,
  $restart                 = $mysql::params::restart,
  $root_group              = $mysql::params::root_group,
  $root_password           = $mysql::params::root_password,
  $service_enabled         = $mysql::params::server_service_enabled,
  $service_manage          = $mysql::params::server_service_manage,
  $service_name            = $mysql::params::server_service_name,
  $service_provider        = $mysql::params::server_service_provider,
  $users                   = {},
  $grants                  = {},
  $databases               = {},

  # Deprecated parameters
  $enabled                 = undef,
  $manage_service          = undef
) inherits mysql::params {

  # Deprecated parameters.
  if $enabled {
    crit('This parameter has been renamed to service_enabled.')
    $real_service_enabled = $enabled
  } else {
    $real_service_enabled = $service_enabled
  }
  if $manage_service {
    crit('This parameter has been renamed to service_manage.')
    $real_service_manage = $manage_service
  } else {
    $real_service_manage = $service_manage
  }

  # Create a merged together set of options.  Rightmost hashes win over left.
  $options = mysql_deepmerge($mysql::params::default_options, $override_options)

  Class['mysql::server::root_password'] -> Mysql::Db <| |>

  include '::mysql::server::install'
  include '::mysql::server::config'
  include '::mysql::server::service'
  include '::mysql::server::root_password'
  include '::mysql::server::providers'

  if $remove_default_accounts {
    class { '::mysql::server::account_security':
      require => Anchor['mysql::server::end'],
    }
  }

  anchor { 'mysql::server::start': }
  anchor { 'mysql::server::end': }

  if $restart {
    Anchor['mysql::server::start'] ->
    Class['mysql::server::install'] ->
    # Only difference between the blocks is that we use ~> to restart if
    # restart is set to true.
    Class['mysql::server::config'] ~>
    Class['mysql::server::service'] ->
    Class['mysql::server::root_password'] ->
    Class['mysql::server::providers'] ->
    Anchor['mysql::server::end']
  } else {
    Anchor['mysql::server::start'] ->
    Class['mysql::server::install'] ->
    Class['mysql::server::config'] ->
    Class['mysql::server::service'] ->
    Class['mysql::server::root_password'] ->
    Class['mysql::server::providers'] ->
    Anchor['mysql::server::end']
  }


}
class mysql::server::account_security {
  mysql_user {
    [ "root@${::fqdn}",
      'root@127.0.0.1',
      'root@::1',
      "@${::fqdn}",
      '@localhost',
      '@%']:
    ensure  => 'absent',
    require => Anchor['mysql::server::end'],
  }
  if ($::fqdn != $::hostname) {
    mysql_user { ["root@${::hostname}", "@${::hostname}"]:
      ensure  => 'absent',
      require => Anchor['mysql::server::end'],
    }
  }
  mysql_database { 'test':
    ensure  => 'absent',
    require => Anchor['mysql::server::end'],
  }
}
# See README.me for usage.
class mysql::server::backup (
  $backupuser,
  $backuppassword,
  $backupdir,
  $backupdirmode = '0700',
  $backupdirowner = 'root',
  $backupdirgroup = 'root',
  $backupcompress = true,
  $backuprotate = 30,
  $ignore_events = true,
  $delete_before_dump = false,
  $backupdatabases = [],
  $file_per_database = false,
  $ensure = 'present',
  $time = ['23', '5'],
  $postscript = false,
  $execpath   = '/usr/bin:/usr/sbin:/bin:/sbin',
) {

  mysql_user { "${backupuser}@localhost":
    ensure        => $ensure,
    password_hash => mysql_password($backuppassword),
    provider      => 'mysql',
    require       => Class['mysql::server::root_password'],
  }

  mysql_grant { "${backupuser}@localhost/*.*":
    ensure     => present,
    user       => "${backupuser}@localhost",
    table      => '*.*',
    privileges => [ 'SELECT', 'RELOAD', 'LOCK TABLES', 'SHOW VIEW', 'PROCESS' ],
    require    => Mysql_user["${backupuser}@localhost"],
  }

  cron { 'mysql-backup':
    ensure  => $ensure,
    command => '/usr/local/sbin/mysqlbackup.sh',
    user    => 'root',
    hour    => $time[0],
    minute  => $time[1],
    require => File['mysqlbackup.sh'],
  }

  file { 'mysqlbackup.sh':
    ensure  => $ensure,
    path    => '/usr/local/sbin/mysqlbackup.sh',
    mode    => '0700',
    owner   => 'root',
    group   => 'root',
    content => template('mysql/mysqlbackup.sh.erb'),
  }

  file { 'mysqlbackupdir':
    ensure => 'directory',
    path   => $backupdir,
    mode   => $backupdirmode,
    owner  => $backupdirowner,
    group  => $backupdirgroup,
  }

}
# See README.me for options.
class mysql::server::config {

  $options = $mysql::server::options

  File {
    owner  => 'root',
    group  => $mysql::server::root_group,
    mode   => '0400',
  }

  file { '/etc/mysql':
    ensure => directory,
    mode   => '0755',
  }

  file { '/etc/mysql/conf.d':
    ensure  => directory,
    mode    => '0755',
    recurse => $mysql::server::purge_conf_dir,
    purge   => $mysql::server::purge_conf_dir,
  }

  if $mysql::server::manage_config_file  {
    file { $mysql::server::config_file:
      content => template('mysql/my.cnf.erb'),
      mode    => '0644',
    }
  }

  if $options['mysqld']['ssl-disable'] {
    notify {'ssl-disable':
      message =>'Disabling SSL is evil! You should never ever do this except if you are forced to use a mysql version compiled without SSL support'
    }
  }
}
#
class mysql::server::install {

  package { 'mysql-server':
    ensure => $mysql::server::package_ensure,
    name   => $mysql::server::package_name,
  }

}
#This is a helper class to add a monitoring user to the database
class mysql::server::monitor (
  $mysql_monitor_username,
  $mysql_monitor_password,
  $mysql_monitor_hostname
) {

  Anchor['mysql::server::end'] -> Class['mysql::server::monitor']

  mysql_user { "${mysql_monitor_username}@${mysql_monitor_hostname}":
    ensure        => present,
    password_hash => mysql_password($mysql_monitor_password),
    require       => Class['mysql::server::service'],
  }

  mysql_grant { "${mysql_monitor_username}@${mysql_monitor_hostname}/*.*":
    ensure     => present,
    user       => "${mysql_monitor_username}@${mysql_monitor_hostname}",
    table      => '*.*',
    privileges => [ 'PROCESS', 'SUPER' ],
    require    => Mysql_user["${mysql_monitor_username}@${mysql_monitor_hostname}"],
  }

}
#
class mysql::server::mysqltuner($ensure='present') {
  # mysql performance tester
  file { '/usr/local/bin/mysqltuner':
    ensure  => $ensure,
    mode    => '0550',
    source  => 'puppet:///modules/mysql/mysqltuner.pl',
  }
}
# Convenience class to call each of the three providers with the corresponding
# hashes provided in mysql::server.
# See README.md for details.
class mysql::server::providers {
  create_resources('mysql_user', $mysql::server::users)
  create_resources('mysql_grant', $mysql::server::grants)
  create_resources('mysql_database', $mysql::server::databases)
}
#
class mysql::server::root_password {

  $options = $mysql::server::options

  # manage root password if it is set
  if $mysql::server::root_password != 'UNSET' {
    mysql_user { 'root@localhost':
      ensure        => present,
      password_hash => mysql_password($mysql::server::root_password),
    }

    file { "${::root_home}/.my.cnf":
      content => template('mysql/my.cnf.pass.erb'),
      owner   => 'root',
      mode    => '0600',
      require => Mysql_user['root@localhost'],
    }
  }

}
#
class mysql::server::service {

  if $mysql::server::real_service_enabled {
    $service_ensure = 'running'
  } else {
    $service_ensure = 'stopped'
  }

  if $mysql::server::real_service_manage {
    file { $mysql::params::log_error:
      owner => 'mysql',
      group => 'mysql',
    }
    service { 'mysqld':
      ensure   => $service_ensure,
      name     => $mysql::server::service_name,
      enable   => $mysql::server::real_service_enabled,
      provider => $mysql::server::service_provider,
    }
  }

}
{
  "name": "puppetlabs-mysql",
  "version": "2.3.1",
  "author": "Puppet Labs",
  "summary": "Mysql module",
  "license": "Apache 2.0",
  "source": "git://github.com/puppetlabs/puppetlabs-mysql.git",
  "project_page": "http://github.com/puppetlabs/puppetlabs-mysql",
  "issues_url": "https://github.com/puppetlabs/puppetlabs-mysql/issues",
  "operatingsystem_support": [
    {
      "operatingsystem": "RedHat",
      "operatingsystemrelease": [
        "5",
        "6",
        "7"
      ]
    },
    {
      "operatingsystem": "CentOS",
      "operatingsystemrelease": [
        "5",
        "6",
        "7"
      ]
    },
    {
      "operatingsystem": "OracleLinux",
      "operatingsystemrelease": [
        "5",
        "6",
        "7"
      ]
    },
    {
      "operatingsystem": "Scientific",
      "operatingsystemrelease": [
        "5",
        "6",
        "7"
      ]
    },
    {
      "operatingsystem": "SLES",
      "operatingsystemrelease": [
        "11 SP1"
      ]
    },
    {
      "operatingsystem": "Debian",
      "operatingsystemrelease": [
        "6",
        "7"
      ]
    },
    {
      "operatingsystem": "Ubuntu",
      "operatingsystemrelease": [
        "10.04",
        "12.04",
        "14.04"
      ]
    }
  ],
  "requirements": [
    {
      "name": "pe",
      "version_requirement": ">= 3.2.0 < 3.4.0"
    },
    {
      "name": "puppet",
      "version_requirement": "3.x"
    }
  ],
  "description": "Mysql module",
  "dependencies": [
    {
      "name": "puppetlabs/stdlib",
      "version_requirement": ">= 3.2.0"
    }
  ]
}
require 'spec_helper_acceptance'

describe 'mysql::server::account_security class', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'running puppet code' do
    it 'should work with no errors' do
      pp = <<-EOS
        class { 'mysql::server': remove_default_accounts => true }
      EOS

      # Run it twice and test for idempotency
      apply_manifest(pp, :catch_failures => true)
      expect(apply_manifest(pp, :catch_failures => true).exit_code).to be_zero
    end

    describe 'accounts' do
      it 'should delete accounts' do
        shell("mysql -e 'show grants for root@127.0.0.1;'", :acceptable_exit_codes => 1)
      end

      it 'should delete databases' do
        shell("mysql -e 'show databases;' |grep test", :acceptable_exit_codes => 1)
      end
    end
  end
end
require 'spec_helper_acceptance'

describe 'mysql::server::backup class', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  context 'should work with no errors' do
    it 'when configuring mysql backups' do
      pp = <<-EOS
        class { 'mysql::server': root_password => 'password' }
        mysql::db { [
          'backup1',
          'backup2'
        ]:
          user     => 'backup',
          password => 'secret',
        }

        package { 'bzip2':
          ensure => present,
        }

        class { 'mysql::server::backup':
          backupuser     => 'myuser',
          backuppassword => 'mypassword',
          backupdir      => '/tmp/backups',
          backupcompress => true,
          postscript     => [
            'rm -rf /var/tmp/mysqlbackups',
            'rm -f /var/tmp/mysqlbackups.done',
            'cp -r /tmp/backups /var/tmp/mysqlbackups',
            'touch /var/tmp/mysqlbackups.done',
          ],
          execpath      => '/usr/bin:/usr/sbin:/bin:/sbin:/opt/zimbra/bin',
          require       => Package['bzip2'],
        }
      EOS

      apply_manifest(pp, :catch_failures => true)
      apply_manifest(pp, :catch_failures => true)
    end
  end

  describe 'mysqlbackup.sh' do
    it 'should run mysqlbackup.sh with no errors' do
      shell("/usr/local/sbin/mysqlbackup.sh") do |r|
        expect(r.stderr).to eq("")
      end
    end

    it 'should dump all databases to single file' do
      shell('ls -l /tmp/backups/mysql_backup_*-*.sql.bz2 | wc -l') do |r|
        expect(r.stdout).to match(/1/)
        expect(r.exit_code).to be_zero
      end
    end

    context 'should create one file per database per run' do
      it 'executes mysqlbackup.sh a second time' do
        shell('sleep 1')
        shell('/usr/local/sbin/mysqlbackup.sh')
      end

      it 'creates at least one backup tarball' do
        shell('ls -l /tmp/backups/mysql_backup_*-*.sql.bz2 | wc -l') do |r|
          expect(r.stdout).to match(/2/)
          expect(r.exit_code).to be_zero
        end
      end
    end
  end
end
require 'spec_helper_acceptance'

osfamily = fact('osfamily')
operatingsystem = fact('operatingsystem')
ruby_package_provider = 'undef'

case osfamily
when 'RedHat'
  java_package   = 'mysql-connector-java'
  perl_package   = 'perl-DBD-MySQL'
  php_package    = 'php-mysql'
  python_package = 'MySQL-python'
  ruby_package   = 'ruby-mysql'
  if fact('operatingsystemmajrelease') == '7'
    ruby_package_provider = 'gem'
  end
when 'Suse'
  java_package   = 'mysql-connector-java'
  perl_package   = 'perl-DBD-mysql'
  php_package    = 'apache2-mod_php53'
  python_package = 'python-mysql'
  case operatingsystem
  when /OpenSuSE/
    ruby_package = 'rubygem-mysql'
  when /(SLES|SLED)/
    ruby_package = 'ruby-mysql'
  end
when 'Debian'
  java_package = 'libmysql-java'
  perl_package     = 'libdbd-mysql-perl'
  php_package      = 'php5-mysql'
  python_package   = 'python-mysqldb'
  if fact('lsbdistcodename') == 'trusty'
    ruby_package   = 'ruby-mysql'
  else
    ruby_package   = 'libmysql-ruby'
  end
when 'FreeBSD'
  java_package = 'databases/mysql-connector-java'
  perl_package   = 'p5-DBD-mysql'
  php_package    = 'php5-mysql'
  python_package = 'databases/py-MySQLdb'
  ruby_package   = 'ruby-mysql'
else
  case operatingsystem
  when 'Amazon'
    java_package = 'mysql-connector-java'
    perl_package   = 'perl-DBD-MySQL'
    php_package    = 'php5-mysql'
    python_package = 'MySQL-python'
    ruby_package   = 'ruby-mysql'
  end
end

describe 'mysql::bindings class', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do

  if fact('osfamily') == 'RedHat' and fact('operatingsystemmajrelease') =~ /(5|6)/
    it 'adds epel' do
      pp = "class { 'epel': }"
      apply_manifest(pp, :catch_failures => true)
    end
  end

  describe 'running puppet code' do
    it 'should work with no errors' do
      pp = <<-EOS
        class { 'mysql::bindings': }
      EOS

      # Run it twice and test for idempotency
      apply_manifest(pp, :catch_failures => true)
      expect(apply_manifest(pp, :catch_failures => true).exit_code).to be_zero
    end
  end

  describe 'all parameters' do
    it 'should work with no errors' do
      pp = <<-EOS
        class { 'mysql::bindings':
          java_enable             => true,
          perl_enable             => true,
          php_enable              => true,
          python_enable           => true,
          ruby_enable             => true,
          java_package_ensure     => present,
          perl_package_ensure     => present,
          php_package_ensure      => present,
          python_package_ensure   => present,
          ruby_package_ensure     => present,
          java_package_name       => #{java_package},
          perl_package_name       => #{perl_package},
          php_package_name        => #{php_package},
          python_package_name     => #{python_package},
          ruby_package_name       => #{ruby_package},
          java_package_provider   => undef,
          perl_package_provider   => undef,
          php_package_provider    => undef,
          python_package_provider => undef,
          ruby_package_provider   => #{ruby_package_provider},
        }
      EOS

      # Run it twice and test for idempotency
      apply_manifest(pp, :catch_failures => true)
      expect(apply_manifest(pp, :catch_failures => true).exit_code).to be_zero
    end

    describe package(java_package) do
      it { should be_installed }
    end

    describe package(perl_package) do
      it { should be_installed }
    end

    # This package is not available out of the box and adding in other repos
    # is a bit much for the scope of this test.
    unless fact('osfamily') == 'RedHat'
      describe package(php_package) do
        it { should be_installed }
      end
    end

    describe package(python_package) do
      it { should be_installed }
    end

    # ruby-mysql is installed via gem on RHEL7, be_installed doesn't know how to check that
    if fact('osfamily') == 'RedHat' && fact('operatingsystemmajrelease') == '7'
      describe package(ruby_package) do
        it { should_not be_installed }
      end
    else
      describe package(ruby_package) do
        it { should be_installed }
      end
    end
  end
end
require 'spec_helper_acceptance'

describe 'mysql::db define', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'creating a database' do
    # Using puppet_apply as a helper
    it 'should work with no errors' do
      pp = <<-EOS
        class { 'mysql::server': root_password => 'password' }
        mysql::db { 'spec1':
          user     => 'root1',
          password => 'password',
        }
      EOS

      # Run it twice and test for idempotency
      apply_manifest(pp, :catch_failures => true)
      apply_manifest(pp, :catch_changes => true)

      expect(shell("mysql -e 'show databases;'|grep spec1").exit_code).to be_zero
    end
  end

  describe 'creating a database with post-sql' do
    # Using puppet_apply as a helper
    it 'should work with no errors' do
      pp = <<-EOS
        class { 'mysql::server': override_options => { 'root_password' => 'password' } }
        file { '/tmp/spec.sql':
          ensure  => file,
          content => 'CREATE TABLE table1 (id int);',
          before  => Mysql::Db['spec2'],
        }
        mysql::db { 'spec2':
          user     => 'root1',
          password => 'password',
          sql      => '/tmp/spec.sql',
        }
      EOS

      # Run it twice and test for idempotency
      apply_manifest(pp, :catch_failures => true)
      apply_manifest(pp, :catch_changes => true)
    end

    it 'should have the table' do
      expect(shell("mysql -e 'show tables;' spec2|grep table1").exit_code).to be_zero
    end
  end

  describe 'creating a database with dbname parameter' do
    # Using puppet_apply as a helper
    it 'should work with no errors' do
      pp = <<-EOS
        class { 'mysql::server': override_options => { 'root_password' => 'password' } }
        mysql::db { 'spec1':
          user     => 'root1',
          password => 'password',
	  dbname   => 'realdb',
        }
      EOS

      # Run it twice and test for idempotency
      apply_manifest(pp, :catch_failures => true)
      apply_manifest(pp, :catch_changes => true)
    end

    it 'should have the database named realdb' do
      expect(shell("mysql -e 'show databases;'|grep realdb").exit_code).to be_zero
    end
  end
end
require 'spec_helper_acceptance'

describe 'config location', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  it 'creates the file elsewhere' do
    pp = <<-EOS
        class { 'mysql::server':
          config_file => '/etc/testmy.cnf',
        }
    EOS
    apply_manifest(pp, :catch_failures => true)
  end

  describe file('/etc/testmy.cnf') do
    it { should be_file }
  end
end

describe 'manage_config_file', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  it 'wont reset the location of my.cnf' do
    pp = <<-EOS
      class { 'mysql::server':
        config_file        => '/etc/my.cnf',
        manage_config_file => false,
        service_manage     => false,
      }
    EOS
    # Make sure this doesn't exist so we can test if puppet
    # readded it.  It may not exist in the first place on
    # some platforms.
    shell('rm /etc/my.cnf', :acceptable_exit_codes => [0,1,2])
    apply_manifest(pp, :catch_failures => true)
  end

  describe file('/etc/my.cnf') do
    it { should_not be_file }
  end
end

describe 'resets', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  it 'cleans up' do
    pp = <<-EOS
        class { 'mysql::server': }
    EOS
    apply_manifest(pp, :catch_failures => true)
    shell('rm /etc/testmy.cnf')
  end
end
require 'spec_helper_acceptance'

describe 'mysql::server::monitor class', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  it 'should work with no errors' do
    pp = <<-EOS
      class { 'mysql::server': root_password => 'password' }

      class { 'mysql::server::monitor':
        mysql_monitor_username => 'monitoruser',
        mysql_monitor_password => 'monitorpass',
        mysql_monitor_hostname => 'localhost',
      }
    EOS

    apply_manifest(pp, :catch_failures => true)
    expect(apply_manifest(pp, :catch_failures => true).exit_code).to be_zero
  end

  it 'should run mysqladmin ping with no errors' do
    expect(shell("mysqladmin -u monitoruser -pmonitorpass -h localhost ping").stdout).to match(/mysqld is alive/)
  end
end
require 'spec_helper_acceptance'

describe 'mysql::server::root_password class', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do

  describe 'reset' do
    it 'shuts down mysql' do
      pp = <<-EOS
      class { 'mysql::server': service_enabled => false }
      EOS

      apply_manifest(pp, :catch_failures => true)
    end

    it 'deletes the /root/.my.cnf password' do
      shell('rm -rf /root/.my.cnf')
    end

    it 'deletes all databases' do
      case fact('osfamily')
      when 'RedHat', 'Suse'
        shell('grep -q datadir /etc/my.cnf && rm -rf `grep datadir /etc/my.cnf | cut -d" " -f 3`/*')
      when 'Debian'
        shell('rm -rf `grep datadir /etc/mysql/my.cnf | cut -d" " -f 3`/*')
        shell('mysql_install_db')
      end
    end

    it 'starts up mysql' do
      pp = <<-EOS
      class { 'mysql::server': service_enabled => true }
      EOS

      puppet_apply(pp, :catch_failures => true)
    end
  end

  describe 'when unset' do
    it 'should work' do
      pp = <<-EOS
        class { 'mysql::server': root_password => 'test' }
      EOS

      # Run it twice and test for idempotency
      apply_manifest(pp, :catch_failures => true)
      expect(apply_manifest(pp, :catch_failures => true).exit_code).to be_zero
    end
  end

  describe 'when set' do
    it 'should work' do
      pp = <<-EOS
        class { 'mysql::server': root_password => 'new', old_root_password => 'test' }
      EOS

      # Run it twice and test for idempotency
      apply_manifest(pp, :catch_failures => true)
      expect(apply_manifest(pp, :catch_failures => true).exit_code).to be_zero
    end
  end
end

# Debian relies on a debian-sys-maint@ account to do almost everything.
# Without recreating this account we can't even stop the service in future
# tests.
if fact('osfamily') == 'Debian'
  describe 'readd debian user' do
    it 'readds the user' do
      shell("MYSQL_PASSWORD=`head -5 /etc/mysql/debian.cnf | grep password | cut -d' ' -f 3`; mysql -NBe \"GRANT ALL PRIVILEGES ON *.* to 'debian-sys-maint'@'localhost' IDENTIFIED BY '${MYSQL_PASSWORD}' WITH GRANT OPTION;\"")
    end
  end
end
require 'spec_helper_acceptance'

describe 'mysql class', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  case fact('osfamily')
  when 'RedHat'
    if fact('operatingsystemmajrelease') == '7'
      package_name     = 'mariadb-server'
      service_name     = 'mariadb'
      service_provider = 'undef'
      mycnf            = '/etc/my.cnf'
    else
      package_name     = 'mysql-server'
      service_name     = 'mysqld'
      service_provider = 'undef'
      mycnf            = '/etc/my.cnf'
    end
  when 'Suse'
    case fact('operatingsystem')
    when 'OpenSuSE'
      package_name     = 'mysql-community-server'
      service_name     = 'mysql'
      service_provider = 'undef'
      mycnf            = '/etc/my.cnf'
    when 'SLES'
      package_name     = 'mysql'
      service_name     = 'mysql'
      service_provider = 'undef'
      mycnf            = '/etc/my.cnf'
    end
  when 'Debian'
    package_name     = 'mysql-server'
    service_name     = 'mysql'
    service_provider = 'undef'
    mycnf            = '/etc/mysql/my.cnf'
  when 'Ubuntu'
    package_name     = 'mysql-server'
    service_name     = 'mysql'
    service_provider = 'upstart'
    mycnf            = '/etc/mysql/my.cnf'
  end

  describe 'running puppet code' do
    # Using puppet_apply as a helper
    it 'should work with no errors' do
      pp = <<-EOS
        class { 'mysql::server': }
      EOS

      # Run it twice and test for idempotency
      apply_manifest(pp, :catch_failures => true)
      expect(apply_manifest(pp, :catch_failures => true).exit_code).to be_zero
    end

    describe package(package_name) do
      it { should be_installed }
    end

    describe service(service_name) do
      it { should be_running }
      it { should be_enabled }
    end
  end

  describe 'mycnf' do
    it 'should contain sensible values' do
      pp = <<-EOS
        class { 'mysql::server': }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe file(mycnf) do
      it { should contain 'key_buffer_size = 16M' }
      it { should contain 'max_binlog_size = 100M' }
      it { should contain 'query_cache_size = 16M' }
    end
  end

  describe 'my.cnf changes' do
    it 'sets values' do
      pp = <<-EOS
        class { 'mysql::server':
          override_options => { 'mysqld' => 
            { 'key_buffer'       => '32M',
              'max_binlog_size'  => '200M',
              'query_cache_size' => '32M',
            }
          }  
        }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe file(mycnf) do
      it { should contain 'key_buffer = 32M' }
      it { should contain 'max_binlog_size = 200M' }
      it { should contain 'query_cache_size = 32M' }
    end
  end

  describe 'my.cnf should contain multiple instances of the same option' do
    it 'sets multiple values' do
      pp = <<-EOS
        class { 'mysql::server':
          override_options => { 'mysqld' => 
            { 'replicate-do-db' => ['base1', 'base2', 'base3'], }
          }  
        }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe file(mycnf) do
      it { should contain 'replicate-do-db = base1' }
      it { should contain 'replicate-do-db = base2' }
      it { should contain 'replicate-do-db = base3' }
    end
  end

  describe 'package_ensure => absent' do
    it 'uninstalls mysql' do
      pp = <<-EOS
        class { 'mysql::server':
          service_enabled => false,
          package_ensure  => absent,
          package_name    => #{package_name}
        }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe package(package_name) do
      it { should_not be_installed }
    end
  end

  describe 'package_ensure => present' do
    it 'installs mysql' do
      pp = <<-EOS
        class { 'mysql::server':
          package_ensure => present,
          package_name   => #{package_name}
        }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe package(package_name) do
      it { should be_installed }
    end
  end

  describe 'purge_conf_dir' do

    it 'purges the conf dir' do
      pp = <<-EOS
        class { 'mysql::server':
          purge_conf_dir => true
        }
      EOS
      shell('touch /etc/mysql/conf.d/test.conf')
      apply_manifest(pp, :catch_failures => true)
    end

    describe file('/etc/mysql/conf.d/test.conf') do
      it { should_not be_file }
    end
  end

  describe 'restart' do
    it 'restart => true' do
      pp = <<-EOS
        class { 'mysql::server':
          restart          => true,
          override_options => { 'mysqldump' => { 'default-character-set' => 'UTF-8' } }
        }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.exit_code).to eq(2)
        expect(r.stdout).to match(/Scheduling refresh/)
      end
    end
    it 'restart => false' do
      pp = <<-EOS
        class { 'mysql::server':
          restart          => false,
          override_options => { 'mysqldump' => { 'default-character-set' => 'UTF-16' } }
        }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.exit_code).to eq(2)
        expect(r.stdout).to_not match(/Scheduling refresh/)
      end
    end
  end

  describe 'root_group' do
    it 'creates a group' do
      pp = "group { 'test': ensure => present }"
      apply_manifest(pp, :catch_failures => true)
    end

    it 'sets the group of files' do
      pp = <<-EOS
        class { 'mysql::server':
          root_group => 'test',
          config_file => '/tmp/mysql_group_test',
        }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe file('/tmp/mysql_group_test') do
      it { should be_grouped_into 'test' }
    end
  end

  describe 'service parameters' do
    it 'calls all parameters' do
      pp = <<-EOS
      class { 'mysql::server':
        service_enabled  => true,
        service_manage   => true,
        service_name     => #{service_name},
        service_provider => #{service_provider}
      }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end
  end

  describe 'users, grants, and databases' do
    it 'are created' do
      pp = <<-EOS
      class { 'mysql::server':
        users => {
          'zerg1@localhost' => {
            ensure                   => 'present',
            max_connections_per_hour => '0',
            max_queries_per_hour     => '0',
            max_updates_per_hour     => '0',
            max_user_connections     => '0',
            password_hash            => '*F3A2A51A9B0F2BE2468926B4132313728C250DBF',
          }
        },
        grants => {
          'zerg1@localhost/zergdb.*' => {
            ensure     => 'present',
            options    => ['GRANT'],
            privileges => ['SELECT', 'INSERT', 'UPDATE', 'DELETE'],
            table      => 'zergdb.*',
            user       => 'zerg1@localhost',
          }
        },
        databases => {
          'zergdb' => {
            ensure  => 'present',
            charset => 'utf8',
          }
        },
      }
    EOS
      apply_manifest(pp, :catch_failures => true)
    end

    it 'has a user' do
      shell("mysql -NBe \"select '1' from mysql.user where CONCAT(user, '@', host) = 'zerg1@localhost'\"") do |r|
        expect(r.stdout).to match(/^1$/)
        expect(r.stderr).to be_empty
      end
    end
    it 'has a grant' do
      shell("mysql -NBe \"SHOW GRANTS FOR zerg1@localhost\"") do |r|
        expect(r.stdout).to match(/GRANT SELECT, INSERT, UPDATE, DELETE ON `zergdb`.* TO 'zerg1'@'localhost' WITH GRANT OPTION/)
        expect(r.stderr).to be_empty
      end
    end
    it 'has a database' do
      shell("mysql -NBe \"SHOW DATABASES LIKE 'zergdb'\"") do |r|
        expect(r.stdout).to match(/zergdb/)
        expect(r.stderr).to be_empty
      end
    end
  end

end
HOSTS:
  centos-510-x64:
    roles:
      - master
    platform: el-5-x86_64
    box : centos-510-x64-virtualbox-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-510-x64-virtualbox-nocm.box
    hypervisor : vagrant
CONFIG:
  type: git
HOSTS:
  centos-59-x64:
    roles:
      - master
    platform: el-5-x86_64
    box : centos-59-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-59-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: git
HOSTS:
  centos-64-x64:
    roles:
      - master
      - database
      - dashboard
    platform: el-6-x86_64
    box : centos-64-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: pe
HOSTS:
  centos-65-x64:
    roles:
      - master
    platform: el-6-x86_64
    box : centos-65-x64-vbox436-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-65-x64-virtualbox-nocm.box
    hypervisor : vagrant
CONFIG:
  type: foss
HOSTS:
  centos-64-x64:
    roles:
      - master
    platform: el-6-x86_64
    box : centos-64-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: foss
HOSTS:
  fedora-18-x64:
    roles:
      - master
    platform: fedora-18-x86_64
    box : fedora-18-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/fedora-18-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: foss
HOSTS:
  sles-11-x64.local:
    roles:
      - master
    platform: sles-11-x64
    box : sles-11sp1-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/sles-11sp1-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
    type: foss
HOSTS:
  ubuntu-server-10044-x64:
    roles:
      - master
    platform: ubuntu-10.04-amd64
    box : ubuntu-server-10044-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/ubuntu-server-10044-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: foss
HOSTS:
  ubuntu-server-12042-x64:
    roles:
      - master
    platform: ubuntu-12.04-amd64
    box : ubuntu-server-12042-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/ubuntu-server-12042-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: foss
HOSTS:
  ubuntu-server-1404-x64:
    roles:
      - master
    platform: ubuntu-14.04-amd64
    box : puppetlabs/ubuntu-14.04-64-nocm
    box_url : https://vagrantcloud.com/puppetlabs/ubuntu-14.04-64-nocm
    hypervisor : vagrant
CONFIG:
  log_level   : debug
  type: git
require 'spec_helper_acceptance'

describe 'mysql_database', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'setup' do
    it 'should work with no errors' do
      pp = <<-EOS
        class { 'mysql::server': }
      EOS

      apply_manifest(pp, :catch_failures => true)
    end
  end

  describe 'creating database' do
    it 'should work without errors' do
      pp = <<-EOS
        mysql_database { 'spec_db':
          ensure => present,
        }
      EOS

      apply_manifest(pp, :catch_failures => true)
    end

    it 'should find the database' do
      shell("mysql -NBe \"SHOW DATABASES LIKE 'spec_db'\"") do |r|
        expect(r.stdout).to match(/^spec_db$/)
        expect(r.stderr).to be_empty
      end
    end
  end

  describe 'charset and collate' do
    it 'should create two db of different types idempotently' do
      pp = <<-EOS
        mysql_database { 'spec_latin1':
          charset => 'latin1',
          collate => 'latin1_swedish_ci',
        }
        mysql_database { 'spec_utf8':
          charset => 'utf8',
          collate => 'utf8_general_ci',
        }
      EOS

      apply_manifest(pp, :catch_failures => true)
      apply_manifest(pp, :catch_changes => true)
    end

    it 'should find latin1 db' do
      shell("mysql -NBe \"SHOW VARIABLES LIKE '%_database'\" spec_latin1") do |r|
        expect(r.stdout).to match(/^character_set_database\tlatin1\ncollation_database\tlatin1_swedish_ci$/)
        expect(r.stderr).to be_empty
      end
    end

    it 'should find utf8 db' do
      shell("mysql -NBe \"SHOW VARIABLES LIKE '%_database'\" spec_utf8") do |r|
        expect(r.stdout).to match(/^character_set_database\tutf8\ncollation_database\tutf8_general_ci$/)
        expect(r.stderr).to be_empty
      end
    end
  end
end
require 'spec_helper_acceptance'

describe 'mysql_grant', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do

  describe 'setup' do
    it 'setup mysql::server' do
      pp = <<-EOS
        class { 'mysql::server': }
      EOS

      apply_manifest(pp, :catch_failures => true)
    end
  end

  describe 'missing privileges for user' do
    it 'should fail' do
      pp = <<-EOS
        mysql_grant { 'test1@tester/test.*':
          ensure => 'present',
          table  => 'test.*',
          user   => 'test1@tester',
        }
      EOS

      expect(apply_manifest(pp, :expect_failures => true).stderr).to match(/privileges parameter is required/)
    end

    it 'should not find the user' do
      expect(shell("mysql -NBe \"SHOW GRANTS FOR test1@tester\"", { :acceptable_exit_codes => 1}).stderr).to match(/There is no such grant defined for user 'test1' on host 'tester'/)
    end
  end

  describe 'missing table for user' do
    it 'should fail' do
      pp = <<-EOS
        mysql_grant { 'atest@tester/test.*':
          ensure => 'present',
          user   => 'atest@tester',
          privileges => ['ALL'],
        }
      EOS

      apply_manifest(pp, :expect_failures => true)
    end

    it 'should not find the user' do
      expect(shell("mysql -NBe \"SHOW GRANTS FOR atest@tester\"", {:acceptable_exit_codes => 1}).stderr).to match(/There is no such grant defined for user 'atest' on host 'tester'/)
    end
  end

  describe 'adding privileges' do
    it 'should work without errors' do
      pp = <<-EOS
        mysql_grant { 'test2@tester/test.*':
          ensure     => 'present',
          table      => 'test.*',
          user       => 'test2@tester',
          privileges => ['SELECT', 'UPDATE'],
        }
      EOS

      apply_manifest(pp, :catch_failures => true)
    end

    it 'should find the user' do
      shell("mysql -NBe \"SHOW GRANTS FOR test2@tester\"") do |r|
        expect(r.stdout).to match(/GRANT SELECT, UPDATE.*TO 'test2'@'tester'/)
        expect(r.stderr).to be_empty
      end
    end
  end

  describe 'adding option' do
    it 'should work without errors' do
      pp = <<-EOS
        mysql_grant { 'test3@tester/test.*':
          ensure  => 'present',
          table   => 'test.*',
          user    => 'test3@tester',
          options => ['GRANT'],
          privileges => ['SELECT', 'UPDATE'],
        }
      EOS

      apply_manifest(pp, :catch_failures => true)
    end

    it 'should find the user' do
      shell("mysql -NBe \"SHOW GRANTS FOR test3@tester\"") do |r|
        expect(r.stdout).to match(/GRANT SELECT, UPDATE ON `test`.* TO 'test3'@'tester' WITH GRANT OPTION$/)
        expect(r.stderr).to be_empty
      end
    end
  end

  describe 'adding all privileges without table' do
    it 'should fail' do
      pp = <<-EOS
        mysql_grant { 'test4@tester/test.*':
          ensure     => 'present',
          user       => 'test4@tester',
          options    => ['GRANT'],
          privileges => ['SELECT', 'UPDATE', 'ALL'],
        }
      EOS

      expect(apply_manifest(pp, :expect_failures => true).stderr).to match(/table parameter is required./)
    end
  end

  describe 'adding all privileges' do
    it 'should only try to apply ALL' do
      pp = <<-EOS
        mysql_grant { 'test4@tester/test.*':
          ensure     => 'present',
          table      => 'test.*',
          user       => 'test4@tester',
          options    => ['GRANT'],
          privileges => ['SELECT', 'UPDATE', 'ALL'],
        }
      EOS

      apply_manifest(pp, :catch_failures => true)
    end

    it 'should find the user' do
      shell("mysql -NBe \"SHOW GRANTS FOR test4@tester\"") do |r|
        expect(r.stdout).to match(/GRANT ALL PRIVILEGES ON `test`.* TO 'test4'@'tester' WITH GRANT OPTION/)
        expect(r.stderr).to be_empty
      end
    end
  end

  # Test combinations of user@host to ensure all cases work.
  describe 'short hostname' do
    it 'should apply' do
      pp = <<-EOS
        mysql_grant { 'test@short/test.*':
          ensure     => 'present',
          table      => 'test.*',
          user       => 'test@short',
          privileges => 'ALL',
        }
        mysql_grant { 'test@long.hostname.com/test.*':
          ensure     => 'present',
          table      => 'test.*',
          user       => 'test@long.hostname.com',
          privileges => 'ALL',
        }
        mysql_grant { 'test@192.168.5.6/test.*':
          ensure     => 'present',
          table      => 'test.*',
          user       => 'test@192.168.5.6',
          privileges => 'ALL',
        }
        mysql_grant { 'test@2607:f0d0:1002:0051:0000:0000:0000:0004/test.*':
          ensure     => 'present',
          table      => 'test.*',
          user       => 'test@2607:f0d0:1002:0051:0000:0000:0000:0004',
          privileges => 'ALL',
        }
        mysql_grant { 'test@::1/128/test.*':
          ensure     => 'present',
          table      => 'test.*',
          user       => 'test@::1/128',
          privileges => 'ALL',
        }
      EOS

      apply_manifest(pp, :catch_failures => true)
    end

    it 'finds short hostname' do
      shell("mysql -NBe \"SHOW GRANTS FOR test@short\"") do |r|
        expect(r.stdout).to match(/GRANT ALL PRIVILEGES ON `test`.* TO 'test'@'short'/)
        expect(r.stderr).to be_empty
      end
    end
    it 'finds long hostname' do
      shell("mysql -NBe \"SHOW GRANTS FOR 'test'@'long.hostname.com'\"") do |r|
        expect(r.stdout).to match(/GRANT ALL PRIVILEGES ON `test`.* TO 'test'@'long.hostname.com'/)
        expect(r.stderr).to be_empty
      end
    end
    it 'finds ipv4' do
      shell("mysql -NBe \"SHOW GRANTS FOR 'test'@'192.168.5.6'\"") do |r|
        expect(r.stdout).to match(/GRANT ALL PRIVILEGES ON `test`.* TO 'test'@'192.168.5.6'/)
        expect(r.stderr).to be_empty
      end
    end
    it 'finds ipv6' do
      shell("mysql -NBe \"SHOW GRANTS FOR 'test'@'2607:f0d0:1002:0051:0000:0000:0000:0004'\"") do |r|
        expect(r.stdout).to match(/GRANT ALL PRIVILEGES ON `test`.* TO 'test'@'2607:f0d0:1002:0051:0000:0000:0000:0004'/)
        expect(r.stderr).to be_empty
      end
    end
    it 'finds short ipv6' do
      shell("mysql -NBe \"SHOW GRANTS FOR 'test'@'::1/128'\"") do |r|
        expect(r.stdout).to match(/GRANT ALL PRIVILEGES ON `test`.* TO 'test'@'::1\/128'/)
        expect(r.stderr).to be_empty
      end
    end
  end

  describe 'complex test' do
    it 'setup mysql::server' do
      pp = <<-EOS
      $dbSubnet = '10.10.10.%'

      mysql_database { 'foo':
        ensure => present,
      }

      exec { 'mysql-create-table':
        command     => '/usr/bin/mysql -NBe "CREATE TABLE foo.bar (name VARCHAR(20))"',
        environment => "HOME=${::root_home}",
        unless      => '/usr/bin/mysql -NBe "SELECT 1 FROM foo.bar LIMIT 1;"',
        require     => Mysql_database['foo'],
      }

      Mysql_grant {
          ensure     => present,
          options    => ['GRANT'],
          privileges => ['ALL'],
          table      => '*.*',
          require    => [ Mysql_database['foo'], Exec['mysql-create-table'] ],
      }

      mysql_grant { "user1@${dbSubnet}/*.*":
          user       => "user1@${dbSubnet}",
      }
      mysql_grant { "user2@${dbSubnet}/foo.bar":
          privileges => ['SELECT', 'INSERT', 'UPDATE'],
          user       => "user2@${dbSubnet}",
          table      => 'foo.bar',
      }
      mysql_grant { "user3@${dbSubnet}/foo.*":
          privileges => ['SELECT', 'INSERT', 'UPDATE'],
          user       => "user3@${dbSubnet}",
          table      => 'foo.*',
      }
      mysql_grant { 'web@%/*.*':
          user       => 'web@%',
      }
      mysql_grant { "web@${dbSubnet}/*.*":
          user       => "web@${dbSubnet}",
      }
      mysql_grant { "web@${fqdn}/*.*":
          user       => "web@${fqdn}",
      }
      mysql_grant { 'web@localhost/*.*':
          user       => 'web@localhost',
      }
      EOS

      apply_manifest(pp, :catch_failures => true)
      apply_manifest(pp, :catch_changes => true)
    end
  end

  describe 'lower case privileges' do
    it 'create ALL privs' do
      pp = <<-EOS
      mysql_grant { 'lowercase@localhost/*.*':
          user       => 'lowercase@localhost',
          privileges => 'ALL',
          table      => '*.*',
      }
      EOS

      apply_manifest(pp, :catch_failures => true)
    end

    it 'create lowercase all privs' do
      pp = <<-EOS
      mysql_grant { 'lowercase@localhost/*.*':
          user       => 'lowercase@localhost',
          privileges => 'all',
          table      => '*.*',
      }
      EOS

      expect(apply_manifest(pp, :catch_failures => true).exit_code).to eq(0)
    end
  end

  describe 'adding procedure privileges' do
    it 'should work without errors' do
       pp = <<-EOS
       mysql_grant { 'test2@tester/PROCEDURE test.simpleproc':
         ensure     => 'present',
         table      => 'PROCEDURE test.simpleproc',
         user       => 'test2@tester',
         privileges => ['EXECUTE'],
       }
       EOS

      apply_manifest(pp, :catch_failures => true)
    end

    it 'should find the user' do
      shell("mysql -NBe \"SHOW GRANTS FOR test2@tester\"") do |r|
        expect(r.stdout).to match(/GRANT EXECUTE ON PROCEDURE `test`.`simpleproc` TO 'test2'@'tester'/)
        expect(r.stderr).to be_empty
      end
    end
  end
end
require 'spec_helper_acceptance'

describe 'mysql_user', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'setup' do
    it 'should work with no errors' do
      pp = <<-EOS
        class { 'mysql::server': }
      EOS

      apply_manifest(pp, :catch_failures => true)
    end
  end

  describe 'adding user' do
    it 'should work without errors' do
      pp = <<-EOS
        mysql_user { 'ashp@localhost':
          password_hash => '6f8c114b58f2ce9e',
        }
      EOS

      apply_manifest(pp, :catch_failures => true)
    end

    it 'should find the user' do
      shell("mysql -NBe \"select '1' from mysql.user where CONCAT(user, '@', host) = 'ashp@localhost'\"") do |r|
        expect(r.stdout).to match(/^1$/)
        expect(r.stderr).to be_empty
      end
    end
  end
end
require 'spec_helper_acceptance'

describe 'unsupported distributions and OSes', :if => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  it 'should fail' do
    pp = <<-EOS
    class { 'mysql::server': }
    EOS
    expect(apply_manifest(pp, :expect_failures => true).stderr).to match(/unsupported osfamily/i)
  end
end
require 'spec_helper'

describe 'mysql::bindings' do
  let(:params) {{
    'java_enable'   => true,
    'perl_enable'   => true,
    'php_enable'    => true,
    'python_enable' => true,
    'ruby_enable'   => true,
  }}

  shared_examples 'bindings' do |osfamily, operatingsystem, operatingsystemrelease, java_name, perl_name, php_name, python_name, ruby_name|
    let :facts do
      { :osfamily => osfamily, :operatingsystem => operatingsystem,
        :operatingsystemrelease => operatingsystemrelease, :root_home => '/root',
      }
    end
    it { should contain_package('mysql-connector-java').with(
      :name   => java_name,
      :ensure => 'present'
    )}
    it { should contain_package('perl_mysql').with(
      :name     => perl_name,
      :ensure   => 'present'
    )}
    it { should contain_package('python-mysqldb').with(
      :name   => python_name,
      :ensure => 'present'
    )}
    it { should contain_package('ruby_mysql').with(
      :name     => ruby_name,
      :ensure   => 'present'
    )}
  end

  context 'Debian' do
    it_behaves_like 'bindings', 'Debian', 'Debian', '7.4','libmysql-java', 'libdbd-mysql-perl', 'php5-mysql', 'python-mysqldb', 'libmysql-ruby'
    it_behaves_like 'bindings', 'Debian', 'Ubuntu', '14.04', 'libmysql-java', 'libdbd-mysql-perl', 'php5-mysql', 'python-mysqldb', 'libmysql-ruby'
  end

  context 'freebsd' do
    it_behaves_like 'bindings', 'FreeBSD', 'FreeBSD', '10.0', 'databases/mysql-connector-java', 'p5-DBD-mysql', 'databases/php5-mysql', 'databases/py-MySQLdb', 'databases/ruby-mysql'
  end

  context 'redhat' do
    it_behaves_like 'bindings', 'RedHat', 'RedHat', '6.5', 'mysql-connector-java', 'perl-DBD-MySQL', 'php-mysql', 'MySQL-python', 'ruby-mysql'
    it_behaves_like 'bindings', 'RedHat', 'OpenSuSE', '11.3', 'mysql-connector-java', 'perl-DBD-MySQL', 'php-mysql', 'MySQL-python', 'ruby-mysql'
  end

  describe 'on any other os' do
    let :facts do
      {:osfamily => 'foo', :root_home => '/root'}
    end

    it 'should fail' do
      expect { subject }.to raise_error(/Unsupported osfamily: foo/)
    end
  end

end
describe 'mysql::client' do
  let(:facts) {{ :osfamily => 'RedHat' }}

  context 'with defaults' do
    it { should_not contain_class('mysql::bindings') }
    it { should contain_package('mysql_client') }
  end

  context 'with bindings enabled' do
    let(:params) {{ :bindings_enable => true }}

    it { should contain_class('mysql::bindings') }
    it { should contain_package('mysql_client') }
  end

end
require 'spec_helper'

describe 'mysql::server::account_security' do

  let :facts do {
    :fqdn     => 'myhost.mydomain',
    :hostname => 'myhost',
    :root_home => '/root'
  }
  end

  it 'should remove Mysql_User[root@myhost.mydomain]' do
    should contain_mysql_user('root@myhost.mydomain').with_ensure('absent')
  end
  it 'should remove Mysql_User[root@myhost]' do
    should contain_mysql_user('root@myhost').with_ensure('absent')
  end
  it 'should remove Mysql_User[root@127.0.0.1]' do
    should contain_mysql_user('root@127.0.0.1').with_ensure('absent')
  end
  it 'should remove Mysql_User[root@::1]' do
    should contain_mysql_user('root@::1').with_ensure('absent')
  end
  it 'should remove Mysql_User[@myhost.mydomain]' do
    should contain_mysql_user('@myhost.mydomain').with_ensure('absent')
  end
  it 'should remove Mysql_User[@myhost]' do
    should contain_mysql_user('@myhost').with_ensure('absent')
  end
  it 'should remove Mysql_User[@localhost]' do
    should contain_mysql_user('@localhost').with_ensure('absent')
  end
  it 'should remove Mysql_User[@%]' do
    should contain_mysql_user('@%').with_ensure('absent')
  end

  it 'should remove Mysql_database[test]' do
    should contain_mysql_database('test').with_ensure('absent')
  end

end
require 'spec_helper'

describe 'mysql::server::backup' do

    let(:default_params) {
        { 'backupuser'         => 'testuser',
            'backuppassword'     => 'testpass',
            'backupdir'          => '/tmp',
            'backuprotate'       => '25',
            'delete_before_dump' => true,
            'execpath'           => '/usr/bin:/usr/sbin:/bin:/sbin:/opt/zimbra/bin',
        }
    }
    context 'standard conditions' do
        let(:params) { default_params }

        it { should contain_mysql_user('testuser@localhost').with(
            :require => 'Class[Mysql::Server::Root_password]'
        )}

        it { should contain_mysql_grant('testuser@localhost/*.*').with(
            :privileges => ["SELECT", "RELOAD", "LOCK TABLES", "SHOW VIEW", "PROCESS"]
        )}

        it { should contain_cron('mysql-backup').with(
            :command => '/usr/local/sbin/mysqlbackup.sh',
            :ensure  => 'present'
        )}

        it { should contain_file('mysqlbackup.sh').with(
            :path   => '/usr/local/sbin/mysqlbackup.sh',
            :ensure => 'present'
        ) }

        it { should contain_file('mysqlbackupdir').with(
            :path   => '/tmp',
            :ensure => 'directory'
        )}

        it 'should have compression by default' do
            verify_contents(subject, 'mysqlbackup.sh', [
                            ' --all-databases | bzcat -zc > ${DIR}/${PREFIX}`date +%Y%m%d-%H%M%S`.sql.bz2',
            ])
        end
        it 'should skip backing up events table by default' do
            verify_contents(subject, 'mysqlbackup.sh', [
                            'EVENTS="--ignore-table=mysql.event"',
            ])
        end

        it 'should have 25 days of rotation' do
            # MySQL counts from 0 I guess.
            should contain_file('mysqlbackup.sh').with_content(/.*ROTATE=24.*/)
        end

        it 'should have a standard PATH' do
            should contain_file('mysqlbackup.sh').with_content(%r{PATH=/usr/bin:/usr/sbin:/bin:/sbin:/opt/zimbra/bin})
        end
    end

    context 'custom ownership and mode for backupdir' do
        let(:params) do
            { :backupdirmode => '0750',
                :backupdirowner => 'testuser',
                :backupdirgroup => 'testgrp',
            }.merge(default_params)
        end

        it { should contain_file('mysqlbackupdir').with(
            :path => '/tmp',
            :ensure => 'directory',
            :mode => '0750',
            :owner => 'testuser',
            :group => 'testgrp'
        ) }
    end

    context 'with compression disabled' do
        let(:params) do
            { :backupcompress => false }.merge(default_params)
        end

        it { should contain_file('mysqlbackup.sh').with(
            :path   => '/usr/local/sbin/mysqlbackup.sh',
            :ensure => 'present'
        ) }

        it 'should be able to disable compression' do
            verify_contents(subject, 'mysqlbackup.sh', [
                            ' --all-databases > ${DIR}/${PREFIX}`date +%Y%m%d-%H%M%S`.sql',
            ])
        end
    end

    context 'with mysql.events backedup' do
        let(:params) do
            { :ignore_events => false }.merge(default_params)
        end

        it { should contain_file('mysqlbackup.sh').with(
            :path   => '/usr/local/sbin/mysqlbackup.sh',
            :ensure => 'present'
        ) }

        it 'should be able to backup events table' do
            verify_contents(subject, 'mysqlbackup.sh', [
                            'EVENTS="--events"',
            ])
        end
    end


    context 'with database list specified' do
        let(:params) do
            { :backupdatabases => ['mysql'] }.merge(default_params)
        end

        it { should contain_file('mysqlbackup.sh').with(
            :path   => '/usr/local/sbin/mysqlbackup.sh',
            :ensure => 'present'
        ) }

        it 'should have a backup file for each database' do
            content = subject.resource('file','mysqlbackup.sh').send(:parameters)[:content]
            content.should match(' mysql | bzcat -zc \${DIR}\\\${PREFIX}mysql_`date')
            #      verify_contents(subject, 'mysqlbackup.sh', [
            #        ' mysql | bzcat -zc ${DIR}/${PREFIX}mysql_`date +%Y%m%d-%H%M%S`.sql',
            #      ])
        end 
    end

    context 'with file per database' do
        let(:params) do
            default_params.merge({ :file_per_database => true })
        end

        it 'should loop through backup all databases' do
            verify_contents(subject, 'mysqlbackup.sh', [
                            'mysql -s -r -N -e \'SHOW DATABASES\' | while read dbname',
                            'do',
                            '  mysqldump -u${USER} -p${PASS} --opt --flush-logs --single-transaction \\',
                            '    ${EVENTS} \\',
                            '    ${dbname} | bzcat -zc > ${DIR}/${PREFIX}${dbname}_`date +%Y%m%d-%H%M%S`.sql.bz2',
                            'done',
            ])
        end

        context 'with compression disabled' do
            let(:params) do
                default_params.merge({ :file_per_database => true, :backupcompress => false })
            end

            it 'should loop through backup all databases without compression' do
                verify_contents(subject, 'mysqlbackup.sh', [
                                '    ${dbname} > ${DIR}/${PREFIX}${dbname}_`date +%Y%m%d-%H%M%S`.sql',
                ])
            end
        end
    end

		context 'with postscript' do
			let(:params) do
				default_params.merge({ :postscript => 'rsync -a /tmp backup01.local-lan:' })
			end

			it 'should be add postscript' do
				verify_contents(subject, 'mysqlbackup.sh', [
					'rsync -a /tmp backup01.local-lan:',
				])
			end
		end

		context 'with postscripts' do
			let(:params) do
				default_params.merge({ :postscript => [
					'rsync -a /tmp backup01.local-lan:',
					'rsync -a /tmp backup02.local-lan:',
				]})
			end

			it 'should be add postscript' do
				verify_contents(subject, 'mysqlbackup.sh', [
					'rsync -a /tmp backup01.local-lan:',
					'rsync -a /tmp backup02.local-lan:',
				])
			end
		end
end
require 'spec_helper'
describe 'mysql::server::monitor' do
  let :facts do
    { :osfamily => 'Debian', :root_home => '/root' }
  end
  let :pre_condition do
    "include 'mysql::server'"
  end

  let :default_params do
    {
      :mysql_monitor_username   => 'monitoruser',
      :mysql_monitor_password   => 'monitorpass',
      :mysql_monitor_hostname   => 'monitorhost',
    }
  end

  let :params do
    default_params
  end

  it { should contain_mysql_user('monitoruser@monitorhost')}

  it { should contain_mysql_grant('monitoruser@monitorhost/*.*').with(
    :ensure     => 'present',
    :user       => 'monitoruser@monitorhost',
    :table      => '*.*',
    :privileges => ["PROCESS", "SUPER"],
    :require    => 'Mysql_user[monitoruser@monitorhost]'
  )}
end
describe 'mysql::server::mysqltuner' do

  it { should contain_file('/usr/local/bin/mysqltuner') }

end
require 'spec_helper'
describe 'mysql::server' do
  let(:facts) {{:osfamily => 'RedHat', :root_home => '/root'}}

  context 'with defaults' do
    it { should contain_class('mysql::server::install') }
    it { should contain_class('mysql::server::config') }
    it { should contain_class('mysql::server::service') }
    it { should contain_class('mysql::server::root_password') }
    it { should contain_class('mysql::server::providers') }
  end

  # make sure that overriding the mysqld settings keeps the defaults for everything else
  context 'with overrides' do
    let(:params) {{ :override_options => { 'mysqld' => { 'socket' => '/var/lib/mysql/mysql.sock' } } }}
    it do
      should contain_file('/etc/my.cnf').with({
        :mode => '0644',
      }).with_content(/basedir/)
    end
  end

  describe 'with multiple instance of an option' do
    let(:params) {{ :override_options => { 'mysqld' => { 'replicate-do-db' => ['base1', 'base2', 'base3'], } }}}
    it do
      should contain_file('/etc/my.cnf').with_content(
        /^replicate-do-db = base1$/
      ).with_content(
        /^replicate-do-db = base2$/
      ).with_content(
        /^replicate-do-db = base3$/
      )
    end
  end

  describe 'an option set to true' do
    let(:params) {
      { :override_options => { 'mysqld' => { 'ssl' => true } }}
    }
    it do
      should contain_file('/etc/my.cnf').with_content(/^\s*ssl\s*(?:$|= true)/m)
    end
  end

  describe 'an option set to false' do
    let(:params) {
      { :override_options => { 'mysqld' => { 'ssl' => false } }}
    }
    it do
      should contain_file('/etc/my.cnf').with_content(/^\s*ssl = false/m)
    end
  end

  context 'with remove_default_accounts set' do
    let (:params) {{ :remove_default_accounts => true }}
    it { should contain_class('mysql::server::account_security') }
  end

  describe 'possibility of disabling ssl completely' do
    let(:params) {
      { :override_options => { 'mysqld' => { 'ssl' => true, 'ssl-disable' => true } }}
    }
    it do
      should contain_file('/etc/my.cnf').without_content(/^\s*ssl\s*(?:$|= true)/m)
    end
  end

  context 'mysql::server::install' do
    let(:params) {{ :package_ensure => 'present', :name => 'mysql-server' }}
    it do
      should contain_package('mysql-server').with({
      :ensure => :present,
      :name   => 'mysql-server',
    })
    end
  end

  context 'mysql::server::config' do
    it do
      should contain_file('/etc/mysql').with({
        :ensure => :directory,
        :mode   => '0755',
      })
    end

    it do
      should contain_file('/etc/mysql/conf.d').with({
        :ensure => :directory,
        :mode   => '0755',
      })
    end

    it do
      should contain_file('/etc/my.cnf').with({
        :mode => '0644',
      })
    end
  end

  context 'mysql::server::service' do
    context 'with defaults' do
      it { should contain_service('mysqld') }
    end

    context 'service_enabled set to false' do
      let(:params) {{ :service_enabled => false }}

      it do
        should contain_service('mysqld').with({
          :ensure => :stopped
        })
      end
    end
  end

  context 'mysql::server::root_password' do
    describe 'when defaults' do
      it { should_not contain_mysql_user('root@localhost') }
      it { should_not contain_file('/root/.my.cnf') }
    end
    describe 'when set' do
      let(:params) {{:root_password => 'SET' }}
      it { should contain_mysql_user('root@localhost') }
      it { should contain_file('/root/.my.cnf') }
    end

  end

  context 'mysql::server::providers' do
    describe 'with users' do
      let(:params) {{:users => {
        'foo@localhost' => {
          'max_connections_per_hour' => '1',
          'max_queries_per_hour'     => '2',
          'max_updates_per_hour'     => '3',
          'max_user_connections'     => '4',
          'password_hash'            => '*F3A2A51A9B0F2BE2468926B4132313728C250DBF'
        },
        'foo2@localhost' => {}
      }}}
      it { should contain_mysql_user('foo@localhost').with(
        :max_connections_per_hour => '1',
        :max_queries_per_hour     => '2',
        :max_updates_per_hour     => '3',
        :max_user_connections     => '4',
        :password_hash            => '*F3A2A51A9B0F2BE2468926B4132313728C250DBF'
      )}
      it { should contain_mysql_user('foo2@localhost').with(
        :max_connections_per_hour => nil,
        :max_queries_per_hour     => nil,
        :max_updates_per_hour     => nil,
        :max_user_connections     => nil,
        :password_hash            => ''
      )}
    end

    describe 'with grants' do
      let(:params) {{:grants => {
        'foo@localhost/somedb.*' => {
          'user'       => 'foo@localhost',
          'table'      => 'somedb.*',
          'privileges' => ["SELECT", "UPDATE"],
          'options'    => ["GRANT"],
        },
        'foo2@localhost/*.*' => {
          'user'       => 'foo2@localhost',
          'table'      => '*.*',
          'privileges' => ["SELECT"],
        },
      }}}
      it { should contain_mysql_grant('foo@localhost/somedb.*').with(
        :user       => 'foo@localhost',
        :table      => 'somedb.*',
        :privileges => ["SELECT", "UPDATE"],
        :options    => ["GRANT"]
      )}
      it { should contain_mysql_grant('foo2@localhost/*.*').with(
        :user       => 'foo2@localhost',
        :table      => '*.*',
        :privileges => ["SELECT"],
        :options    => nil
      )}
    end

    describe 'with databases' do
      let(:params) {{:databases => {
        'somedb' => {
          'charset' => 'latin1',
          'collate' => 'latin1',
        },
        'somedb2' => {}
      }}}
      it { should contain_mysql_database('somedb').with(
        :charset => 'latin1',
        :collate => 'latin1'
      )}
      it { should contain_mysql_database('somedb2')}
    end

  end

end
require 'spec_helper'

describe 'mysql::db', :type => :define do
  let(:facts) {{ :osfamily => 'RedHat' }}
  let(:title) { 'test_db' }

  let(:params) {
    { 'user'     => 'testuser',
      'password' => 'testpass',
    }
  }

  it 'should report an error when ensure is not present or absent' do
    params.merge!({'ensure' => 'invalid_val'})
    expect { subject }.to raise_error(Puppet::Error,
      /invalid_val is not supported for ensure\. Allowed values are 'present' and 'absent'\./)
  end

  it 'should not notify the import sql exec if no sql script was provided' do
    should contain_mysql_database('test_db').without_notify
  end

  it 'should subscribe to database if sql script is given' do
    params.merge!({'sql' => 'test_sql'})
    should contain_exec('test_db-import').with_subscribe('Mysql_database[test_db]')
  end

  it 'should only import sql script on creation if not enforcing' do
    params.merge!({'sql' => 'test_sql', 'enforce_sql' => false})
    should contain_exec('test_db-import').with_refreshonly(true)
  end

  it 'should import sql script on creation if enforcing' do
    params.merge!({'sql' => 'test_sql', 'enforce_sql' => true})
    should contain_exec('test_db-import').with_refreshonly(false)
  end

  it 'should not create database and database user' do
    params.merge!({'ensure' => 'absent', 'host' => 'localhost'})
    should contain_mysql_database('test_db').with_ensure('absent')
    should contain_mysql_user('testuser@localhost').with_ensure('absent')
  end

  it 'should create with an appropriate collate and charset' do
    params.merge!({'charset' => 'utf8', 'collate' => 'utf8_danish_ci'})
    should contain_mysql_database('test_db').with({
      'charset' => 'utf8',
      'collate' => 'utf8_danish_ci',
    })
  end

  it 'should use dbname parameter as database name instead of name' do
    params.merge!({'dbname' => 'real_db'})
    should contain_mysql_database('real_db')
  end
end
s
mtime
require 'simplecov'
SimpleCov.start do
  add_filter "/spec/"
end
require 'puppetlabs_spec_helper/module_spec_helper'
require 'beaker-rspec'

UNSUPPORTED_PLATFORMS = [ 'Windows', 'Solaris', 'AIX' ]

unless ENV['RS_PROVISION'] == 'no' or ENV['BEAKER_provision'] == 'no'
  if hosts.first.is_pe?
    install_pe
  else
    install_puppet
  end
  hosts.each do |host|
    on hosts, "mkdir -p #{host['distmoduledir']}"
  end
end

RSpec.configure do |c|
  # Project root
  proj_root = File.expand_path(File.join(File.dirname(__FILE__), '..'))

  # Readable test descriptions
  c.formatter = :documentation

  # Configure all nodes in nodeset
  c.before :suite do
    # Install module and dependencies
    puppet_module_install(:source => proj_root, :module_name => 'mysql')
    hosts.each do |host|
      # Required for binding tests.
      if fact('osfamily') == 'RedHat'
        version = fact("operatingsystemmajrelease")
        shell("yum localinstall -y http://yum.puppetlabs.com/puppetlabs-release-el-#{version}.noarch.rpm")
      end

      shell("/bin/touch #{default['puppetpath']}/hiera.yaml")
      shell('puppet module install puppetlabs-stdlib --version 3.2.0', { :acceptable_exit_codes => [0,1] })
      on host, puppet('module','install','stahnma/epel'), { :acceptable_exit_codes => [0,1] }
    end
  end
end
require 'spec_helper'

describe 'the mysql_password function' do
  before :all do
    Puppet::Parser::Functions.autoloader.loadall
  end

  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it 'should exist' do
    Puppet::Parser::Functions.function('mysql_password').should == 'function_mysql_password'
  end

  it 'should raise a ParseError if there is less than 1 arguments' do
    lambda { scope.function_mysql_password([]) }.should( raise_error(Puppet::ParseError))
  end

  it 'should raise a ParseError if there is more than 1 arguments' do
    lambda { scope.function_mysql_password(%w(foo bar)) }.should( raise_error(Puppet::ParseError))
  end

  it 'should convert password into a hash' do
    result = scope.function_mysql_password(%w(password))
    result.should(eq('*2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19'))
  end

end
#! /usr/bin/env ruby -S rspec

require 'spec_helper'

describe Puppet::Parser::Functions.function(:mysql_deepmerge) do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  describe 'when calling mysql_deepmerge from puppet' do
    it "should not compile when no arguments are passed" do
      pending("Fails on 2.6.x, see bug #15912") if Puppet.version =~ /^2\.6\./
      Puppet[:code] = '$x = mysql_deepmerge()'
      expect {
        scope.compiler.compile
      }.to raise_error(Puppet::ParseError, /wrong number of arguments/)
    end

    it "should not compile when 1 argument is passed" do
      pending("Fails on 2.6.x, see bug #15912") if Puppet.version =~ /^2\.6\./
      Puppet[:code] = "$my_hash={'one' => 1}\n$x = mysql_deepmerge($my_hash)"
      expect {
        scope.compiler.compile
      }.to raise_error(Puppet::ParseError, /wrong number of arguments/)
    end
  end

  describe 'when calling mysql_deepmerge on the scope instance' do
    it 'should require all parameters are hashes' do
      expect { new_hash = scope.function_mysql_deepmerge([{}, '2'])}.to raise_error(Puppet::ParseError, /unexpected argument type String/)
      expect { new_hash = scope.function_mysql_deepmerge([{}, 2])}.to raise_error(Puppet::ParseError, /unexpected argument type Fixnum/)
    end

    it 'should accept empty strings as puppet undef' do
      expect { new_hash = scope.function_mysql_deepmerge([{}, ''])}.not_to raise_error
    end

    it 'should be able to mysql_deepmerge two hashes' do
      new_hash = scope.function_mysql_deepmerge([{'one' => '1', 'two' => '1'}, {'two' => '2', 'three' => '2'}])
      new_hash['one'].should   == '1'
      new_hash['two'].should   == '2'
      new_hash['three'].should == '2'
    end

    it 'should mysql_deepmerge multiple hashes' do
      hash = scope.function_mysql_deepmerge([{'one' => 1}, {'one' => '2'}, {'one' => '3'}])
      hash['one'].should == '3'
    end

    it 'should accept empty hashes' do
      scope.function_mysql_deepmerge([{},{},{}]).should == {}
    end

    it 'should mysql_deepmerge subhashes' do
      hash = scope.function_mysql_deepmerge([{'one' => 1}, {'two' => 2, 'three' => { 'four' => 4 } }])
      hash['one'].should == 1
      hash['two'].should == 2
      hash['three'].should == { 'four' => 4 }
    end

    it 'should append to subhashes' do
      hash = scope.function_mysql_deepmerge([{'one' => { 'two' => 2 } }, { 'one' => { 'three' => 3 } }])
      hash['one'].should == { 'two' => 2, 'three' => 3 }
    end

    it 'should append to subhashes 2' do
      hash = scope.function_mysql_deepmerge([{'one' => 1, 'two' => 2, 'three' => { 'four' => 4 } }, {'two' => 'dos', 'three' => { 'five' => 5 } }])
      hash['one'].should == 1
      hash['two'].should == 'dos'
      hash['three'].should == { 'four' => 4, 'five' => 5 }
    end

    it 'should append to subhashes 3' do
      hash = scope.function_mysql_deepmerge([{ 'key1' => { 'a' => 1, 'b' => 2 }, 'key2' => { 'c' => 3 } }, { 'key1' => { 'b' => 99 } }])
      hash['key1'].should == { 'a' => 1, 'b' => 99 }
      hash['key2'].should == { 'c' => 3 }
    end

    it 'should equate keys mod dash and underscore' do
      hash = scope.function_mysql_deepmerge([{  'a-b-c' => 1 } , { 'a_b_c' => 10 }])
      hash['a_b_c'].should == 10
      hash.should_not have_key('a-b-c')
    end

    it 'should keep style of the last when keys are euqal mod dash and underscore' do
      hash = scope.function_mysql_deepmerge([{  'a-b-c' => 1,  'b_c_d' => { 'c-d-e' => 2, 'e-f-g' => 3 }} , { 'a_b_c' => 10, 'b-c-d' => { 'c_d_e' => 12 } }])
      hash['a_b_c'].should == 10
      hash.should_not have_key('a-b-c')
      hash['b-c-d'].should == { 'e-f-g' => 3, 'c_d_e' => 12 }
      hash.should_not have_key('b_c_d')
    end
  end
end
require 'spec_helper'

provider_class = Puppet::Type.type(:database).provider(:mysql)

describe provider_class do
  subject { provider_class }

  let(:root_home) { '/root' }
  let(:defaults_file) { '--defaults-extra-file=/root/.my.cnf' }

  let(:raw_databases) do
    <<-SQL_OUTPUT
information_schema
mydb
mysql
performance_schema
test
    SQL_OUTPUT
  end

  let(:parsed_databases) { %w(information_schema mydb mysql performance_schema test) }

  before :each do
    @resource = Puppet::Type::Database.new(
      { :charset => 'utf8', :name => 'new_database' }
    )
    @provider = provider_class.new(@resource)
    Facter.stubs(:value).with(:root_home).returns(root_home)
    Puppet::Util.stubs(:which).with('mysql').returns('/usr/bin/mysql')
    subject.stubs(:which).with('mysql').returns('/usr/bin/mysql')
    subject.stubs(:defaults_file).returns('--defaults-extra-file=/root/.my.cnf')
  end

  describe 'self.instances' do
    it 'returns an array of databases' do
      subject.stubs(:mysql).with([defaults_file, '-NBe', 'show databases']).returns(raw_databases)

      databases = subject.instances.collect {|x| x.name }
      parsed_databases.should match_array(databases)
    end
  end

  describe 'create' do
    it 'makes a user' do
      subject.expects(:mysql).with([defaults_file, '-NBe', "create database `#{@resource[:name]}` character set #{@resource[:charset]}"])
      @provider.create
    end
  end

  describe 'destroy' do
    it 'removes a user if present' do
      subject.expects(:mysqladmin).with([defaults_file, '-f', 'drop', "#{@resource[:name]}"])
      @provider.destroy
    end
  end

  describe 'charset' do
    it 'returns a charset' do
      subject.expects(:mysql).with([defaults_file, '-NBe', "show create database `#{@resource[:name]}`"]).returns('mydbCREATE DATABASE `mydb` /*!40100 DEFAULT CHARACTER SET utf8 */')
      @provider.charset.should == 'utf8'
    end
  end

  describe 'charset=' do
    it 'changes the charset' do
      subject.expects(:mysql).with([defaults_file, '-NBe', "alter database `#{@resource[:name]}` CHARACTER SET blah"]).returns('0')

      @provider.charset=('blah')
    end
  end

  describe 'exists?' do
    it 'checks if user exists' do
      subject.expects(:mysql).with([defaults_file, '-NBe', 'show databases']).returns('information_schema\nmydb\nmysql\nperformance_schema\ntest')
      @provider.exists?
    end
  end

  describe 'self.defaults_file' do
    it 'sets --defaults-extra-file' do
      File.stubs(:file?).with('#{root_home}/.my.cnf').returns(true)
      @provider.defaults_file.should == '--defaults-extra-file=/root/.my.cnf'
    end
  end

end
require 'puppet'
require 'mocha/api'
require 'spec_helper'
RSpec.configure do |config|
  config.mock_with :mocha
end
provider_class = Puppet::Type.type(:database_grant).provider(:mysql)
describe provider_class do
  let(:root_home) { '/root' }

  before :each do
    @resource = Puppet::Type::Database_grant.new(
      { :privileges => 'all', :provider => 'mysql', :name => 'user@host'}
    )
    @provider = provider_class.new(@resource)
    Facter.stubs(:value).with(:root_home).returns(root_home)
    File.stubs(:file?).with("#{root_home}/.my.cnf").returns(true)
  end

  it 'should query privileges from the database' do
    provider_class.expects(:mysql) .with(["--defaults-extra-file=#{root_home}/.my.cnf", 'mysql', '-Be', 'describe user']).returns <<-EOT
Field	Type	Null	Key	Default	Extra
Host	char(60)	NO	PRI		
User	char(16)	NO	PRI		
Password	char(41)	NO			
Select_priv	enum('N','Y')	NO		N	
Insert_priv	enum('N','Y')	NO		N	
Update_priv	enum('N','Y')	NO		N
EOT
    provider_class.expects(:mysql).with(["--defaults-extra-file=#{root_home}/.my.cnf", 'mysql', '-Be', 'describe db']).returns <<-EOT
Field	Type	Null	Key	Default	Extra
Host	char(60)	NO	PRI		
Db	char(64)	NO	PRI		
User	char(16)	NO	PRI		
Select_priv	enum('N','Y')	NO		N	
Insert_priv	enum('N','Y')	NO		N	
Update_priv	enum('N','Y')	NO		N
EOT
    provider_class.user_privs.should == %w(Select_priv Insert_priv Update_priv)
    provider_class.db_privs.should == %w(Select_priv Insert_priv Update_priv)
  end

  it 'should query set privileges' do
    provider_class.expects(:mysql).with(["--defaults-extra-file=#{root_home}/.my.cnf", 'mysql', '-Be', "select * from mysql.user where user='user' and host='host'"]).returns <<-EOT
Host	User	Password	Select_priv	Insert_priv	Update_priv
host	user		Y	N	Y
EOT
    @provider.privileges.should == %w(Select_priv Update_priv)
  end

  it 'should recognize when all privileges are set' do
    provider_class.expects(:mysql).with(["--defaults-extra-file=#{root_home}/.my.cnf", 'mysql', '-Be', "select * from mysql.user where user='user' and host='host'"]).returns <<-EOT
Host	User	Password	Select_priv	Insert_priv	Update_priv
host	user		Y	Y	Y
EOT
    @provider.all_privs_set?.should == true
  end

  it 'should recognize when all privileges are not set' do
    provider_class.expects(:mysql).with(["--defaults-extra-file=#{root_home}/.my.cnf", 'mysql', '-Be', "select * from mysql.user where user='user' and host='host'"]).returns <<-EOT
Host	User	Password	Select_priv	Insert_priv	Update_priv
host	user		Y	N	Y
EOT
    @provider.all_privs_set?.should == false
  end

  it 'should be able to set all privileges' do
    provider_class.expects(:mysql).with(["--defaults-extra-file=#{root_home}/.my.cnf", 'mysql', '-NBe', "SELECT '1' FROM user WHERE user='user' AND host='host'"]).returns "1\n"
    provider_class.expects(:mysql).with(["--defaults-extra-file=#{root_home}/.my.cnf", 'mysql', '-Be', "update user set Select_priv = 'Y', Insert_priv = 'Y', Update_priv = 'Y' where user='user' and host='host'"])
    provider_class.expects(:mysqladmin).with(%W(--defaults-extra-file=#{root_home}/.my.cnf flush-privileges))
    @provider.privileges=(%w(all))
  end

  it 'should be able to set partial privileges' do
    provider_class.expects(:mysql).with(["--defaults-extra-file=#{root_home}/.my.cnf", 'mysql', '-NBe', "SELECT '1' FROM user WHERE user='user' AND host='host'"]).returns "1\n"
    provider_class.expects(:mysql).with(["--defaults-extra-file=#{root_home}/.my.cnf", 'mysql', '-Be', "update user set Select_priv = 'Y', Insert_priv = 'N', Update_priv = 'Y' where user='user' and host='host'"])
    provider_class.expects(:mysqladmin).with(%W(--defaults-extra-file=#{root_home}/.my.cnf flush-privileges))
    @provider.privileges=(%w(Select_priv Update_priv))
  end

  it 'should be case insensitive' do
    provider_class.expects(:mysql).with(["--defaults-extra-file=#{root_home}/.my.cnf", 'mysql', '-NBe', "SELECT '1' FROM user WHERE user='user' AND host='host'"]).returns "1\n"
    provider_class.expects(:mysql).with(["--defaults-extra-file=#{root_home}/.my.cnf", 'mysql', '-Be', "update user set Select_priv = 'Y', Insert_priv = 'Y', Update_priv = 'Y' where user='user' and host='host'"])
    provider_class.expects(:mysqladmin).with(["--defaults-extra-file=#{root_home}/.my.cnf", 'flush-privileges'])
    @provider.privileges=(%w(SELECT_PRIV insert_priv UpDaTe_pRiV))
  end

  it 'should not pass --defaults-extra-file if $root_home/.my.cnf is absent' do
    File.stubs(:file?).with("#{root_home}/.my.cnf").returns(false)
    provider_class.expects(:mysql).with(['mysql', '-NBe', "SELECT '1' FROM user WHERE user='user' AND host='host'"]).returns "1\n"
    provider_class.expects(:mysql).with(['mysql', '-Be', "update user set Select_priv = 'Y', Insert_priv = 'N', Update_priv = 'Y' where user='user' and host='host'"])
    provider_class.expects(:mysqladmin).with(%w(flush-privileges))
    @provider.privileges=(%w(Select_priv Update_priv))
  end
end
require 'spec_helper'

provider_class = Puppet::Type.type(:database_user).provider(:mysql)

describe provider_class do
  subject { provider_class }

  let(:root_home) { '/root' }
  let(:defaults_file) { '--defaults-extra-file=/root/.my.cnf' }
  let(:newhash) { '*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF5' }

  let(:raw_users) do
    <<-SQL_OUTPUT
root@127.0.0.1
root@::1
@localhost
debian-sys-maint@localhost
root@localhost
usvn_user@localhost
@vagrant-ubuntu-raring-64
    SQL_OUTPUT
  end

  let(:parsed_users) { %w(root@127.0.0.1 root@::1 debian-sys-maint@localhost root@localhost usvn_user@localhost) }

  before :each do
    # password hash = mypass
    @resource = Puppet::Type::Database_user.new(
      { :password_hash => '*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF4',
        :name => 'joe@localhost',
        :max_user_connections => '10'
      }
    )
    @provider = provider_class.new(@resource)
    Facter.stubs(:value).with(:root_home).returns(root_home)
    Puppet::Util.stubs(:which).with('mysql').returns('/usr/bin/mysql')
    subject.stubs(:which).with('mysql').returns('/usr/bin/mysql')
    subject.stubs(:defaults_file).returns('--defaults-extra-file=/root/.my.cnf')
  end

  describe 'self.instances' do
    it 'returns an array of users' do
      subject.stubs(:mysql).with([defaults_file, 'mysql', "-BNeselect concat(User, '@',Host) as User from mysql.user"]).returns(raw_users)

      usernames = subject.instances.collect {|x| x.name }
      parsed_users.should match_array(usernames)
    end
  end

  describe 'create' do
    it 'makes a user' do
      subject.expects(:mysql).with([defaults_file, 'mysql', '-e', "grant usage on *.* to 'joe'@'localhost' identified by PASSWORD
      '*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF4' with max_user_connections 10"])
      @provider.expects(:exists?).returns(true)
      @provider.create.should be_true
    end
  end

  describe 'destroy' do
    it 'removes a user if present' do
      subject.expects(:mysql).with([defaults_file, 'mysql', '-e', "drop user 'joe'@'localhost'"])
      @provider.expects(:exists?).returns(false)
      @provider.destroy.should be_true
    end
  end

  describe 'password_hash' do
    it 'returns a hash' do
      subject.expects(:mysql).with([defaults_file, 'mysql', '-NBe', "select password from mysql.user where CONCAT(user, '@', host) = 'joe@localhost'"]).returns('*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF4')
      @provider.password_hash.should == '*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF4'
    end
  end

  describe 'password_hash=' do
    it 'changes the hash' do
      subject.expects(:mysql).with([defaults_file, 'mysql', '-e', "SET PASSWORD FOR 'joe'@'localhost' = '*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF5'"]).returns('0')

      @provider.expects(:password_hash).returns('*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF5')
      @provider.password_hash=('*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF5')
    end
  end

  describe 'max_user_connections' do
    it 'returns max user connections' do
      subject.expects(:mysql).with([defaults_file, 'mysql', '-NBe', "select max_user_connections from mysql.user where CONCAT(user, '@', host) = 'joe@localhost'"]).returns('10')
      @provider.max_user_connections.should == '10'
    end
  end

  describe 'max_user_connections=' do
    it 'changes max user connections' do
      subject.expects(:mysql).with([defaults_file, 'mysql', '-e', "grant usage on *.* to 'joe'@'localhost' with max_user_connections 42"]).returns('0')
      @provider.expects(:max_user_connections).returns('42')
      @provider.max_user_connections=('42')
    end
  end

  describe 'exists?' do
    it 'checks if user exists' do
      subject.expects(:mysql).with([defaults_file, 'mysql', '-NBe', "select '1' from mysql.user where CONCAT(user, '@', host) = 'joe@localhost'"]).returns('1')
      @provider.exists?.should be_true
    end
  end

  describe 'flush' do
    it 'removes cached privileges' do
      subject.expects(:mysqladmin).with([defaults_file, 'flush-privileges'])
      @provider.flush
    end
  end

  describe 'self.defaults_file' do
    it 'sets --defaults-extra-file' do
      File.stubs(:file?).with('#{root_home}/.my.cnf').returns(true)
      @provider.defaults_file.should == '--defaults-extra-file=/root/.my.cnf'
    end
  end

end
require 'spec_helper'

describe Puppet::Type.type(:mysql_database).provider(:mysql) do

  let(:defaults_file) { '--defaults-extra-file=/root/.my.cnf' }

  let(:raw_databases) do
    <<-SQL_OUTPUT
information_schema
mydb
mysql
performance_schema
test
    SQL_OUTPUT
  end

  let(:parsed_databases) { %w(information_schema mydb mysql performance_schema test) }

  let(:resource) { Puppet::Type.type(:mysql_database).new(
    { :ensure   => :present,
      :charset  => 'latin1',
      :collate  => 'latin1_swedish_ci',
      :name     => 'new_database',
      :provider => described_class.name
    }
  )}
  let(:provider) { resource.provider }

  before :each do
    Facter.stubs(:value).with(:root_home).returns('/root')
    Puppet::Util.stubs(:which).with('mysql').returns('/usr/bin/mysql')
    File.stubs(:file?).with('/root/.my.cnf').returns(true)
    provider.class.stubs(:mysql).with([defaults_file, '-NBe', 'show databases']).returns('new_database')
    provider.class.stubs(:mysql).with([defaults_file, '-NBe', "show variables like '%_database'", 'new_database']).returns("character_set_database latin1\ncollation_database latin1_swedish_ci\nskip_show_database OFF")
  end

  let(:instance) { provider.class.instances.first }

  describe 'self.instances' do
    it 'returns an array of databases' do
      provider.class.stubs(:mysql).with([defaults_file, '-NBe', 'show databases']).returns(raw_databases)
      raw_databases.each_line do |db|
        provider.class.stubs(:mysql).with([defaults_file, '-NBe', "show variables like '%_database'", db.chomp]).returns("character_set_database latin1\ncollation_database  latin1_swedish_ci\nskip_show_database  OFF")
      end
      databases = provider.class.instances.collect {|x| x.name }
      parsed_databases.should match_array(databases)
    end
  end

  describe 'self.prefetch' do
    it 'exists' do
      provider.class.instances
      provider.class.prefetch({})
    end
  end

  describe 'create' do
    it 'makes a database' do
      provider.expects(:mysql).with([defaults_file, '-NBe', "create database if not exists `#{resource[:name]}` character set #{resource[:charset]} collate #{resource[:collate]}"])
      provider.expects(:exists?).returns(true)
      provider.create.should be_true
    end
  end

  describe 'destroy' do
    it 'removes a database if present' do
      provider.expects(:mysql).with([defaults_file, '-NBe', "drop database `#{resource[:name]}`"])
      provider.expects(:exists?).returns(false)
      provider.destroy.should be_true
    end
  end

  describe 'exists?' do
    it 'checks if database exists' do
      instance.exists?.should be_true
    end
  end

  describe 'self.defaults_file' do
    it 'sets --defaults-extra-file' do
      File.stubs(:file?).with('/root/.my.cnf').returns(true)
      provider.defaults_file.should eq '--defaults-extra-file=/root/.my.cnf'
    end
    it 'fails if file missing' do
      File.stubs(:file?).with('/root/.my.cnf').returns(false)
      provider.defaults_file.should be_nil
    end
  end

  describe 'charset' do
    it 'returns a charset' do
      instance.charset.should == 'latin1'
    end
  end

  describe 'charset=' do
    it 'changes the charset' do
      provider.expects(:mysql).with([defaults_file, '-NBe', "alter database `#{resource[:name]}` CHARACTER SET blah"]).returns('0')

      provider.charset=('blah')
    end
  end

  describe 'collate' do
    it 'returns a collate' do
      instance.collate.should == 'latin1_swedish_ci'
    end
  end

  describe 'collate=' do
    it 'changes the collate' do
      provider.expects(:mysql).with([defaults_file, '-NBe', "alter database `#{resource[:name]}` COLLATE blah"]).returns('0')

      provider.collate=('blah')
    end
  end

end
require 'spec_helper'

describe Puppet::Type.type(:mysql_user).provider(:mysql) do
  let(:defaults_file) { '--defaults-extra-file=/root/.my.cnf' }
  let(:newhash) { '*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF5' }

  let(:raw_users) do
    <<-SQL_OUTPUT
root@127.0.0.1
root@::1
@localhost
debian-sys-maint@localhost
root@localhost
usvn_user@localhost
@vagrant-ubuntu-raring-64
    SQL_OUTPUT
  end

  let(:parsed_users) { %w(root@127.0.0.1 root@::1 @localhost debian-sys-maint@localhost root@localhost usvn_user@localhost @vagrant-ubuntu-raring-64) }

  let(:resource) { Puppet::Type.type(:mysql_user).new(
      { :ensure                   => :present,
        :password_hash            => '*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF4',
        :name                     => 'joe@localhost',
        :max_user_connections     => '10',
        :max_connections_per_hour => '10',
        :max_queries_per_hour     => '10',
        :max_updates_per_hour     => '10',
        :provider                 => described_class.name
      }
  )}
  let(:provider) { resource.provider }

  before :each do
    # Set up the stubs for an instances call.
    Facter.stubs(:value).with(:root_home).returns('/root')
    Puppet::Util.stubs(:which).with('mysql').returns('/usr/bin/mysql')
    File.stubs(:file?).with('/root/.my.cnf').returns(true)
    provider.class.stubs(:mysql).with([defaults_file, '-NBe', "SELECT CONCAT(User, '@',Host) AS User FROM mysql.user"]).returns('joe@localhost')
    provider.class.stubs(:mysql).with([defaults_file, '-NBe', "SELECT MAX_USER_CONNECTIONS, MAX_CONNECTIONS, MAX_QUESTIONS, MAX_UPDATES, PASSWORD FROM mysql.user WHERE CONCAT(user, '@', host) = 'joe@localhost'"]).returns('10 10 10 10 *6C8989366EAF75BB670AD8EA7A7FC1176A95CEF4')
  end

  let(:instance) { provider.class.instances.first }

  describe 'self.instances' do
    it 'returns an array of users' do
      provider.class.stubs(:mysql).with([defaults_file, '-NBe', "SELECT CONCAT(User, '@',Host) AS User FROM mysql.user"]).returns(raw_users)
      parsed_users.each do |user|
        provider.class.stubs(:mysql).with([defaults_file, '-NBe', "SELECT MAX_USER_CONNECTIONS, MAX_CONNECTIONS, MAX_QUESTIONS, MAX_UPDATES, PASSWORD FROM mysql.user WHERE CONCAT(user, '@', host) = '#{user}'"]).returns('10 10 10 10 ')
      end

      usernames = provider.class.instances.collect {|x| x.name }
      parsed_users.should match_array(usernames)
    end
  end

  describe 'self.prefetch' do
    it 'exists' do
      provider.class.instances
      provider.class.prefetch({})
    end
  end

  describe 'create' do
    it 'makes a user' do
      provider.expects(:mysql).with([defaults_file, '-e', "GRANT USAGE ON *.* TO 'joe'@'localhost' IDENTIFIED BY PASSWORD '*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF4' WITH MAX_USER_CONNECTIONS 10 MAX_CONNECTIONS_PER_HOUR 10 MAX_QUERIES_PER_HOUR 10 MAX_UPDATES_PER_HOUR 10"])
      provider.expects(:exists?).returns(true)
      provider.create.should be_true
    end
  end

  describe 'destroy' do
    it 'removes a user if present' do
      provider.expects(:mysql).with([defaults_file, '-e', "DROP USER 'joe'@'localhost'"])
      provider.expects(:exists?).returns(false)
      provider.destroy.should be_true
    end
  end

  describe 'exists?' do
    it 'checks if user exists' do
      instance.exists?.should be_true
    end
  end

  describe 'self.defaults_file' do
    it 'sets --defaults-extra-file' do
      File.stubs(:file?).with('/root/.my.cnf').returns(true)
      provider.defaults_file.should eq '--defaults-extra-file=/root/.my.cnf'
    end
    it 'fails if file missing' do
      File.expects(:file?).with('/root/.my.cnf').returns(false)
      provider.defaults_file.should be_nil
    end
  end

  describe 'password_hash' do
    it 'returns a hash' do
      instance.password_hash.should == '*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF4'
    end
  end

  describe 'password_hash=' do
    it 'changes the hash' do
      provider.expects(:mysql).with([defaults_file, '-e', "SET PASSWORD FOR 'joe'@'localhost' = '*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF5'"]).returns('0')

      provider.expects(:password_hash).returns('*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF5')
      provider.password_hash=('*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF5')
    end
  end

  ['max_user_connections', 'max_connections_per_hour', 'max_queries_per_hour',
   'max_updates_per_hour'].each do |property|

    describe property do
      it "returns #{property}" do
        instance.send("#{property}".to_sym).should == '10'
      end
    end

    describe "#{property}=" do
      it "changes #{property}" do
        provider.expects(:mysql).with([defaults_file, '-e', "GRANT USAGE ON *.* TO 'joe'@'localhost' WITH #{property.upcase} 42"]).returns('0')
        provider.expects(property.to_sym).returns('42')
        provider.send("#{property}=".to_sym, '42')
      end
    end
  end

end
require 'puppet'
require 'puppet/type/mysql_database'
describe Puppet::Type.type(:mysql_database) do

  before :each do
    @user = Puppet::Type.type(:mysql_database).new(:name => 'test', :charset => 'utf8', :collate => 'utf8_blah_ci')
  end

  it 'should accept a database name' do
    @user[:name].should == 'test'
  end

  it 'should accept a charset' do
    @user[:charset] = 'latin1'
    @user[:charset].should == 'latin1'
  end

  it 'should accept a collate' do
    @user[:collate] = 'latin1_swedish_ci'
    @user[:collate].should == 'latin1_swedish_ci'
  end

  it 'should require a name' do
    expect {
      Puppet::Type.type(:mysql_database).new({})
    }.to raise_error(Puppet::Error, 'Title or name must be provided')
  end

end
require 'puppet'
require 'puppet/type/mysql_grant'
describe Puppet::Type.type(:mysql_grant) do

  before :each do
    @user = Puppet::Type.type(:mysql_grant).new(:name => 'foo@localhost/*.*', :privileges => ['ALL', 'PROXY'], :table => ['*.*','@'], :user => 'foo@localhost')
  end

  it 'should accept a grant name' do
    @user[:name].should == 'foo@localhost/*.*'
  end
  
  it 'should accept ALL privileges' do
    @user[:privileges] = 'ALL'
    @user[:privileges].should == ['ALL']
  end

  it 'should accept PROXY privilege' do
    @user[:privileges] = 'PROXY'
    @user[:privileges].should == ['PROXY']
  end
  
  it 'should accept a table' do
    @user[:table] = '*.*'
    @user[:table].should == '*.*'
  end
  
  it 'should accept @ for table' do
    @user[:table] = '@'
    @user[:table].should == '@'
  end
  
  it 'should accept a user' do
    @user[:user] = 'foo@localhost'
    @user[:user].should == 'foo@localhost'
  end
  
  it 'should require a name' do
    expect {
      Puppet::Type.type(:mysql_grant).new({})
    }.to raise_error(Puppet::Error, 'Title or name must be provided')
  end

end
require 'puppet'
require 'puppet/type/mysql_user'
describe Puppet::Type.type(:mysql_user) do

  before :each do
    @user = Puppet::Type.type(:mysql_user).new(:name => 'foo@localhost', :password_hash => 'pass')
  end

  it 'should accept a user name' do
    @user[:name].should == 'foo@localhost'
  end

  it 'should fail with a long user name' do
    expect {
      Puppet::Type.type(:mysql_user).new({:name => '12345678901234567@localhost', :password_hash => 'pass'})
      }.to raise_error /MySQL usernames are limited to a maximum of 16 characters/
  end

  it 'should accept a password' do
    @user[:password_hash] = 'foo'
    @user[:password_hash].should == 'foo'
  end

  it 'should require a name' do
    expect {
      Puppet::Type.type(:mysql_user).new({})
    }.to raise_error(Puppet::Error, 'Title or name must be provided')
  end

end
<% @options.sort.map do |k,v| -%>
<%   if v.is_a?(Hash) -%>
[<%=   k %>]
<%     v.sort.map do |ki, vi| -%>
<%       if ki == 'ssl-disable' or (ki =~ /^ssl/ and v['ssl-disable'] == true) -%>
<%         next %>
<%       elsif vi == true or v == '' -%>
<%=        ki %>
<%       elsif vi.is_a?(Array) -%>
<%         vi.each do |vii| -%>
<%=          ki %> = <%= vii %>
<%         end -%>
<%       elsif vi != :undef -%>
<%=        ki %> = <%= vi %>
<%       end -%>
<%     end -%>
<%   end %>
<% end -%>

!includedir /etc/mysql/conf.d/
[client]
user=root
host=localhost
<% unless scope.lookupvar('mysql::server::root_password') == 'UNSET' -%>
password='<%= scope.lookupvar('mysql::server::root_password') %>'
<% end -%>
socket=<%= @options['client']['socket'] -%>
### MANAGED BY PUPPET ###
<% @settings.sort.each do |section, content|      -%>
[<%= section %>]
<%   content.sort.each do |key, values|          -%>
<%     [values].flatten.sort.each do |value|     -%>
<%= !value ? '#' : '' %><%= key -%><%=
         case value
         when true, false
           ''
         else
           " = #{value}"
         end
%>
<%     end                                       -%>
<%   end                                         -%>

<% end                                           -%>
#!/bin/bash
#
# MySQL Backup Script
#  Dumps mysql databases to a file for another backup tool to pick up.
#
# MySQL code:
# GRANT SELECT, RELOAD, LOCK TABLES ON *.* TO 'user'@'localhost'
# IDENTIFIED BY 'password';
# FLUSH PRIVILEGES;
#
##### START CONFIG ###################################################

USER=<%= @backupuser %>
PASS='<%= @backuppassword %>'
DIR=<%= @backupdir %>
ROTATE=<%= [ Integer(@backuprotate) - 1, 0 ].max %>

PREFIX=mysql_backup_
<% if @ignore_events %>
EVENTS="--ignore-table=mysql.event"
<% else %>
EVENTS="--events"
<% end %>

##### STOP CONFIG ####################################################
PATH=<%= @execpath %>



set -o pipefail

cleanup()
{
    find "${DIR}/" -maxdepth 1 -type f -name "${PREFIX}*.sql*" -mtime +${ROTATE} -print0 | xargs -0 -r rm -f
}

<% if @delete_before_dump -%>
cleanup

<% end -%>
<% if @backupdatabases.empty? -%>
<% if @file_per_database -%>
mysql -s -r -N -e 'SHOW DATABASES' | while read dbname
do
  mysqldump -u${USER} -p${PASS} --opt --flush-logs --single-transaction \
    ${EVENTS} \
    ${dbname} <% if @backupcompress %>| bzcat -zc <% end %>> ${DIR}/${PREFIX}${dbname}_`date +%Y%m%d-%H%M%S`.sql<% if @backupcompress %>.bz2<% end  %>
done
<% else -%>
mysqldump -u${USER} -p${PASS} --opt --flush-logs --single-transaction \
 ${EVENTS} \
 --all-databases <% if @backupcompress %>| bzcat -zc <% end %>> ${DIR}/${PREFIX}`date +%Y%m%d-%H%M%S`.sql<% if @backupcompress %>.bz2<% end  %>
<% end -%>
<% else -%>
<% @backupdatabases.each do |db| -%>
mysqldump -u${USER} -p${PASS} --opt --flush-logs --single-transaction \
    ${EVENTS} \
 <%= db %><% if @backupcompress %>| bzcat -zc <% end %>> ${DIR}/${PREFIX}<%= db %>_`date +%Y%m%d-%H%M%S`.sql<% if @backupcompress %>.bz2<% end  %>
<% end -%>
<% end -%>

<% unless @delete_before_dump -%>
if [ $? -eq 0 ] ; then
    cleanup
fi
<% end -%>

<% if @postscript -%>
  <%- [@postscript].flatten.compact.each do |script|%>
<%= script %>
  <%- end -%>
<% end -%>
class { 'mysql::server':
  config_hash => {'root_password' => 'password'}
}
class { 'mysql::backup':
  backupuser     => 'myuser',
  backuppassword => 'mypassword',
  backupdir      => '/tmp/backups',
}
class { 'mysql::bindings':
  php_enable => 'true',
}
include mysql
class { 'mysql::java':}
class { 'mysql::server':
  config_hash => {'root_password' => 'password'}
}
database{ ['test1', 'test2', 'test3']:
  ensure  => present,
  charset => 'utf8',
  require => Class['mysql::server'],
}
database{ 'test4':
  ensure  => present,
  charset => 'latin1',
}
class { 'mysql::server':
  config_hash => {'root_password' => 'password'}
}
mysql::db { 'mydb':
  user     => 'myuser',
  password => 'mypass',
  host     => 'localhost',
  grant    => ['SELECT', 'UPDATE'],
}
mysql::db { "mydb_${fqdn}":
  user     => 'myuser',
  password => 'mypass',
  dbname   => 'mydb',
  host     => $::fqdn,
  grant    => ['SELECT', 'UPDATE'],
  tag      => $domain,
}
mysql_grant{'test1@localhost/redmine.*':
  user       => 'test1@localhost',
  table      => 'redmine.*',
  privileges => ['UPDATE'],
}
$mysql_root_pw = 'password'

class { 'mysql::server':
  config_hash => {
    root_password => 'password',
  }
}

mysql_user{ 'redmine@localhost':
  ensure        => present,
  password_hash => mysql_password('redmine'),
  require       => Class['mysql::server'],
}

mysql_user{ 'dan@localhost':
  ensure        => present,
  password_hash => mysql_password('blah')
}

mysql_user{ 'dan@%':
  ensure        => present,
  password_hash => mysql_password('blah'),
}
include mysql::perl
class { 'mysql::python':}
include mysql::ruby
class { 'mysql::server':
  root_password => 'password',
}
class { 'mysql::server':
  config_hash => { 'root_password' => 'password', },
}
class { 'mysql::server::account_security': }
mysql::server::config { 'testfile':
  settings => {
    'mysqld' => {
      'bind-address' => '0.0.0.0',
      'read-only'    => true,
    },
    'client' => {
      'port' => '3306'
    }
  }
}
fixtures:
  symlinks:
    nginx: "#{source_dir}"
default_set: 'centos-64-x64'
sets:
  'centos-59-x64':
    nodes:
      "main.foo.vm":
        prefab: 'centos-59-x64'
  'centos-64-x64':
    nodes:
      "main.foo.vm":
        prefab: 'centos-64-x64'
  'fedora-18-x64':
    nodes:
      "main.foo.vm":
        prefab: 'fedora-18-x64'
  'debian-607-x64':
    nodes:
      "main.foo.vm":
        prefab: 'debian-607-x64'
  'debian-70rc1-x64':
    nodes:
      "main.foo.vm":
        prefab: 'debian-70rc1-x64'
  'ubuntu-server-10044-x64':
    nodes:
      "main.foo.vm":
        prefab: 'ubuntu-server-10044-x64'
  'ubuntu-server-12042-x64':
    nodes:
      "main.foo.vm":
        prefab: 'ubuntu-server-12042-x64'
branches:
  except:
  - refactor
  - gh-pages
language: ruby
script: "bundle exec rake --rakefile $PWD/.travis/Rakefile spec SPEC_OPTS='--format documentation'"
rvm:
  - 1.9.3
  - 2.0.0
gemfile: .travis/Gemfile
env:
  matrix:
    - PUPPET_GEM_VERSION="~> 2.7.0"
    - PUPPET_GEM_VERSION="~> 3.0"
matrix:
  exclude:
    - rvm: 1.9.3
      env: PUPPET_GEM_VERSION="~> 2.7.0"
      gemfile: .travis/Gemfile
    - rvm: 2.0.0
      env: PUPPET_GEM_VERSION="~> 2.7.0"
      gemfile: .travis/Gemfile
notifications:
  email: false  
source 'https://rubygems.org'

group :rake do
  gem 'puppetlabs_spec_helper'
  gem 'librarian-puppet', '<1.1.0'
  gem 'open3_backport', :platforms => :ruby_18
  gem 'json',           :platforms => :ruby_18
end

if puppetversion = ENV['PUPPET_GEM_VERSION']
  gem 'puppet', puppetversion, :require => false
else
  gem 'puppet', :require => false
end
require 'puppetlabs_spec_helper/rake_tasks'

# use librarian-puppet to manage fixtures instead of .fixtures.yml
# offers more possibilities like explicit version management, forge downloads,...
task :librarian_spec_prep do
  sh "librarian-puppet install --path=$PWD/spec/fixtures/modules/"
end
task :spec_prep => :librarian_spec_prep
# Contributing

This module has become very popular, and now powers some pretty big infrastructures on many platforms. As such, it is important to be mindful of any changes that you make. Please take a moment to read the below requirements.

## TL;DR

* All PRs must adhere to the Community Style Guide
* Specs must exist for appropriate blocks of code.

## Style Matters

In an effort to introduce consistency around the code contributed to this repository, we will be using the Puppet Labs style guide. Please take a moment and familiarize yourself with this document if you have not before. http://docs.puppetlabs.com/guides/style_guide.html

If you find yourself reading some legacy code that does not adhere to these guidelines... don't fret! There is work in progress to help normalize code amongst this new style. Do your best to adhere to the new guidelines, and if you're feeling helpful, create a new issue in this repo and highlight it. PRs for additional :+1:s

For now, these style guidelines are **HIGHLY ENCOURAGED**, and a maintainer will more than likely push back if there are deviations for new code additions. These will eventually be automatically validated, but for now please do your best. If you get stuck or frustrated, please call in help from a maintainer for assistance.

## Testing

[rspec-puppet](http://rspec-puppet.com/) specs exist for a sizable chunk of our existing functionality, but not all. See here:

https://github.com/jfryman/puppet-nginx/tree/master/spec

Writing specs to confirm behavior before and after your changes is a great way to gain confidence that you're not introducing a regression.

Pull requests with specs will be merged much more quickly than those without.

Tests should not re-create resource declarations in the `rspec` DSL. Rather, test for item that...

* Are modified by a variable
* Test control logic
* Template generation
source 'https://rubygems.org'

group :rake do
  gem 'puppet',       '>=3.0.1'
  gem 'rspec-puppet', '>=1.0.1'
  gem 'rake',         '>=0.9.2.2'
  gem 'puppet-lint',  '>=0.1.12'
  gem 'puppetlabs_spec_helper'
  gem 'puppet-blacksmith'
  gem 'librarian-puppet', '<1.1.0'
  gem 'rspec-system-puppet',     :require => false
  gem 'rspec-system-serverspec', :require => false
end
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
name    'jfryman-nginx'
version '0.0.10'
source 'http://github.com/jfryman/puppet-nginx'
author 'James Fryman'
license 'Apache License Version 2.0'
summary 'Puppet NGINX management module'
description 'This module can be used for basic NGINX Management'
project_page 'http://github.com/jfryman/puppet-nginx'

dependency 'puppetlabs/stdlib', '>= 3.0.0'
dependency 'puppetlabs/apt',    '>= 1.0.0'
dependency 'puppetlabs/concat', '>= 1.1.0'
forge 'http://forge.puppetlabs.com'

mod 'puppetlabs/stdlib', '>= 3.0.0'
mod 'puppetlabs/apt',    '>= 1.0.0'
mod 'puppetlabs/concat', '>= 1.1.0'
FORGE
  remote: http://forge.puppetlabs.com
  specs:
    puppetlabs/apt (1.2.0)
      puppetlabs/stdlib (>= 2.2.1)
    puppetlabs/concat (1.1.0)
    puppetlabs/stdlib (4.1.0)

DEPENDENCIES
  puppetlabs/apt (>= 1.0.0)
  puppetlabs/concat (>= 1.1.0)
  puppetlabs/stdlib (>= 3.0.0)

# NGINX Module

[![Build Status](https://travis-ci.org/jfryman/puppet-nginx.png)](https://travis-ci.org/jfryman/puppet-nginx)

James Fryman <james@frymanet.com>

This module manages NGINX configuration.

## Quick Start

### Requirements

* Puppet-2.7.0 or later
* Ruby-1.9.3 or later (Support for Ruby-1.8.7 is not guaranteed. YMMV).

### Install and bootstrap an NGINX instance

```puppet
class { 'nginx': }
```

### Setup a new virtual host

```puppet
nginx::resource::vhost { 'www.puppetlabs.com':
  www_root => '/var/www/www.puppetlabs.com',
}
```

### Add a Proxy Server

```puppet
nginx::resource::upstream { 'puppet_rack_app':
  members => [
    'localhost:3000',
    'localhost:3001',
    'localhost:3002',
  ],
}

nginx::resource::vhost { 'rack.puppetlabs.com':
  proxy => 'http://puppet_rack_app',
}
```

### Add a smtp proxy

```puppet
class { 'nginx':
  mail => true,
}

nginx::resource::mailhost { 'domain1.example':
  auth_http   => 'server2.example/cgi-bin/auth',
  protocol    => 'smtp',
  listen_port => 587,
  ssl_port    => 465,
  starttls    => 'only',
  xclient     => 'off',
  ssl         => true,
  ssl_cert    => '/tmp/server.crt',
  ssl_key     => '/tmp/server.pem',
}
```

## SSL configuration

By default, creating a vhost resource will only create a HTTP vhost. To also create a HTTPS (SSL-enabled) vhost, set `ssl => true` on the vhost. You will have a HTTP server listening on `listen_port` (port `80` by default) and a HTTPS server listening on `ssl_port` (port `443` by default). Both vhosts will have the same `server_name` and a similar configuration.

To create only a HTTPS vhost, set `ssl => true` and also set `listen_port` to the same value as `ssl_port`. Setting these to the same value disables the HTTP vhost. The resulting vhost will be listening on `ssl_port`.

### Locations

Locations require specific settings depending on whether they should be included in the HTTP, HTTPS or both vhosts.

#### HTTP only vhost (default)
If you only have a HTTP vhost (i.e. `ssl => false` on the vhost) make sure you don't set `ssl => true` on any location you associate with the vhost.

#### HTTP and HTTPS vhost
If you set `ssl => true` and also set `listen_port` and `ssl_port` to different values on the vhost you will need to be specific with the location settings since you will have a HTTP vhost listening on `listen_port` and a HTTPS vhost listening on `ssl_port`:

* To add a location to only the HTTP server, set `ssl => false` on the location (this is the default).
* To add a location to both the HTTP and HTTPS server, set `ssl => true` on the location, and ensure `ssl_only => false` (which is the default value for `ssl_only`).
* To add a location only to the HTTPS server, set both `ssl => true` and `ssl_only => true` on the location.

#### HTTPS only vhost
If you have set `ssl => true` and also set `listen_port` and `ssl_port` to the same value on the vhost, you will have a single HTTPS vhost listening on `ssl_port`. To add a location to this vhost set `ssl => true` and `ssl_only => true` on the location.

## Hiera Support

Defining nginx resources in Hiera.

```yaml
nginx::nginx_upstreams:
  'puppet_rack_app':
    ensure: present
    members:
      - localhost:3000
      - localhost:3001
      - localhost:3002
nginx::nginx_vhosts:
  'www.puppetlabs.com':
    www_root: '/var/www/www.puppetlabs.com'
  'rack.puppetlabs.com':
    proxy: 'http://puppet_rack_app'
nginx::nginx_locations:
  'static':
    location: '~ "^/static/[0-9a-fA-F]{8}\/(.*)$"'
    vhost: www.puppetlabs.com
  'userContent':
    location: /userContent
    vhost: www.puppetlabs.com
    www_root: /var/www/html
nginx::nginx_mailhosts:
  'smtp':
    auth_http: server2.example/cgi-bin/auth
    protocol: smtp
    listen_port: 587
    ssl_port: 465
    starttls: only
```

## Nginx with precompiled Passenger

Currently this works only for Debian family.

```puppet
class { 'nginx':
  package_source  => 'passenger',
  http_cfg_append => {
    'passenger_root' => '/usr/lib/ruby/vendor_ruby/phusion_passenger/locations.ini',
  }
}
```

Package source `passenger` will add [Phusion Passenger repository](https://oss-binaries.phusionpassenger.com/apt/passenger) to APT sources.
For each virtual host you should specify which ruby should be used.

```puppet
nginx::resource::vhost { 'www.puppetlabs.com':
  www_root         => '/var/www/www.puppetlabs.com',
  vhost_cfg_append => {
    'passenger_enabled' => 'on',
    'passenger_ruby'    => '/usr/bin/ruby',
  }
}
```

### Puppet master served by Nginx and Passenger

Virtual host config for serving puppet master:

```puppet
nginx::resource::vhost { 'puppet':
  ensure               => present,
  server_name          => ['puppet'],
  listen_port          => 8140,
  ssl                  => true,
  ssl_cert             => '/var/lib/puppet/ssl/certs/example.com.pem',
  ssl_key              => '/var/lib/puppet/ssl/private_keys/example.com.pem',
  ssl_port             => 8140,
  vhost_cfg_append     => {
    'passenger_enabled'      => 'on',
    'passenger_ruby'         => '/usr/bin/ruby',
    'ssl_crl'                => '/var/lib/puppet/ssl/ca/ca_crl.pem',
    'ssl_client_certificate' => '/var/lib/puppet/ssl/certs/ca.pem',
    'ssl_verify_client'      => 'optional',
    'ssl_verify_depth'       => 1,
  },
  www_root             => '/etc/puppet/rack/public',
  use_default_location => false,
  access_log           => '/var/log/nginx/puppet_access.log',
  error_log            => '/var/log/nginx/puppet_error.log',
  passenger_cgi_param  => {
    'HTTP_X_CLIENT_DN'     => '$ssl_client_s_dn',
    'HTTP_X_CLIENT_VERIFY' => '$ssl_client_verify',
  },
}
```

### Example puppet class calling nginx::vhost with HTTPS FastCGI and redirection of HTTP

```puppet

$full_web_path = '/var/www'

define web::nginx_ssl_with_redirect (
  $backend_port         = 9000,
  $php                  = true,
  $proxy                = undef,
  $www_root             = "${full_web_path}/${name}/",
  $location_cfg_append  = undef,
) {
  nginx::resource::vhost { "${name}.${::domain}":
    ensure              => present,
    www_root            => "${full_web_path}/${name}/",
    location_cfg_append => { 'rewrite' => '^ https://$server_name$request_uri? permanent' },
  }

  if !$www_root {
    $tmp_www_root = undef
  } else {
    $tmp_www_root = $www_root
  }

  nginx::resource::vhost { "${name}.${::domain} ${name}":
    ensure                => present,
    listen_port           => 443,
    www_root              => $tmp_www_root,
    proxy                 => $proxy,
    location_cfg_append   => $location_cfg_append,
    index_files           => [ 'index.php' ],
    ssl                   => true,
    ssl_cert              => 'puppet:///modules/sslkey/wildcard_mydomain.crt',
    ssl_key               => 'puppet:///modules/sslkey/wildcard_mydomain.key',
  }


  if $php {
    nginx::resource::location { "${name}_root":
      ensure          => present,
      ssl             => true,
      ssl_only        => true,
      vhost           => "${name}.${::domain} ${name}",
      www_root        => "${full_web_path}/${name}/",
      location        => '~ \.php$',
      index_files     => ['index.php', 'index.html', 'index.htm'],
      proxy           => undef,
      fastcgi         => "127.0.0.1:${backend_port}",
      fastcgi_script  => undef,
      location_cfg_append => {
        fastcgi_connect_timeout => '3m',
        fastcgi_read_timeout    => '3m',
        fastcgi_send_timeout    => '3m'
      }
    }
  }
}
```

# Call class web::nginx_ssl_with_redirect

```puppet
web::nginx_ssl_with_redirect { 'sub-domain-name':
    backend_port => 9001,
  }
```
require 'bundler'
Bundler.require(:rake)
require 'rake/clean'

CLEAN.include('spec/fixtures/', 'doc', 'pkg')
CLOBBER.include('.tmp', '.librarian')

require 'puppetlabs_spec_helper/rake_tasks'
require 'puppet_blacksmith/rake_tasks'
require 'rspec-system/rake_task'

# use librarian-puppet to manage fixtures instead of .fixtures.yml
# offers more possibilities like explicit version management, forge downloads,...
task :librarian_spec_prep do
 sh "librarian-puppet install --path=spec/fixtures/modules/"
end
task :spec_prep => :librarian_spec_prep

task :default => [:clean, :spec]
{
    "name": "jfryman/puppet-nginx",
    "type": "project",
    "description": "Puppet module for nginx installation",
    "keywords": ["puppet", "nginx"],
    "license": "Apache-2.0",
    "require": {
    },
    "extra": {
        "branch-alias": {
            "dev-master": "1.x-dev"
        }
    }
}
# Class: nginx::config
#
# This module manages NGINX bootstrap and configuration
#
# Parameters:
#
# There are no default parameters for this class.
#
# Actions:
#
# Requires:
#
# Sample Usage:
#
# This class file is not called directly
class nginx::config(
  $client_body_buffer_size        = $nginx::params::nx_client_body_buffer_size,
  $client_body_temp_path          = $nginx::params::nx_client_body_temp_path,
  $client_max_body_size           = $nginx::params::nx_client_max_body_size,
  $confd_purge                    = $nginx::params::nx_confd_purge,
  $conf_dir                       = $nginx::params::nx_conf_dir,
  $conf_template                  = $nginx::params::nx_conf_template,
  $daemon_user                    = $nginx::params::nx_daemon_user,
  $events_use                     = $nginx::params::nx_events_use,
  $fastcgi_cache_inactive         = $nginx::params::nx_fastcgi_cache_inactive,
  $fastcgi_cache_key              = $nginx::params::nx_fastcgi_cache_key,
  $fastcgi_cache_keys_zone        = $nginx::params::nx_fastcgi_cache_keys_zone,
  $fastcgi_cache_levels           = $nginx::params::nx_fastcgi_cache_levels,
  $fastcgi_cache_max_size         = $nginx::params::nx_fastcgi_cache_max_size,
  $fastcgi_cache_path             = $nginx::params::nx_fastcgi_cache_path,
  $fastcgi_cache_use_stale        = $nginx::params::nx_fastcgi_cache_use_stale,
  $gzip                           = $nginx::params::nx_gzip,
  $http_access_log                = $nginx::params::nx_http_access_log,
  $http_cfg_append                = $nginx::params::nx_http_cfg_append,
  $http_tcp_nodelay               = $nginx::params::nx_http_tcp_nodelay,
  $http_tcp_nopush                = $nginx::params::nx_http_tcp_nopush,
  $keepalive_timeout              = $nginx::params::nx_keepalive_timeout,
  $logdir                         = $nginx::params::nx_logdir,
  $mail                           = $nginx::params::nx_mail,
  $multi_accept                   = $nginx::params::nx_multi_accept,
  $names_hash_bucket_size         = $nginx::params::nx_names_hash_bucket_size,
  $names_hash_max_size            = $nginx::params::nx_names_hash_max_size,
  $nginx_error_log                = $nginx::params::nx_nginx_error_log,
  $pid                            = $nginx::params::nx_pid,
  $proxy_buffers                  = $nginx::params::nx_proxy_buffers,
  $proxy_buffer_size              = $nginx::params::nx_proxy_buffer_size,
  $proxy_cache_inactive           = $nginx::params::nx_proxy_cache_inactive,
  $proxy_cache_keys_zone          = $nginx::params::nx_proxy_cache_keys_zone,
  $proxy_cache_levels             = $nginx::params::nx_proxy_cache_levels,
  $proxy_cache_max_size           = $nginx::params::nx_proxy_cache_max_size,
  $proxy_cache_path               = $nginx::params::nx_proxy_cache_path,
  $proxy_conf_template            = $nginx::params::nx_proxy_conf_template,
  $proxy_connect_timeout          = $nginx::params::nx_proxy_connect_timeout,
  $proxy_headers_hash_bucket_size = $nginx::params::nx_proxy_headers_hash_bucket_size,
  $proxy_http_version             = $nginx::params::nx_proxy_http_version,
  $proxy_read_timeout             = $nginx::params::nx_proxy_read_timeout,
  $proxy_redirect                 = $nginx::params::nx_proxy_redirect,
  $proxy_send_timeout             = $nginx::params::nx_proxy_send_timeout,
  $proxy_set_header               = $nginx::params::nx_proxy_set_header,
  $proxy_temp_path                = $nginx::params::nx_proxy_temp_path,
  $run_dir                        = $nginx::params::nx_run_dir,
  $sendfile                       = $nginx::params::nx_sendfile,
  $server_tokens                  = $nginx::params::nx_server_tokens,
  $spdy                           = $nginx::params::nx_spdy,
  $super_user                     = $nginx::params::nx_super_user,
  $temp_dir                       = $nginx::params::nx_temp_dir,
  $types_hash_bucket_size         = $nginx::params::nx_types_hash_bucket_size,
  $types_hash_max_size            = $nginx::params::nx_types_hash_max_size,
  $vhost_purge                    = $nginx::params::nx_vhost_purge,
  $worker_connections             = $nginx::params::nx_worker_connections,
  $worker_processes               = $nginx::params::nx_worker_processes,
  $worker_rlimit_nofile           = $nginx::params::nx_worker_rlimit_nofile,
  $global_owner                   = $nginx::params::global_owner,
  $global_group                   = $nginx::params::global_group,
  $global_mode                    = $nginx::params::global_mode,
  $sites_available_owner          = $nginx::params::sites_available_owner,
  $sites_available_group          = $nginx::params::sites_available_group,
  $sites_available_mode           = $nginx::params::sites_available_mode,
) inherits nginx::params {

  File {
    owner => $global_owner,
    group => $global_group,
    mode  => $global_mode,
  }

  file { $conf_dir:
    ensure => directory,
  }

  file { "${conf_dir}/conf.d":
    ensure => directory,
  }
  if $confd_purge == true {
    File["${conf_dir}/conf.d"] {
      purge   => true,
      recurse => true,
    }
  }

  file { "${conf_dir}/conf.mail.d":
    ensure => directory,
  }
  if $confd_purge == true {
    File["${conf_dir}/conf.mail.d"] {
      purge   => true,
      recurse => true,
    }
  }

  file { "${conf_dir}/conf.d/vhost_autogen.conf":
    ensure => absent,
  }

  file { "${conf_dir}/conf.mail.d/vhost_autogen.conf":
    ensure => absent,
  }

  file {$run_dir:
    ensure => directory,
  }

  file {$client_body_temp_path:
    ensure => directory,
    owner  => $daemon_user,
  }

  file {$proxy_temp_path:
    ensure => directory,
    owner  => $daemon_user,
  }

  file { "${conf_dir}/sites-available":
    owner  => $sites_available_owner,
    group  => $sites_available_group,
    mode   => $sites_available_mode,
    ensure => directory,
  }

  if $vhost_purge == true {
    File["${conf_dir}/sites-available"] {
      purge   => true,
      recurse => true,
    }
  }

  file { "${conf_dir}/sites-enabled":
    ensure => directory,
  }

  if $vhost_purge == true {
    File["${conf_dir}/sites-enabled"] {
      purge   => true,
      recurse => true,
    }
  }

  file { "${conf_dir}/sites-enabled/default":
    ensure => absent,
  }

  file { "${conf_dir}/nginx.conf":
    ensure  => file,
    content => template($conf_template),
  }

  file { "${conf_dir}/conf.d/proxy.conf":
    ensure  => file,
    content => template($proxy_conf_template),
  }

  file { "${conf_dir}/conf.d/default.conf":
    ensure => absent,
  }

  file { "${conf_dir}/conf.d/example_ssl.conf":
    ensure => absent,
  }

  file { "${temp_dir}/nginx.d":
    ensure  => absent,
    purge   => true,
    recurse => true,
    force   => true,
  }

  file { "${temp_dir}/nginx.mail.d":
    ensure  => absent,
    purge   => true,
    recurse => true,
    force   => true,
  }
}
# Class: nginx
#
# This module manages NGINX.
#
# Parameters:
#
# There are no default parameters for this class. All module parameters
# are managed via the nginx::params class
#
# Actions:
#
# Requires:
#  puppetlabs-stdlib - https://github.com/puppetlabs/puppetlabs-stdlib
#
#  Packaged NGINX
#    - RHEL: EPEL or custom package
#    - Debian/Ubuntu: Default Install or custom package
#    - SuSE: Default Install or custom package
#
#  stdlib
#    - puppetlabs-stdlib module >= 0.1.6
#    - plugin sync enabled to obtain the anchor type
#
# Sample Usage:
#
# The module works with sensible defaults:
#
# node default {
#   include nginx
# }
class nginx (
  $client_body_buffer_size        = $nginx::params::nx_client_body_buffer_size,
  $client_body_temp_path          = $nginx::params::nx_client_body_temp_path,
  $client_max_body_size           = $nginx::params::nx_client_max_body_size,
  $confd_purge                    = $nginx::params::nx_confd_purge,
  $configtest_enable              = $nginx::params::nx_configtest_enable,
  $conf_dir                       = $nginx::params::nx_conf_dir,
  $conf_template                  = $nginx::params::nx_conf_template,
  $daemon_user                    = $nginx::params::nx_daemon_user,
  $events_use                     = $nginx::params::nx_events_use,
  $fastcgi_cache_inactive         = $nginx::params::nx_fastcgi_cache_inactive,
  $fastcgi_cache_key              = $nginx::params::nx_fastcgi_cache_key,
  $fastcgi_cache_keys_zone        = $nginx::params::nx_fastcgi_cache_keys_zone,
  $fastcgi_cache_levels           = $nginx::params::nx_fastcgi_cache_levels,
  $fastcgi_cache_max_size         = $nginx::params::nx_fastcgi_cache_max_size,
  $fastcgi_cache_path             = $nginx::params::nx_fastcgi_cache_path,
  $fastcgi_cache_use_stale        = $nginx::params::nx_fastcgi_cache_use_stale,
  $gzip                           = $nginx::params::nx_gzip,
  $http_access_log                = $nginx::params::nx_http_access_log,
  $http_cfg_append                = $nginx::params::nx_http_cfg_append,
  $http_tcp_nodelay               = $nginx::params::nx_http_tcp_nodelay,
  $http_tcp_nopush                = $nginx::params::nx_http_tcp_nopush,
  $keepalive_timeout              = $nginx::params::nx_keepalive_timeout,
  $logdir                         = $nginx::params::nx_logdir,
  $mail                           = $nginx::params::nx_mail,
  $manage_repo                    = $nginx::params::manage_repo,
  $multi_accept                   = $nginx::params::nx_multi_accept,
  $names_hash_bucket_size         = $nginx::params::nx_names_hash_bucket_size,
  $names_hash_max_size            = $nginx::params::nx_names_hash_max_size,
  $nginx_error_log                = $nginx::params::nx_nginx_error_log,
  $nginx_locations                = {},
  $nginx_mailhosts                = {},
  $nginx_upstreams                = {},
  $nginx_vhosts                   = {},
  $package_ensure                 = $nginx::params::package_ensure,
  $package_name                   = $nginx::params::package_name,
  $package_source                 = $nginx::params::package_source,
  $pid                            = $nginx::params::nx_pid,
  $proxy_buffers                  = $nginx::params::nx_proxy_buffers,
  $proxy_buffer_size              = $nginx::params::nx_proxy_buffer_size,
  $proxy_cache_inactive           = $nginx::params::nx_proxy_cache_inactive,
  $proxy_cache_keys_zone          = $nginx::params::nx_proxy_cache_keys_zone,
  $proxy_cache_levels             = $nginx::params::nx_proxy_cache_levels,
  $proxy_cache_max_size           = $nginx::params::nx_proxy_cache_max_size,
  $proxy_cache_path               = $nginx::params::nx_proxy_cache_path,
  $proxy_conf_template            = $nginx::params::nx_proxy_conf_template,
  $proxy_connect_timeout          = $nginx::params::nx_proxy_connect_timeout,
  $proxy_headers_hash_bucket_size = $nginx::params::nx_proxy_headers_hash_bucket_size,
  $proxy_http_version             = $nginx::params::nx_proxy_http_version,
  $proxy_read_timeout             = $nginx::params::nx_proxy_read_timeout,
  $proxy_redirect                 = $nginx::params::nx_proxy_redirect,
  $proxy_send_timeout             = $nginx::params::nx_proxy_send_timeout,
  $proxy_set_header               = $nginx::params::nx_proxy_set_header,
  $proxy_temp_path                = $nginx::params::nx_proxy_temp_path,
  $run_dir                        = $nginx::params::nx_run_dir,
  $sendfile                       = $nginx::params::nx_sendfile,
  $server_tokens                  = $nginx::params::nx_server_tokens,
  $service_ensure                 = $nginx::params::nx_service_ensure,
  $service_restart                = $nginx::params::nx_service_restart,
  $spdy                           = $nginx::params::nx_spdy,
  $super_user                     = $nginx::params::nx_super_user,
  $temp_dir                       = $nginx::params::nx_temp_dir,
  $types_hash_bucket_size         = $nginx::params::nx_types_hash_bucket_size,
  $types_hash_max_size            = $nginx::params::nx_types_hash_max_size,
  $vhost_purge                    = $nginx::params::nx_vhost_purge,
  $worker_connections             = $nginx::params::nx_worker_connections,
  $worker_processes               = $nginx::params::nx_worker_processes,
  $worker_rlimit_nofile           = $nginx::params::nx_worker_rlimit_nofile,
  $global_owner                   = $nginx::params::nx_global_owner,
  $global_group                   = $nginx::params::nx_global_group,
  $global_mode                    = $nginx::params::nx_global_mode,
  $sites_available_owner          = $nginx::params::nx_sites_available_owner,
  $sites_available_group          = $nginx::params::nx_sites_available_group,
  $sites_available_mode           = $nginx::params::nx_sites_available_mode,
  $geo_mappings                   = {},
  $string_mappings                = {},
) inherits nginx::params {

  include stdlib

  if (!is_string($worker_processes)) and (!is_integer($worker_processes)) {
    fail('$worker_processes must be an integer or have value "auto".')
  }
  if (!is_integer($worker_connections)) {
    fail('$worker_connections must be an integer.')
  }
  if (!is_integer($worker_rlimit_nofile)) {
    fail('$worker_rlimit_nofile must be an integer.')
  }
  if (!is_string($events_use)) and ($events_use != false) {
    fail('$events_use must be a string or false.')
  }
  validate_string($multi_accept)
  validate_string($package_name)
  validate_string($package_ensure)
  validate_string($package_source)
  validate_array($proxy_set_header)
  validate_string($proxy_http_version)
  validate_bool($confd_purge)
  validate_bool($vhost_purge)
  if ($proxy_cache_path != false) {
    validate_string($proxy_cache_path)
  }
  if (!is_integer($proxy_cache_levels)) {
    fail('$proxy_cache_levels must be an integer.')
  }
  validate_string($proxy_cache_keys_zone)
  validate_string($proxy_cache_max_size)
  validate_string($proxy_cache_inactive)

  if ($fastcgi_cache_path != false) {
        validate_string($fastcgi_cache_path)
  }
  if (!is_integer($fastcgi_cache_levels)) {
    fail('$fastcgi_cache_levels must be an integer.')
  }
  validate_string($fastcgi_cache_keys_zone)
  validate_string($fastcgi_cache_max_size)
  validate_string($fastcgi_cache_inactive)
  if ($fastcgi_cache_key != false) {
    validate_string($fastcgi_cache_key)
  }
  if ($fastcgi_cache_use_stale != false) {
    validate_string($fastcgi_cache_use_stale)
  }

  validate_bool($configtest_enable)
  validate_string($service_restart)
  validate_bool($mail)
  validate_string($server_tokens)
  validate_string($client_max_body_size)
  if (!is_integer($names_hash_bucket_size)) {
    fail('$names_hash_bucket_size must be an integer.')
  }
  if (!is_integer($names_hash_max_size)) {
    fail('$names_hash_max_size must be an integer.')
  }
  validate_string($proxy_buffers)
  validate_string($proxy_buffer_size)
  if ($http_cfg_append != false) {
    if !(is_hash($http_cfg_append) or is_array($http_cfg_append)) {
      fail('$http_cfg_append must be either a hash or array')
    }
  }

  validate_string($nginx_error_log)
  validate_string($http_access_log)
  validate_hash($nginx_upstreams)
  validate_hash($nginx_vhosts)
  validate_hash($nginx_locations)
  validate_hash($nginx_mailhosts)
  validate_bool($manage_repo)
  validate_string($proxy_headers_hash_bucket_size)
  validate_bool($super_user)

  validate_hash($string_mappings)
  validate_hash($geo_mappings)

  class { 'nginx::package':
    package_name   => $package_name,
    package_source => $package_source,
    package_ensure => $package_ensure,
    notify         => Class['nginx::service'],
    manage_repo    => $manage_repo,
  }

  class { 'nginx::config':
    client_body_buffer_size        => $client_body_buffer_size,
    client_body_temp_path          => $client_body_temp_path,
    client_max_body_size           => $client_max_body_size,
    confd_purge                    => $confd_purge,
    conf_dir                       => $conf_dir,
    conf_template                  => $conf_template,
    daemon_user                    => $daemon_user,
    events_use                     => $events_use,
    fastcgi_cache_inactive         => $fastcgi_cache_inactive,
    fastcgi_cache_key              => $fastcgi_cache_key,
    fastcgi_cache_keys_zone        => $fastcgi_cache_keys_zone,
    fastcgi_cache_levels           => $fastcgi_cache_levels,
    fastcgi_cache_max_size         => $fastcgi_cache_max_size,
    fastcgi_cache_path             => $fastcgi_cache_path,
    fastcgi_cache_use_stale        => $fastcgi_cache_use_stale,
    gzip                           => $gzip,
    http_access_log                => $http_access_log,
    http_cfg_append                => $http_cfg_append,
    http_tcp_nodelay               => $http_tcp_nodelay,
    http_tcp_nopush                => $http_tcp_nopush,
    keepalive_timeout              => $keepalive_timeout,
    logdir                         => $logdir,
    mail                           => $mail,
    multi_accept                   => $multi_accept,
    names_hash_bucket_size         => $names_hash_bucket_size,
    names_hash_max_size            => $names_hash_max_size,
    nginx_error_log                => $nginx_error_log,
    pid                            => $pid,
    proxy_buffers                  => $proxy_buffers,
    proxy_buffer_size              => $proxy_buffer_size,
    proxy_cache_inactive           => $proxy_cache_inactive,
    proxy_cache_keys_zone          => $proxy_cache_keys_zone,
    proxy_cache_levels             => $proxy_cache_levels,
    proxy_cache_max_size           => $proxy_cache_max_size,
    proxy_cache_path               => $proxy_cache_path,
    proxy_conf_template            => $proxy_conf_template,
    proxy_connect_timeout          => $proxy_connect_timeout,
    proxy_headers_hash_bucket_size => $proxy_headers_hash_bucket_size,
    proxy_http_version             => $proxy_http_version,
    proxy_read_timeout             => $proxy_read_timeout,
    proxy_redirect                 => $proxy_redirect,
    proxy_send_timeout             => $proxy_send_timeout,
    proxy_set_header               => $proxy_set_header,
    proxy_temp_path                => $proxy_temp_path,
    run_dir                        => $run_dir,
    sendfile                       => $sendfile,
    server_tokens                  => $server_tokens,
    spdy                           => $spdy,
    super_user                     => $super_user,
    temp_dir                       => $temp_dir,
    types_hash_bucket_size         => $types_hash_bucket_size,
    types_hash_max_size            => $types_hash_max_size,
    vhost_purge                    => $vhost_purge,
    worker_connections             => $worker_connections,
    worker_processes               => $worker_processes,
    worker_rlimit_nofile           => $worker_rlimit_nofile,
    global_owner                   => $global_owner,
    global_group                   => $global_group,
    global_mode                    => $global_mode,
    sites_available_owner          => $sites_available_owner,
    sites_available_group          => $sites_available_group,
    sites_available_mode           => $sites_available_mode,
    require                        => Class['nginx::package'],
    notify                         => Class['nginx::service'],
  }

  class { 'nginx::service':
  }

  create_resources('nginx::resource::upstream', $nginx_upstreams)
  create_resources('nginx::resource::vhost', $nginx_vhosts)
  create_resources('nginx::resource::location', $nginx_locations)
  create_resources('nginx::resource::mailhost', $nginx_mailhosts)
  create_resources('nginx::resource::map', $string_mappings)
  create_resources('nginx::resource::geo', $geo_mappings)

  # Allow the end user to establish relationships to the "main" class
  # and preserve the relationship to the implementation classes through
  # a transitive relationship to the composite class.
  anchor{ 'nginx::begin':
    before => Class['nginx::package'],
    notify => Class['nginx::service'],
  }
  anchor { 'nginx::end':
    require => Class['nginx::service'],
  }
}
# Class: nginx::package
#
# This module manages NGINX package installation
#
# Parameters:
#
# There are no default parameters for this class.
#
# Actions:
#
# Requires:
#
# Sample Usage:
#
# This class file is not called directly
class nginx::package(
  $package_name   = 'nginx',
  $package_source = 'nginx',
  $package_ensure = 'present',
  $manage_repo    = true,
) {

  anchor { 'nginx::package::begin': }
  anchor { 'nginx::package::end': }

  case $::osfamily {
    'redhat': {
      class { 'nginx::package::redhat':
        manage_repo    => $manage_repo,
        package_ensure => $package_ensure,
        package_name   => $package_name,
        require        => Anchor['nginx::package::begin'],
        before         => Anchor['nginx::package::end'],
      }
    }
    'debian': {
      class { 'nginx::package::debian':
        package_name   => $package_name,
        package_source => $package_source,
        package_ensure => $package_ensure,
        manage_repo    => $manage_repo,
        require        => Anchor['nginx::package::begin'],
        before         => Anchor['nginx::package::end'],
      }
    }
    'suse': {
      class { 'nginx::package::suse':
        package_name => $package_name,
        require      => Anchor['nginx::package::begin'],
        before       => Anchor['nginx::package::end'],
      }
    }
    'archlinux': {
      class { 'nginx::package::archlinux':
        require => Anchor['nginx::package::begin'],
        before  => Anchor['nginx::package::end'],
      }
    }
    'Solaris': {
      class { 'nginx::package::solaris':
        package_name   => $package_name,
        package_source => $package_source,
        package_ensure => $package_ensure,
        require        => Anchor['nginx::package::begin'],
        before         => Anchor['nginx::package::end'],
      }
    }
    'FreeBSD': {
      class { 'nginx::package::freebsd':
        package_name   => $package_name,
        package_ensure => $package_ensure,
        require        => Anchor['nginx::package::begin'],
        before         => Anchor['nginx::package::end'],
      }
    }
    default: {
      case $::operatingsystem {
        'amazon': {
          # Amazon was added to osfamily RedHat in 1.7.2
          # https://github.com/puppetlabs/facter/commit/c12d3b6c557df695a7b2b009da099f6a93c7bd31#lib/facter/osfamily.rb
          warning("Module ${module_name} support for ${::operatingsystem} with facter < 1.7.2 is deprecated")
          warning("Please upgrade from facter ${::facterversion} to >= 1.7.2")
          class { 'nginx::package::redhat':
            require => Anchor['nginx::package::begin'],
            before  => Anchor['nginx::package::end'],
          }
        }
        default: {
          fail("Module ${module_name} is not supported on ${::operatingsystem}")
        }
      }
    }
  }
}
# Class: nginx::package::archlinux
#
# This module manages NGINX package installation on Archlinux based systems
#
# Parameters:
#
# There are no default parameters for this class.
#
# Actions:
#
# Requires:
#
# Sample Usage:
#
# This class file is not called directly
class nginx::package::archlinux(
    $package_name   = 'nginx',
    $package_ensure = 'present'
  ) {

  package { $package_name:
    ensure  => $package_ensure,
  }

}
# Class: nginx::package::debian
#
# This module manages NGINX package installation on debian based systems
#
# Parameters:
#
# There are no default parameters for this class.
#
# Actions:
#
# Requires:
#
# Sample Usage:
#
# This class file is not called directly
class nginx::package::debian(
    $manage_repo    = true,
    $package_name   = 'nginx',
    $package_source = 'nginx',
    $package_ensure = 'present'
  ) {

  $distro = downcase($::operatingsystem)

  package { $package_name:
    ensure  => $package_ensure,
    require => Anchor['nginx::apt_repo'],
  }

  anchor { 'nginx::apt_repo' : }

  if $manage_repo {
    include '::apt'

    case $package_source {
      'nginx': {
        apt::source { 'nginx':
          location   => "http://nginx.org/packages/${distro}",
          repos      => 'nginx',
          key        => '7BD9BF62',
          key_source => 'http://nginx.org/keys/nginx_signing.key',
          notify     => Exec['apt_get_update_for_nginx'],
        }
      }
      'passenger': {
        ensure_resource('package', 'apt-transport-https', {'ensure' => 'present' })

        apt::source { 'nginx':
          location   => 'https://oss-binaries.phusionpassenger.com/apt/passenger',
          repos      => "main",
          key        => '561F9B9CAC40B2F7',
          key_source => 'https://oss-binaries.phusionpassenger.com/auto-software-signing-gpg-key.txt',
          notify     => Exec['apt_get_update_for_nginx'],
        }

        package { 'passenger':
          ensure  => 'present',
          require => Anchor['nginx::apt_repo'],
        }
      }
      default: {}
    }

    exec { 'apt_get_update_for_nginx':
      command     => '/usr/bin/apt-get update',
      timeout     => 240,
      returns     => [ 0, 100 ],
      refreshonly => true,
      before      => Anchor['nginx::apt_repo'],
    }
  }
}
# Class: nginx::package::freebsd
#
# Manage the nginx package on FreeBSD
class nginx::package::freebsd (
    $package_name   = 'nginx',
    $package_ensure = 'present'
) {

  package { $package_name:
    ensure  => $package_ensure,
  }
}
# Class: nginx::package::redhat
#
# This module manages NGINX package installation on RedHat based systems
#
# Parameters:
#
# There are no default parameters for this class.
#
# Actions:
#
# Requires:
#
# Sample Usage:
#
# This class file is not called directly
class nginx::package::redhat (
  $manage_repo    = true,
  $package_ensure = 'present',
  $package_name   = 'nginx',
) {

  case $::operatingsystem {
    'fedora': {
      # nginx.org does not supply RPMs for fedora
      # fedora 18 provides 1.2.x packages
      # fedora 19 has 1.4.x packages are in

      # fedora 18 users will need to supply their own nginx 1.4 rpms and/or repo
      if $::lsbmajdistrelease and $::lsbmajdistrelease < 19 {
        notice("${::operatingsystem} ${::lsbmajdistrelease} does not supply nginx >= 1.4 packages")
      }
    }
    default: {
      case $::lsbmajdistrelease {
        5, 6: {
          $os_rel = $::lsbmajdistrelease
        }
        default: {
          # Amazon uses the year as the $::lsbmajdistrelease
          $os_rel = 6
        }
      }

      # as of 2013-07-28
      # http://nginx.org/packages/centos appears to be identical to
      # http://nginx.org/packages/rhel
      # no other dedicated dirs exist for platforms under $::osfamily == redhat
      if $manage_repo {
        yumrepo { 'nginx-release':
          baseurl  => "http://nginx.org/packages/rhel/${os_rel}/\$basearch/",
          descr    => 'nginx repo',
          enabled  => '1',
          gpgcheck => '1',
          priority => '1',
          gpgkey   => 'http://nginx.org/keys/nginx_signing.key',
          before   => Package[$package_name],
        }

        file { '/etc/yum.repos.d/nginx-release.repo':
          ensure  => present,
          require => Yumrepo['nginx-release'],
        }
      }
    }
  }

  package { $package_name:
    ensure  => $package_ensure,
  }

}
# Class: nginx::package::solaris
#
# This module manages NGINX package installation on solaris based systems
#
# Parameters:
#
# *package_name*
# Needs to be specified. SFEnginx,CSWnginx depending on where you get it.
#
# *package_source*
# Needed in case of Solaris 10.
#
# Actions:
#
# Requires:
#
# Sample Usage:
#
# This class file is not called directly
class nginx::package::solaris(
    $package_name   = undef,
    $package_source = '',
    $package_ensure = 'present'
  ){
  package { $package_name:
    ensure => $package_ensure,
    source => $package_source
  }
}
# Class: nginx::package::suse
#
# This module manages NGINX package installation for SuSE based systems
#
# Parameters:
#
# There are no default parameters for this class.
#
# Actions:
#  This module contains all of the required package for SuSE. Apache and all
#  other packages listed below are built into the packaged RPM spec for
#  SuSE and OpenSuSE.
# Requires:
#
# Sample Usage:
#
# This class file is not called directly
class nginx::package::suse (
  $package_name = 'nginx'
) {

  if $caller_module_name != $module_name {
    warning("${name} is deprecated as a public API of the ${module_name} module and should no longer be directly included in the manifest.")
  }

  package { $package_name:
    ensure => $nginx::package_ensure,
  }
}
# Class: nginx::param
#
# This module manages NGINX paramaters
#
# Parameters:
#
# There are no default parameters for this class.
#
# Actions:
#
# Requires:
#
# Sample Usage:
#
# This class file is not called directly
class nginx::params {

  $nx_temp_dir                       = '/tmp'
  $nx_run_dir                        = '/var/nginx'

  $nx_conf_template                  = 'nginx/conf.d/nginx.conf.erb'
  $nx_proxy_conf_template            = 'nginx/conf.d/proxy.conf.erb'
  $nx_confd_purge                    = false
  $nx_vhost_purge                    = false
  $nx_worker_processes               = 1
  $nx_worker_connections             = 1024
  $nx_worker_rlimit_nofile           = 1024
  $nx_types_hash_max_size            = 1024
  $nx_types_hash_bucket_size         = 512
  $nx_names_hash_bucket_size         = 64
  $nx_names_hash_max_size            = 512
  $nx_multi_accept                   = off
  # One of [kqueue|rtsig|epoll|/dev/poll|select|poll|eventport]
  # or false to use OS default
  $nx_events_use                     = false
  $nx_sendfile                       = on
  $nx_keepalive_timeout              = 65
  $nx_http_tcp_nodelay               = on
  $nx_http_tcp_nopush                = off
  $nx_gzip                           = on
  $nx_server_tokens                  = on
  $nx_spdy                           = off
  $nx_ssl_stapling                   = off

  $nx_proxy_redirect                 = off
  $nx_proxy_set_header               = [
    'Host $host',
    'X-Real-IP $remote_addr',
    'X-Forwarded-For $proxy_add_x_forwarded_for',
  ]
  $nx_proxy_cache_path               = false
  $nx_proxy_cache_levels             = 1
  $nx_proxy_cache_keys_zone          = 'd2:100m'
  $nx_proxy_cache_max_size           = '500m'
  $nx_proxy_cache_inactive           = '20m'

  $nx_fastcgi_cache_path             = false
  $nx_fastcgi_cache_levels           = 1
  $nx_fastcgi_cache_keys_zone        = 'd3:100m'
  $nx_fastcgi_cache_max_size         = '500m'
  $nx_fastcgi_cache_inactive         = '20m'
  $nx_fastcgi_cache_key              = false
  $nx_fastcgi_cache_use_stale        = false

  $nx_client_body_temp_path          = "${nx_run_dir}/client_body_temp"
  $nx_client_body_buffer_size        = '128k'
  $nx_client_max_body_size           = '10m'
  $nx_proxy_temp_path                = "${nx_run_dir}/proxy_temp"
  $nx_proxy_connect_timeout          = '90'
  $nx_proxy_send_timeout             = '90'
  $nx_proxy_read_timeout             = '90'
  $nx_proxy_buffers                  = '32 4k'
  $nx_proxy_http_version             = '1.0'
  $nx_proxy_buffer_size              = '8k'
  $nx_proxy_headers_hash_bucket_size = '64'

  $nx_logdir = '/var/log/nginx'

  $nx_pid = $::kernel ? {
    /(?i-mx:linux)/   => $::osfamily ? {
        # archlinux has hardcoded pid in service file to /run/nginx.pid, setting
        # it will prevent nginx from starting
        /(?i-mx:archlinux)/ => false,
        default             => '/var/run/nginx.pid',
    },
    /(?i-mx:sunos)/   => '/var/run/nginx.pid',
    /(?i-mx:freebsd)/ => '/var/run/nginx.pid',
  }

  $nx_conf_dir = $::kernelversion ? {
    /(?i-mx:joyent)/    => '/opt/local/etc/nginx',
    default             => $::kernel ? {
      /(?i-mx:freebsd)/ => '/usr/local/etc/nginx',
      default           => '/etc/nginx',
    }
  }

  if $::osfamily {
    $solaris_nx_daemon_user = $::kernelversion ? {
      /(?i-mx:joyent)/ => 'www',
      default => 'webservd',
    }
    $nx_daemon_user = $::osfamily ? {
      /(?i-mx:archlinux)/                => 'http',
      /(?i-mx:redhat|suse|gentoo|linux)/ => 'nginx',
      /(?i-mx:debian)/                   => 'www-data',
      /(?i-mx:solaris)/                  => $solaris_nx_daemon_user,
      /(?i-mx:freebsd)/                  => 'www',
    }
  } else {
    warning('$::osfamily not defined. Support for $::operatingsystem is deprecated')
    warning("Please upgrade from facter ${::facterversion} to >= 1.7.2")
    $nx_daemon_user = $::operatingsystem ? {
      /(?i-mx:archlinux)/                                                                    => 'http',
      /(?i-mx:debian|ubuntu)/                                                                => 'www-data',
      /(?i-mx:fedora|rhel|redhat|centos|scientific|suse|opensuse|amazon|gentoo|oraclelinux)/ => 'nginx',
      /(?i-mx:solaris)/                                                                      => 'webservd',
      /(?i-mx:freebsd)/                                                                      => 'www',
    }
  }

  $root_group = $::operatingsystem ? {
    'FreeBSD' => 'wheel',
    default   => 'root',
  }

  # Nginx is default launched as root if not change this parameter
  $nx_super_user = true

  # Service restart after Nginx 0.7.53 could also be just
  # "/path/to/nginx/bin -s HUP" Some init scripts do a configtest, some don't.
  # If configtest_enable it's true then service restart will take
  # $nx_service_restart value, forcing configtest.

  $nx_configtest_enable = false
  $nx_service_restart = '/etc/init.d/nginx configtest && /etc/init.d/nginx restart'
  $nx_service_ensure = running

  $nx_mail = false

  $nx_http_cfg_append = false

  $nx_nginx_error_log = "${nx_logdir}/error.log"
  $nx_http_access_log = "${nx_logdir}/access.log"

  # package name depends on distribution, e.g. for Debian nginx-full | nginx-light
  $package_name   = 'nginx'
  $package_ensure = 'present'
  $package_source = 'nginx'
  $manage_repo    = true

  # Specific owner for sites-available directory
  $sites_available_owner = 'root'
  $sites_available_group = $root_group
  $sites_available_mode  = '0644'

  # Owner for all other files
  $global_owner = 'root'
  $global_group = $root_group
  $global_mode  = '0644'
}
# define: nginx::resource::geo
#
# This definition creates a new geo mapping entry for NGINX
#
# Parameters:
#   [*networks*]        - Hash of geo lookup keys and resultant values
#   [*default*]         - Sets the resulting value if the source value fails to
#                         match any of the variants.
#   [*ensure*]          - Enables or disables the specified location
#   [*ranges*]          - Indicates that lookup keys (network addresses) are
#                         specified as ranges.
#   [*address*]         - Nginx defaults to using $remote_addr for testing.
#                         This allows you to override that with another variable
#                         name (automatically prefixed with $)
#   [*delete*]          - deletes the specified network (see: geo module docs)
#   [*proxy_recursive*] - Changes the behavior of address acquisition when
#                         specifying trusted proxies via 'proxies' directive
#   [*proxies*]         - Hash of network->value mappings.

# Actions:
#
# Requires:
#
# Sample Usage:
#
#  nginx::resource::geo { 'client_network':
#    ensure          => present,
#    ranges          => false,
#    default         => extra,
#    proxy_recursive => false,
#    proxies         => [ '192.168.99.99' ],
#    networks        => {
#      '10.0.0.0/8'     => 'intra',
#      '172.16.0.0/12'  => 'intra',
#      '192.168.0.0/16' => 'intra',
#    }
#  }
#
# Sample Hiera usage:
#
#  nginx::geos:
#    client_network:
#      ensure: present
#      ranges: false
#      default: 'extra'
#      proxy_recursive: false
#      proxies:
#         - 192.168.99.99
#      networks:
#        '10.0.0.0/8': 'intra'
#        '172.16.0.0/12': 'intra'
#        '192.168.0.0/16': 'intra'


define nginx::resource::geo (
  $networks,
  $default         = undef,
  $ensure          = 'present',
  $ranges          = false,
  $address         = undef,
  $delete          = undef,
  $proxies         = undef,
  $proxy_recursive = undef
) {

  validate_hash($networks)
  validate_bool($ranges)
  validate_re($ensure, '^(present|absent)$',
    "Invalid ensure value '${ensure}'. Expected 'present' or 'absent'")
  if ($default != undef) { validate_string($default) }
  if ($address != undef) { validate_string($address) }
  if ($delete != undef) { validate_string($delete) }
  if ($proxies != undef) { validate_array($proxies) }
  if ($proxy_recursive != undef) { validate_bool($proxy_recursive) }

  include nginx::params
  $root_group = $nginx::params::root_group

  File {
    owner => 'root',
    group => $root_group,
    mode  => '0644',
  }

  file { "${nginx::config::conf_dir}/conf.d/${name}-geo.conf":
    ensure  => $ensure ? {
      'absent' => absent,
      default  => 'file',
    },
    content => template('nginx/conf.d/geo.erb'),
    notify  => Class['nginx::service'],
  }
}
# define: nginx::resource::location
#
# This definition creates a new location entry within a virtual host
#
# Parameters:
#   [*ensure*]               - Enables or disables the specified location
#     (present|absent)
#   [*internal*]             - Indicates whether or not this loation can be
#     used for internal requests only. Default: false
#   [*vhost*]                - Defines the default vHost for this location
#     entry to include with
#   [*location*]             - Specifies the URI associated with this location
#     entry
#   [*location_allow*]       - Array: Locations to allow connections from.
#   [*location_deny*]        - Array: Locations to deny connections from.
#   [*www_root*]             - Specifies the location on disk for files to be
#     read from. Cannot be set in conjunction with $proxy
#   [*autoindex*]            - Set it on 'on' to activate autoindex directory
#     listing. Undef by default.
#   [*index_files*]          - Default index files for NGINX to read when
#     traversing a directory
#   [*proxy*]                - Proxy server(s) for a location to connect to.
#     Accepts a single value, can be used in conjunction with
#     nginx::resource::upstream
#   [*proxy_redirect*]       - sets the text, which must be changed in
#     response-header "Location" and "Refresh" in the response of the proxied
#     server.
#   [*proxy_read_timeout*]   - Override the default the proxy read timeout
#     value of 90 seconds
#   [*proxy_connect_timeout*] - Override the default the proxy connect timeout
#     value of 90 seconds
#   [*proxy_set_header*]     - Array of vhost headers to set
#   [*fastcgi*]              - location of fastcgi (host:port)
#   [*fastcgi_params*]       - optional alternative fastcgi_params file to use
#   [*fastcgi_script*]       - optional SCRIPT_FILE parameter
#   [*fastcgi_split_path*]   - Allows settings of fastcgi_split_path_info so
#     that you can split the script_name and path_info via regex
#   [*ssl*]                  - Indicates whether to setup SSL bindings for
#     this location.
#   [*ssl_only*]             - Required if the SSL and normal vHost have the
#     same port.
#   [*location_alias*]       - Path to be used as basis for serving requests
#     for this location
#   [*stub_status*]          - If true it will point configure module
#     stub_status to provide nginx stats on location
#   [*raw_prepend*]          - A single string, or an array of strings to
#     prepend to the location directive (after custom_cfg directives). NOTE:
#     YOU are responsible for a semicolon on each line that requires one.
#   [*raw_append*]           - A single string, or an array of strings to
#     append to the location directive (after custom_cfg directives). NOTE:
#     YOU are responsible for a semicolon on each line that requires one.
#   [*location_custom_cfg*]  - Expects a hash with custom directives, cannot
#     be used with other location types (proxy, fastcgi, root, or stub_status)
#   [*location_cfg_prepend*] - Expects a hash with extra directives to put
#     before anything else inside location (used with all other types except
#     custom_cfg)
#   [*location_custom_cfg_prepend*]   - Expects a array with extra directives
#     to put before anything else inside location (used with all other types
#     except custom_cfg). Used for logical structures such as if.
#   [*location_custom_cfg_append*]    - Expects a array with extra directives
#     to put before anything else inside location (used with all other types
#     except custom_cfg). Used for logical structures such as if.
#   [*location_cfg_append*]  - Expects a hash with extra directives to put
#     after everything else inside location (used with all other types except
#     custom_cfg)
#   [*try_files*]            - An array of file locations to try
#   [*option*]               - Reserved for future use
#   [*proxy_cache*]           - This directive sets name of zone for caching.
#     The same zone can be used in multiple places.
#   [*proxy_cache_valid*]     - This directive sets the time for caching
#     different replies.
#   [*proxy_method*]         - If defined, overrides the HTTP method of the
#     request to be passed to the backend.
#   [*proxy_set_body*]       - If defined, sets the body passed to the backend.
#   [*auth_basic*]            - This directive includes testing name and password
#     with HTTP Basic Authentication.
#   [*auth_basic_user_file*]  - This directive sets the htpasswd filename for
#     the authentication realm.
#   [*priority*]              - Location priority. Default: 500. User priority
#     401-499, 501-599. If the priority is higher than the default priority,
#     the location will be defined after root, or before root.
#
#
# Actions:
#
# Requires:
#
# Sample Usage:
#  nginx::resource::location { 'test2.local-bob':
#    ensure   => present,
#    www_root => '/var/www/bob',
#    location => '/bob',
#    vhost    => 'test2.local',
#  }
#
#  Custom config example to limit location on localhost,
#  create a hash with any extra custom config you want.
#  $my_config = {
#    'access_log' => 'off',
#    'allow'      => '127.0.0.1',
#    'deny'       => 'all'
#  }
#  nginx::resource::location { 'test2.local-bob':
#    ensure              => present,
#    www_root            => '/var/www/bob',
#    location            => '/bob',
#    vhost               => 'test2.local',
#    location_cfg_append => $my_config,
#  }

define nginx::resource::location (
  $ensure               = present,
  $internal             = false,
  $location             = $name,
  $vhost                = undef,
  $www_root             = undef,
  $autoindex            = undef,
  $index_files          = [
    'index.html',
    'index.htm',
    'index.php'],
  $proxy                = undef,
  $proxy_redirect       = $nginx::config::proxy_redirect,
  $proxy_read_timeout   = $nginx::config::proxy_read_timeout,
  $proxy_connect_timeout = $nginx::config::proxy_connect_timeout,
  $proxy_set_header     = $nginx::config::proxy_set_header,
  $fastcgi              = undef,
  $fastcgi_params       = "${nginx::config::conf_dir}/fastcgi_params",
  $fastcgi_script       = undef,
  $fastcgi_split_path   = undef,
  $ssl                  = false,
  $ssl_only             = false,
  $location_alias       = undef,
  $location_allow       = undef,
  $location_deny        = undef,
  $option               = undef,
  $stub_status          = undef,
  $raw_prepend          = undef,
  $raw_append           = undef,
  $location_custom_cfg  = undef,
  $location_cfg_prepend = undef,
  $location_cfg_append  = undef,
  $location_custom_cfg_prepend  = undef,
  $location_custom_cfg_append   = undef,
  $try_files            = undef,
  $proxy_cache          = false,
  $proxy_cache_valid    = false,
  $proxy_method         = undef,
  $proxy_set_body       = undef,
  $auth_basic           = undef,
  $auth_basic_user_file = undef,
  $rewrite_rules        = [],
  $priority             = 500
) {

  include nginx::params
  $root_group = $nginx::params::root_group

  File {
    owner  => 'root',
    group  => $root_group,
    mode   => '0644',
    notify => Class['nginx::service'],
  }

  validate_re($ensure, '^(present|absent)$',
    "${ensure} is not supported for ensure. Allowed values are 'present' and 'absent'.")
  validate_string($location)
  if ($vhost != undef) {
    validate_string($vhost)
  }
  if ($www_root != undef) {
    validate_string($www_root)
  }
  if ($autoindex != undef) {
    validate_string($autoindex)
  }
  validate_array($index_files)
  if ($proxy != undef) {
    validate_string($proxy)
  }
  validate_string($proxy_redirect)
  validate_string($proxy_read_timeout)
  validate_string($proxy_connect_timeout)
  validate_array($proxy_set_header)
  if ($fastcgi != undef) {
    validate_string($fastcgi)
  }
  validate_string($fastcgi_params)
  if ($fastcgi_script != undef) {
    validate_string($fastcgi_script)
  }
  if ($fastcgi_split_path != undef) {
    validate_string($fastcgi_split_path)
  }

  validate_bool($internal)

  validate_bool($ssl)
  validate_bool($ssl_only)
  if ($location_alias != undef) {
    validate_string($location_alias)
  }
  if ($location_allow != undef) {
    validate_array($location_allow)
  }
  if ($location_deny != undef) {
    validate_array($location_deny)
  }
  if ($option != undef) {
    warning('The $option parameter has no effect and is deprecated.')
  }
  if ($stub_status != undef) {
    validate_bool($stub_status)
  }
  if ($raw_prepend != undef) {
    if (is_array($raw_prepend)) {
      validate_array($raw_prepend)
    } else {
      validate_string($raw_prepend)
    }
  }
  if ($raw_append != undef) {
    if (is_array($raw_append)) {
      validate_array($raw_append)
    } else {
      validate_string($raw_append)
    }
  }
  if ($location_custom_cfg != undef) {
    validate_hash($location_custom_cfg)
  }
  if ($location_cfg_prepend != undef) {
    validate_hash($location_cfg_prepend)
  }
  if ($location_cfg_append != undef) {
    validate_hash($location_cfg_append)
  }
  if ($try_files != undef) {
    validate_array($try_files)
  }
  if ($proxy_cache != false) {
    validate_string($proxy_cache)
  }
  if ($proxy_cache_valid != false) {
    validate_string($proxy_cache_valid)
  }
  if ($proxy_method != undef) {
    validate_string($proxy_method)
  }
  if ($proxy_set_body != undef) {
    validate_string($proxy_set_body)
  }
  if ($auth_basic != undef) {
    validate_string($auth_basic)
  }
  if ($auth_basic_user_file != undef) {
    validate_string($auth_basic_user_file)
  }
  if !is_integer($priority) {
    fail('$priority must be an integer.')
  }
  validate_array($rewrite_rules)
  if ($priority < 401) or ($priority > 899) {
    fail('$priority must be in the range 401-899.')
  }

  # # Shared Variables
  $ensure_real = $ensure ? {
    'absent' => absent,
    default  => file,
  }

  $vhost_sanitized = regsubst($vhost, ' ', '_', 'G')
  $config_file = "${nginx::config::conf_dir}/sites-available/${vhost_sanitized}.conf"

  $location_sanitized_tmp = regsubst($location, '\/', '_', 'G')
  $location_sanitized = regsubst($location_sanitized_tmp, "\\\\", '_', 'G')

  ## Check for various error conditions
  if ($vhost == undef) {
    fail('Cannot create a location reference without attaching to a virtual host')
  }
  if (($www_root == undef) and ($proxy == undef) and ($location_alias == undef) and ($stub_status == undef) and ($fastcgi == undef) and ($location_custom_cfg == undef)) {
    fail('Cannot create a location reference without a www_root, proxy, location_alias, fastcgi, stub_status, or location_custom_cfg defined')
  }
  if (($www_root != undef) and ($proxy != undef)) {
    fail('Cannot define both directory and proxy in a virtual host')
  }

  # Use proxy or fastcgi template if $proxy is defined, otherwise use directory template.
  if ($proxy != undef) {
    $content_real = template('nginx/vhost/locations/proxy.erb')
  } elsif ($location_alias != undef) {
    $content_real = template('nginx/vhost/locations/alias.erb')
  } elsif ($stub_status != undef) {
    $content_real = template('nginx/vhost/locations/stub_status.erb')
  } elsif ($fastcgi != undef) {
    $content_real = template('nginx/vhost/locations/fastcgi.erb')
  } elsif ($www_root != undef) {
    $content_real = template('nginx/vhost/locations/directory.erb')
  } else {
    $content_real = template('nginx/vhost/locations/empty.erb')
  }

  if $fastcgi != undef and !defined(File[$fastcgi_params]) {
    file { $fastcgi_params:
      ensure  => present,
      mode    => '0770',
      content => template('nginx/vhost/fastcgi_params.erb'),
    }
  }

  ## Create stubs for vHost File Fragment Pattern
  if ($ssl_only != true) {
    $tmpFile=md5("${vhost_sanitized}-${priority}-${location_sanitized}")

    concat::fragment { "${tmpFile}":
      ensure  => present,
      target  => $config_file,
      content => join([
        template('nginx/vhost/location_header.erb'),
        $content_real,
        template('nginx/vhost/location_footer.erb')
      ], ''),
      order   => "${priority}",
    }
  }

  ## Only create SSL Specific locations if $ssl is true.
  if ($ssl == true or $ssl_only == true) {
    $ssl_priority = $priority + 300

    $sslTmpFile=md5("${vhost_sanitized}-${ssl_priority}-${location_sanitized}-ssl")
    concat::fragment {"${sslTmpFile}":
      ensure  => present,
      target  => $config_file,
      content => join([
        template('nginx/vhost/location_header.erb'),
        $content_real,
        template('nginx/vhost/location_footer.erb')
      ], ''),
      order   => "${ssl_priority}",
    }
  }

  if ($auth_basic_user_file != undef) {
    #Generate htpasswd with provided file-locations
    file { "${nginx::config::conf_dir}/${location_sanitized}_htpasswd":
      ensure => $ensure,
      mode   => '0644',
      source => $auth_basic_user_file,
    }
  }
}
# define: nginx::resource::mailhost
#
# This definition creates a virtual host
#
# Parameters:
#   [*ensure*]              - Enables or disables the specified mailhost (present|absent)
#   [*listen_ip*]           - Default IP Address for NGINX to listen with this vHost on. Defaults to all interfaces (*)
#   [*listen_port*]         - Default IP Port for NGINX to listen with this vHost on. Defaults to TCP 80
#   [*listen_options*]      - Extra options for listen directive like 'default' to catchall. Undef by default.
#   [*ipv6_enable*]         - BOOL value to enable/disable IPv6 support (false|true). Module will check to see if IPv6
#                             support exists on your system before enabling.
#   [*ipv6_listen_ip*]      - Default IPv6 Address for NGINX to listen with this vHost on. Defaults to all interfaces (::)
#   [*ipv6_listen_port*]    - Default IPv6 Port for NGINX to listen with this vHost on. Defaults to TCP 80
#   [*ipv6_listen_options*] - Extra options for listen directive like 'default' to catchall. Template will allways add ipv6only=on.
#                             While issue jfryman/puppet-nginx#30 is discussed, default value is 'default'.
#   [*index_files*]         - Default index files for NGINX to read when traversing a directory
#   [*ssl*]                 - Indicates whether to setup SSL bindings for this mailhost.
#   [*ssl_cert*]            - Pre-generated SSL Certificate file to reference for SSL Support. This is not generated by this module.
#   [*ssl_key*]             - Pre-generated SSL Key file to reference for SSL Support. This is not generated by this module.
#   [*ssl_port*]            - Default IP Port for NGINX to listen with this SSL vHost on. Defaults to TCP 443
#   [*starttls*]            - enable STARTTLS support: (on|off|only)
#   [*protocol*]            - Mail protocol to use: (imap|pop3|smtp)
#   [*auth_http*]           - With this directive you can set the URL to the external HTTP-like server for authorization.
#   [*xclient*]             - wheter to use xclient for smtp (on|off)
#   [*server_name*]         - List of mailhostnames for which this mailhost will respond. Default [$name].
#
# Actions:
#
# Requires:
#
# Sample Usage:
#  nginx::resource::mailhost { 'domain1.example':
#    ensure      => present,
#    auth_http   => 'server2.example/cgi-bin/auth',
#    protocol    => 'smtp',
#    listen_port => 587,
#    ssl_port    => 465,
#    starttls    => 'only',
#    xclient     => 'off',
#    ssl         => true,
#    ssl_cert    => '/tmp/server.crt',
#    ssl_key     => '/tmp/server.pem',
#  }
define nginx::resource::mailhost (
  $listen_port,
  $ensure              = 'present',
  $listen_ip           = '*',
  $listen_options      = undef,
  $ipv6_enable         = false,
  $ipv6_listen_ip      = '::',
  $ipv6_listen_port    = '80',
  $ipv6_listen_options = 'default ipv6only=on',
  $ssl                 = false,
  $ssl_cert            = undef,
  $ssl_key             = undef,
  $ssl_port            = undef,
  $starttls            = 'off',
  $protocol            = undef,
  $auth_http           = undef,
  $xclient             = 'on',
  $server_name         = [$name]
) {

  include nginx::params
  $root_group = $nginx::params::root_group

  File {
    owner => 'root',
    group => $root_group,
    mode  => '0644',
  }

  if !is_integer($listen_port) {
    fail('$listen_port must be an integer.')
  }
  validate_re($ensure, '^(present|absent)$',
    "${ensure} is not supported for ensure. Allowed values are 'present' and 'absent'.")
  validate_string($listen_ip)
  if ($listen_options != undef) {
    validate_string($listen_options)
  }
  validate_bool($ipv6_enable)
  validate_string($ipv6_listen_ip)
  if !is_integer($ipv6_listen_port) {
    fail('$ipv6_listen_port must be an integer.')
  }
  validate_string($ipv6_listen_options)
  validate_bool($ssl)
  if ($ssl_cert != undef) {
    validate_string($ssl_cert)
  }
  if ($ssl_key != undef) {
    validate_string($ssl_key)
  }
  if ($ssl_port != undef) and (!is_integer($ssl_port)) {
    fail('$ssl_port must be an integer.')
  }
  validate_re($starttls, '^(on|only|off)$',
    "${starttls} is not supported for starttls. Allowed values are 'on', 'only' and 'off'.")
  if ($protocol != undef) {
    validate_string($protocol)
  }
  if ($auth_http != undef) {
    validate_string($auth_http)
  }
  validate_string($xclient)
  validate_array($server_name)

  $config_file = "${nginx::config::conf_dir}/conf.mail.d/${name}.conf"

  # Add IPv6 Logic Check - Nginx service will not start if ipv6 is enabled
  # and support does not exist for it in the kernel.
  if ($ipv6_enable and !$::ipaddress6) {
    warning('nginx: IPv6 support is not enabled or configured properly')
  }

  # Check to see if SSL Certificates are properly defined.
  if ($ssl or $starttls == 'on' or $starttls == 'only') {
    if ($ssl_cert == undef) or ($ssl_key == undef) {
      fail('nginx: SSL certificate/key (ssl_cert/ssl_cert) and/or SSL Private must be defined and exist on the target system(s)')
    }
  }

  concat { $config_file:
    owner  => 'root',
    group  => $root_group,
    mode   => '0644',
    notify => Class['nginx::service'],
  }

  if ($listen_port != $ssl_port) {
    concat::fragment { "${name}-header":
      ensure  => present,
      target  => $config_file,
      content => template('nginx/mailhost/mailhost.erb'),
      order   => '001',
    }
  }

  # Create SSL File Stubs if SSL is enabled
  if ($ssl) {
    concat::fragment { "${name}-ssl":
      ensure  => present,
      target  => $config_file,
      content => template('nginx/mailhost/mailhost_ssl.erb'),
      order   => '700',
    }
  }
}
# define: nginx::resource::map
#
# This definition creates a new mapping entry for NGINX
#
# Parameters:
#   [*ensure*]     - Enables or disables the specified location (present|absent)
#   [*default*]    - Sets the resulting value if the source values fails to
#                    match any of the variants.
#   [*string*]     - Source string or variable to provide mapping for
#   [*mappings*]   - Hash of map lookup keys and resultant values
#   [*hostnames*]  - Indicates that source values can be hostnames with a
#                    prefix or suffix mask.

# Actions:
#
# Requires:
#
# Sample Usage:
#
#  nginx::resource::map { 'backend_pool':
#    ensure    => present,
#    hostnames => true,
#    default   => 'ny-pool-1,
#    string    => '$http_host',
#    mappings  => {
#      '*.nyc.example.com' => 'ny-pool-1',
#      '*.sf.example.com'  => 'sf-pool-1',
#    }
#  }
#
# Sample Hiera usage:
#
#  nginx::maps:
#    client_network:
#      ensure: present
#      hostnames: true
#      default: 'ny-pool-1'
#      string: $http_host
#      mappings:
#        '*.nyc.example.com': 'ny-pool-1'
#        '*.sf.example.com': 'sf-pool-1'


define nginx::resource::map (
  $string,
  $mappings,
  $default    = undef,
  $ensure     = 'present',
  $hostnames  = false
) {
  validate_string($string)
  validate_re($string, '^.{2,}$',
    "Invalid string value [${string}]. Expected a minimum of 2 characters.")
  validate_hash($mappings)
  validate_bool($hostnames)
  validate_re($ensure, '^(present|absent)$',
    "Invalid ensure value '${ensure}'. Expected 'present' or 'absent'")
  if ($default != undef) { validate_string($default) }

  include nginx::params
  $root_group = $nginx::params::root_group

  File {
    owner => 'root',
    group => $root_group,
    mode  => '0644',
  }

  file { "${nginx::config::conf_dir}/conf.d/${name}-map.conf":
    ensure  => $ensure ? {
      'absent' => absent,
      default  => 'file',
    },
    content => template('nginx/conf.d/map.erb'),
    notify  => Class['nginx::service'],
  }
}
# define: nginx::resource::upstream
#
# This definition creates a new upstream proxy entry for NGINX
#
# Parameters:
#   [*members*]               - Array of member URIs for NGINX to connect to. Must follow valid NGINX syntax.
#                               If omitted, individual members should be defined with nginx::resource::upstream::member
#   [*ensure*]                - Enables or disables the specified location (present|absent)
#   [*upstream_cfg_prepend*]  - It expects a hash with custom directives to put before anything else inside upstream
#   [*upstream_fail_timeout*] - Set the fail_timeout for the upstream. Default is 10 seconds - As that is what Nginx does normally.
#
# Actions:
#
# Requires:
#
# Sample Usage:
#  nginx::resource::upstream { 'proxypass':
#    ensure  => present,
#    members => [
#      'localhost:3000',
#      'localhost:3001',
#      'localhost:3002',
#    ],
#  }
#
#  Custom config example to use ip_hash, and 20 keepalive connections
#  create a hash with any extra custom config you want.
#  $my_config = {
#    'ip_hash'   => '',
#    'keepalive' => '20',
#  }
#  nginx::resource::upstream { 'proxypass':
#    ensure              => present,
#    members => [
#      'localhost:3000',
#      'localhost:3001',
#      'localhost:3002',
#    ],
#    upstream_cfg_prepend => $my_config,
#  }
define nginx::resource::upstream (
  $members = undef,
  $ensure = 'present',
  $upstream_cfg_prepend = undef,
  $upstream_fail_timeout = '10s',
) {

  if $members != undef {
    validate_array($members)
  }
  validate_re($ensure, '^(present|absent)$',
    "${ensure} is not supported for ensure. Allowed values are 'present' and 'absent'.")
  if ($upstream_cfg_prepend != undef) {
    validate_hash($upstream_cfg_prepend)
  }

  include nginx::params
  $root_group = $nginx::params::root_group

  Concat {
    owner => 'root',
    group => $root_group,
    mode  => '0644',
  }

  concat { "${nginx::config::conf_dir}/conf.d/${name}-upstream.conf":
    ensure  => $ensure ? {
      'absent' => absent,
      'file'   => present,
      default  => present,
    },
    notify  => Class['nginx::service'],
  }

  # Uses: $name, $upstream_cfg_prepend
  concat::fragment { "${name}_upstream_header":
    target  => "${nginx::config::conf_dir}/conf.d/${name}-upstream.conf",
    order   => 10,
    content => template('nginx/conf.d/upstream_header.erb'),
  }

  if $members != undef {
    # Uses: $members, $upstream_fail_timeout
    concat::fragment { "${name}_upstream_members":
      target  => "${nginx::config::conf_dir}/conf.d/${name}-upstream.conf",
      order   => 50,
      content => template('nginx/conf.d/upstream_members.erb'),
    }
  } else {
    # Collect exported members:
    Nginx::Resource::Upstream::Member <<| upstream == $name |>>
  }

  concat::fragment { "${name}_upstream_footer":
    target  => "${nginx::config::conf_dir}/conf.d/${name}-upstream.conf",
    order   => 90,
    content => "}\n",
  }
}
# Define: nginx::resources::upstream::member
#
# Creates an upstream member inside the upstream block. Export this resource
# in all upstream member servers and collect them on the NGINX server.
#
#
# Requirements:
#   Requires storeconfigs on the Puppet Master to export and collect resources
#
#
# Parameters:
#   [*upstream*]                - The name of the upstream resource
#   [*server*]                  - Hostname or IP of the upstream member server
#   [*port*]                    - Port of the listening service on the upstream member
#   [*upstream_fail_timeout*]   - Set the fail_timeout for the upstream. Default is 10 seconds
#
#
# Examples:
#
#   Exporting the resource on a upstream member server:
#
#   @@nginx::resource::upstream::member { $::fqdn:
#     upstream  => 'proxypass',
#     server    => $::ipaddress,
#     port      => '3000',
#   }
#
#
#   Collecting the resource on the NGINX server:
#
#   nginx::resource::upstream { 'proxypass':
#     ensure    => present,
#   }
#
define nginx::resource::upstream::member (
  $upstream,
  $server,
  $port                   = '80',
  $upstream_fail_timeout  = '10s',
) {

  # Uses: $server, $port, $upstream_fail_timeout
  concat::fragment { "${upstream}_upstream_member_${name}":
    target  => "${nginx::config::conf_dir}/conf.d/${upstream}-upstream.conf",
    order   => 40,
    content => template('nginx/conf.d/upstream_member.erb'),
  }
}
# define: nginx::resource::vhost
#
# This definition creates a virtual host
#
# Parameters:
#   [*ensure*]              - Enables or disables the specified vhost
#     (present|absent)
#   [*listen_ip*]           - Default IP Address for NGINX to listen with this
#     vHost on. Defaults to all interfaces (*)
#   [*listen_port*]         - Default IP Port for NGINX to listen with this
#     vHost on. Defaults to TCP 80
#   [*listen_options*]      - Extra options for listen directive like
#     'default' to catchall. Undef by default.
#   [*location_allow*]      - Array: Locations to allow connections from.
#   [*location_deny*]       - Array: Locations to deny connections from.
#   [*ipv6_enable*]         - BOOL value to enable/disable IPv6 support
#     (false|true). Module will check to see if IPv6 support exists on your
#     system before enabling.
#   [*ipv6_listen_ip*]      - Default IPv6 Address for NGINX to listen with
#     this vHost on. Defaults to all interfaces (::)
#   [*ipv6_listen_port*]    - Default IPv6 Port for NGINX to listen with this
#     vHost on. Defaults to TCP 80
#   [*ipv6_listen_options*] - Extra options for listen directive like 'default'
#     to catchall. Template will allways add ipv6only=on. While issue
#     jfryman/puppet-nginx#30 is discussed, default value is 'default'.
#   [*add_header*]          - Hash: Adds headers to the HTTP response when
#     response code is equal to 200, 204, 301, 302 or 304.
#   [*index_files*]         - Default index files for NGINX to read when
#     traversing a directory
#   [*autoindex*]           - Set it on 'on' or 'off 'to activate/deactivate
#                             autoindex directory listing. Undef by default.
#   [*proxy*]               - Proxy server(s) for the root location to connect
#     to.  Accepts a single value, can be used in conjunction with
#     nginx::resource::upstream
#   [*proxy_read_timeout*]  - Override the default the proxy read timeout value
#     of 90 seconds
#   [*proxy_redirect*]      - Override the default proxy_redirect value of off.
#   [*resolver*]            - Array: Configures name servers used to resolve
#     names of upstream servers into addresses.
#   [*fastcgi*]             - location of fastcgi (host:port)
#   [*fastcgi_params*]      - optional alternative fastcgi_params file to use
#   [*fastcgi_script*]      - optional SCRIPT_FILE parameter
#   [*ssl*]                 - Indicates whether to setup SSL bindings for this
#     vhost.
#   [*ssl_cert*]            - Pre-generated SSL Certificate file to reference
#     for SSL Support. This is not generated by this module.
#   [*ssl_dhparam*]         - This directive specifies a file containing
#     Diffie-Hellman key agreement protocol cryptographic parameters, in PEM
#     format, utilized for exchanging session keys between server and client.
#   [*ssl_key*]             - Pre-generated SSL Key file to reference for SSL
#     Support. This is not generated by this module.
#   [*ssl_port*]            - Default IP Port for NGINX to listen with this SSL
#     vHost on. Defaults to TCP 443
#   [*ssl_protocols*]       - SSL protocols enabled. Defaults to 'SSLv3 TLSv1
#     TLSv1.1 TLSv1.2'.
#   [*ssl_ciphers*]         - SSL ciphers enabled. Defaults to
#     'HIGH:!aNULL:!MD5'.
#   [*ssl_stapling*]        - Bool: Enables or disables stapling of OCSP
#     responses by the server. Defaults to false.
#   [*ssl_stapling_file*]   - String: When set, the stapled OCSP response
#     will be taken from the specified file instead of querying the OCSP
#     responder specified in the server certificate.
#   [*ssl_stapling_responder*] - String: Overrides the URL of the OCSP
#     responder specified in the Authority Information Access certificate
#     extension.
#   [*ssl_stapling_verify*] - Bool: Enables or disables verification of
#     OCSP responses by the server. Defaults to false.
#   [*ssl_trusted_cert*]    - String: Specifies a file with trusted CA
#     certificates in the PEM format used to verify client certificates and
#     OCSP responses if ssl_stapling is enabled.
#   [*spdy*]                - Toggles SPDY protocol.
#   [*server_name*]         - List of vhostnames for which this vhost will
#     respond. Default [$name].
#   [*www_root*]            - Specifies the location on disk for files to be
#     read from. Cannot be set in conjunction with $proxy
#   [*rewrite_www_to_non_www*]  - Adds a server directive and rewrite rule to
#     rewrite www.domain.com to domain.com in order to avoid duplicate
#     content (SEO);
#   [*try_files*]               - Specifies the locations for files to be
#     checked as an array. Cannot be used in conjuction with $proxy.
#   [*proxy_cache*]             - This directive sets name of zone for caching.
#     The same zone can be used in multiple places.
#   [*proxy_cache_valid*]       - This directive sets the time for caching
#     different replies.
#   [*proxy_method*]            - If defined, overrides the HTTP method of the
#     request to be passed to the backend.
#   [*proxy_set_body*]          - If defined, sets the body passed to the backend.
#   [*auth_basic*]              - This directive includes testing name and
#      password with HTTP Basic Authentication.
#   [*auth_basic_user_file*]    - This directive sets the htpasswd filename for
#     the authentication realm.
#   [*client_max_body_size*]    - This directive sets client_max_body_size.
#   [*client_body_timeout*]     - Sets how long the server will wait for a
#      client body. Default is 60s
#   [*client_header_timeout*]     - Sets how long the server will wait for a
#      client header. Default is 60s
#   [*raw_prepend*]            - A single string, or an array of strings to
#     prepend to the server directive (after cfg prepend directives). NOTE:
#     YOU are responsible for a semicolon on each line that requires one.
#   [*raw_append*]             - A single string, or an array of strings to
#     append to the server directive (after cfg append directives). NOTE:
#     YOU are responsible for a semicolon on each line that requires one.
#   [*location_raw_prepend*]          - A single string, or an array of strings
#     to prepend to the location directive (after custom_cfg directives). NOTE:
#     YOU are responsible for a semicolon on each line that requires one.
#   [*location_raw_append*]           - A single string, or an array of strings
#     to append to the location directive (after custom_cfg directives). NOTE:
#     YOU are responsible for a semicolon on each line that requires one.
#   [*vhost_cfg_append*]        - It expects a hash with custom directives to
#     put after everything else inside vhost
#   [*vhost_cfg_prepend*]       - It expects a hash with custom directives to
#     put before everything else inside vhost
#   [*vhost_cfg_ssl_append*]        - It expects a hash with custom directives to
#     put after everything else inside vhost ssl
#   [*vhost_cfg_ssl_prepend*]       - It expects a hash with custom directives to
#     put before everything else inside vhost ssl
#   [*rewrite_to_https*]        - Adds a server directive and rewrite rule to
#     rewrite to ssl
#   [*include_files*]           - Adds include files to vhost
#   [*access_log*]              - Where to write access log. May add additional
#     options like log format to the end.
#   [*error_log*]               - Where to write error log. May add additional
#     options like error level to the end.
#   [*passenger_cgi_param*]     - Allows one to define additional CGI environment
#     variables to pass to the backend application
#   [*log_by_lua*]              - Run the Lua source code inlined as the
#     <lua-script-str> at the log request processing phase.
#     This does not replace the current access logs, but runs after.
#   [*log_by_lua_file*]         - Equivalent to log_by_lua, except that the file
#     specified by <path-to-lua-script-file> contains the Lua code, or, as from
#     the v0.5.0rc32 release, the Lua/LuaJIT bytecode to be executed.
#   [*gzip_types*]              - Defines gzip_types, nginx default is text/html
#   [*owner*]                   - Defines owner of the .conf file
#   [*group*]                   - Defines group of the .conf file
#   [*mode*]                    - Defines mode of the .conf file
# Actions:
#
# Requires:
#
# Sample Usage:
#  nginx::resource::vhost { 'test2.local':
#    ensure   => present,
#    www_root => '/var/www/nginx-default',
#    ssl      => true,
#    ssl_cert => '/tmp/server.crt',
#    ssl_key  => '/tmp/server.pem',
#  }
define nginx::resource::vhost (
  $ensure                 = 'present',
  $listen_ip              = '*',
  $listen_port            = '80',
  $listen_options         = undef,
  $location_allow         = [],
  $location_deny          = [],
  $ipv6_enable            = false,
  $ipv6_listen_ip         = '::',
  $ipv6_listen_port       = '80',
  $ipv6_listen_options    = 'default ipv6only=on',
  $add_header             = undef,
  $ssl                    = false,
  $ssl_listen_option      = true,
  $ssl_cert               = undef,
  $ssl_dhparam            = undef,
  $ssl_key                = undef,
  $ssl_port               = '443',
  $ssl_protocols          = 'SSLv3 TLSv1 TLSv1.1 TLSv1.2',
  $ssl_ciphers            = 'HIGH:!aNULL:!MD5',
  $ssl_cache              = 'shared:SSL:10m',
  $ssl_stapling           = false,
  $ssl_stapling_file      = undef,
  $ssl_stapling_responder = undef,
  $ssl_stapling_verify    = false,
  $ssl_trusted_cert       = undef,
  $spdy                   = $nginx::config::spdy,
  $proxy                  = undef,
  $proxy_redirect         = undef,
  $proxy_read_timeout     = $nginx::config::proxy_read_timeout,
  $proxy_connect_timeout  = $nginx::config::proxy_connect_timeout,
  $proxy_set_header       = [],
  $proxy_cache            = false,
  $proxy_cache_valid      = false,
  $proxy_method           = undef,
  $proxy_set_body         = undef,
  $resolver               = [],
  $fastcgi                = undef,
  $fastcgi_params         = "${nginx::config::conf_dir}/fastcgi_params",
  $fastcgi_script         = undef,
  $index_files            = [
    'index.html',
    'index.htm',
    'index.php'],
  $autoindex              = undef,
  $server_name            = [$name],
  $www_root               = undef,
  $rewrite_www_to_non_www = false,
  $rewrite_to_https       = undef,
  $location_custom_cfg    = undef,
  $location_cfg_prepend   = undef,
  $location_cfg_append    = undef,
  $location_custom_cfg_prepend  = undef,
  $location_custom_cfg_append   = undef,
  $try_files              = undef,
  $auth_basic             = undef,
  $auth_basic_user_file   = undef,
  $client_body_timeout    = undef,
  $client_header_timeout  = undef,
  $client_max_body_size   = undef,
  $raw_prepend            = undef,
  $raw_append             = undef,
  $location_raw_prepend   = undef,
  $location_raw_append    = undef,
  $vhost_cfg_prepend      = undef,
  $vhost_cfg_append       = undef,
  $vhost_cfg_ssl_prepend      = undef,
  $vhost_cfg_ssl_append       = undef,
  $include_files          = undef,
  $access_log             = undef,
  $error_log              = undef,
  $format_log             = undef,
  $passenger_cgi_param    = undef,
  $log_by_lua             = undef,
  $log_by_lua_file        = undef,
  $use_default_location   = true,
  $rewrite_rules          = [],
  $string_mappings        = {},
  $geo_mappings           = {},
  $gzip_types             = undef,
  $owner                  = $nginx::config::global_owner,
  $group                  = $nginx::config::global_group,
  $mode                   = $nginx::config::global_mode,
) {

  validate_re($ensure, '^(present|absent)$',
    "${ensure} is not supported for ensure. Allowed values are 'present' and 'absent'.")
  validate_string($listen_ip)
  if !is_integer($listen_port) {
    fail('$listen_port must be an integer.')
  }
  if ($listen_options != undef) {
    validate_string($listen_options)
  }
  validate_array($location_allow)
  validate_array($location_deny)
  validate_bool($ipv6_enable)
  validate_string($ipv6_listen_ip)
  if !is_integer($ipv6_listen_port) {
    fail('$ipv6_listen_port must be an integer.')
  }
  validate_string($ipv6_listen_options)
  if ($add_header != undef) {
    validate_hash($add_header)
  }
  validate_bool($ssl)
  if ($ssl_cert != undef) {
    validate_string($ssl_cert)
  }
  validate_bool($ssl_listen_option)
  if ($ssl_dhparam != undef) {
    validate_string($ssl_dhparam)
  }
  if ($ssl_key != undef) {
    validate_string($ssl_key)
  }
  if !is_integer($ssl_port) {
    fail('$ssl_port must be an integer.')
  }
  validate_string($ssl_protocols)
  validate_string($ssl_ciphers)
  validate_string($ssl_cache)
  validate_bool($ssl_stapling)
  if ($ssl_stapling_file != undef) {
    validate_string($ssl_stapling_file)
  }
  if ($ssl_stapling_responder != undef) {
    validate_string($ssl_stapling_responder)
  }
  validate_bool($ssl_stapling_verify)
  if ($ssl_trusted_cert != undef) {
    validate_string($ssl_trusted_cert)
  }
  validate_string($spdy)
  if ($proxy != undef) {
    validate_string($proxy)
  }
  validate_string($proxy_read_timeout)
  validate_string($proxy_redirect)
  validate_array($proxy_set_header)
  if ($proxy_cache != false) {
    validate_string($proxy_cache)
  }
  if ($proxy_cache_valid != false) {
    validate_string($proxy_cache_valid)
  }
  if ($proxy_method != undef) {
    validate_string($proxy_method)
  }
  if ($proxy_set_body != undef) {
    validate_string($proxy_set_body)
  }
  validate_array($resolver)
  if ($fastcgi != undef) {
    validate_string($fastcgi)
  }
  validate_string($fastcgi_params)
  if ($fastcgi_script != undef) {
    validate_string($fastcgi_script)
  }
  validate_array($index_files)
  if ($autoindex != undef) {
    validate_string($autoindex)
  }
  validate_array($server_name)
  if ($www_root != undef) {
    validate_string($www_root)
  }
  validate_bool($rewrite_www_to_non_www)
  if ($rewrite_to_https != undef) {
    validate_bool($rewrite_to_https)
  }
  if ($raw_prepend != undef) {
    if (is_array($raw_prepend)) {
      validate_array($raw_prepend)
    } else {
      validate_string($raw_prepend)
    }
  }
  if ($raw_append != undef) {
    if (is_array($raw_append)) {
      validate_array($raw_append)
    } else {
      validate_string($raw_append)
    }
  }
  if ($location_raw_prepend != undef) {
    if (is_array($location_raw_prepend)) {
      validate_array($location_raw_prepend)
    } else {
      validate_string($location_raw_prepend)
    }
  }
  if ($location_raw_append != undef) {
    if (is_array($location_raw_append)) {
      validate_array($location_raw_append)
    } else {
      validate_string($location_raw_append)
    }
  }
  if ($location_custom_cfg != undef) {
    validate_hash($location_custom_cfg)
  }
  if ($location_cfg_prepend != undef) {
    validate_hash($location_cfg_prepend)
  }
  if ($location_cfg_append != undef) {
    validate_hash($location_cfg_append)
  }
  if ($try_files != undef) {
    validate_array($try_files)
  }
  if ($auth_basic != undef) {
    validate_string($auth_basic)
  }
  if ($auth_basic_user_file != undef) {
    validate_string($auth_basic_user_file)
  }
  if ($vhost_cfg_prepend != undef) {
    validate_hash($vhost_cfg_prepend)
  }
  if ($vhost_cfg_append != undef) {
    validate_hash($vhost_cfg_append)
  }
  if ($vhost_cfg_ssl_prepend != undef) {
    validate_hash($vhost_cfg_ssl_prepend)
  }
  if ($vhost_cfg_ssl_append != undef) {
    validate_hash($vhost_cfg_ssl_append)
  }
  if ($include_files != undef) {
    validate_array($include_files)
  }
  if ($access_log != undef) {
    validate_string($access_log)
  }
  if ($error_log != undef) {
    validate_string($error_log)
  }
  if ($passenger_cgi_param != undef) {
    validate_hash($passenger_cgi_param)
  }
  if ($log_by_lua != undef) {
    validate_string($log_by_lua)
  }
  if ($log_by_lua_file != undef) {
    validate_string($log_by_lua_file)
  }
  if ($client_body_timeout != undef) {
    validate_string($client_body_timeout)
  }
  if ($client_header_timeout != undef) {
    validate_string($client_header_timeout)
  }
  if ($gzip_types != undef) {
    validate_string($gzip_types)
  }
  validate_bool($use_default_location)
  validate_array($rewrite_rules)
  validate_hash($string_mappings)
  validate_hash($geo_mappings)

  validate_string($owner)
  validate_string($group)
  validate_re($mode, '^\d{4}$',
    "${mode} is not valid. It should be 4 digits (0644 by default).")

  # Variables
  $vhost_dir = "${nginx::config::conf_dir}/sites-available"
  $vhost_enable_dir = "${nginx::config::conf_dir}/sites-enabled"
  $vhost_symlink_ensure = $ensure ? {
    'absent' => absent,
    default  => 'link',
  }

  $name_sanitized = regsubst($name, ' ', '_', 'G')
  $config_file = "${vhost_dir}/${name_sanitized}.conf"

  File {
    ensure => $ensure ? {
      'absent' => absent,
      default  => 'file',
    },
    notify => Class['nginx::service'],
    owner  => $owner,
    group  => $group,
    mode   => $mode,
  }

  # Add IPv6 Logic Check - Nginx service will not start if ipv6 is enabled
  # and support does not exist for it in the kernel.
  if ($ipv6_enable == true) and (!$ipaddress6) {
    warning('nginx: IPv6 support is not enabled or configured properly')
  }

  # Check to see if SSL Certificates are properly defined.
  if ($ssl == true) {
    if ($ssl_cert == undef) or ($ssl_key == undef) {
      fail('nginx: SSL certificate/key (ssl_cert/ssl_key) and/or SSL Private must be defined and exist on the target system(s)')
    }
  }


  # This was a lot to add up in parameter list so add it down here
  # Also opted to add more logic here and keep template cleaner which
  # unfortunately means resorting to the $varname_real thing
  $access_log_tmp = $access_log ? {
    undef   => "${nginx::config::logdir}/${name_sanitized}.access.log",
    default => $access_log,
  }

  $access_log_real = $format_log ? {
    undef   => $access_log_tmp,
    default => "${access_log_tmp} ${format_log}",
  }

  $error_log_real = $error_log ? {
    undef   => "${nginx::config::logdir}/${name_sanitized}.error.log",
    default => $error_log,
  }

  concat { $config_file:
    owner  => $owner,
    group  => $group,
    mode   => $mode,
    notify => Class['nginx::service'],
  }

  $ssl_only = ($ssl == true) and ($ssl_port == $listen_port)

  if $use_default_location == true {
    # Create the default location reference for the vHost
    nginx::resource::location {"${name_sanitized}-default":
      ensure                => $ensure,
      vhost                 => $name_sanitized,
      ssl                   => $ssl,
      ssl_only              => $ssl_only,
      location              => '/',
      location_allow        => $location_allow,
      location_deny         => $location_deny,
      proxy                 => $proxy,
      proxy_redirect        => $proxy_redirect,
      proxy_read_timeout    => $proxy_read_timeout,
      proxy_connect_timeout => $proxy_connect_timeout,
      proxy_cache           => $proxy_cache,
      proxy_cache_valid     => $proxy_cache_valid,
      proxy_method          => $proxy_method,
      proxy_set_body        => $proxy_set_body,
      fastcgi               => $fastcgi,
      fastcgi_params        => $fastcgi_params,
      fastcgi_script        => $fastcgi_script,
      try_files             => $try_files,
      www_root              => $www_root,
      autoindex             => $autoindex,
      index_files           => [],
      location_custom_cfg   => $location_custom_cfg,
      notify                => Class['nginx::service'],
      rewrite_rules         => $rewrite_rules,
      raw_prepend           => $location_raw_prepend,
      raw_append            => $location_raw_append
    }
    $root = undef
  } else {
    $root = $www_root
  }

  # Support location_cfg_prepend and location_cfg_append on default location created by vhost
  if $location_cfg_prepend {
    Nginx::Resource::Location["${name_sanitized}-default"] {
      location_cfg_prepend => $location_cfg_prepend }
  }

  if $location_cfg_append {
    Nginx::Resource::Location["${name_sanitized}-default"] {
      location_cfg_append => $location_cfg_append }
  }

  if $location_custom_cfg_prepend {
    Nginx::Resource::Location["${name_sanitized}-default"] {
      location_custom_cfg_prepend => $location_custom_cfg_prepend }
  }

  if $location_custom_cfg_append {
    Nginx::Resource::Location["${name_sanitized}-default"] {
      location_custom_cfg_append => $location_custom_cfg_append }
  }

  if $fastcgi != undef and !defined(File[$fastcgi_params]) {
    file { $fastcgi_params:
      ensure  => present,
      mode    => '0770',
      content => template('nginx/vhost/fastcgi_params.erb'),
    }
  }

  if ($listen_port != $ssl_port) {
    concat::fragment { "${name_sanitized}-header":
      ensure  => present,
      target  => $config_file,
      content => template('nginx/vhost/vhost_header.erb'),
      order   => '001',
    }
  }

  # Create a proper file close stub.
  if ($listen_port != $ssl_port) {
    concat::fragment { "${name_sanitized}-footer":
      ensure  => present,
      target  => $config_file,
      content => template('nginx/vhost/vhost_footer.erb'),
      order   => '699',
    }
  }

  # Create SSL File Stubs if SSL is enabled
  if ($ssl == true) {
    # Access and error logs are named differently in ssl template

    # This was a lot to add up in parameter list so add it down here
    # Also opted to add more logic here and keep template cleaner which
    # unfortunately means resorting to the $varname_real thing
    $ssl_access_log_tmp = $access_log ? {
      undef   => "${nginx::config::logdir}/ssl-${name_sanitized}.access.log",
      default => $access_log,
    }

    $ssl_access_log_real = $format_log ? {
      undef   => $ssl_access_log_tmp,
      default => "${ssl_access_log_tmp} ${format_log}",
    }

    $ssl_error_log_real = $error_log ? {
      undef   => "${nginx::config::logdir}/ssl-${name_sanitized}.error.log",
      default => $error_log,
    }

    concat::fragment { "${name_sanitized}-ssl-header":
      target  => $config_file,
      content => template('nginx/vhost/vhost_ssl_header.erb'),
      order   => '700',
    }
    concat::fragment { "${name_sanitized}-ssl-footer":
      target  => $config_file,
      content => template('nginx/vhost/vhost_ssl_footer.erb'),
      order   => '999',
    }

    #Generate ssl key/cert with provided file-locations
    $cert = regsubst($name,' ','_', 'G')

    # Check if the file has been defined before creating the file to
    # avoid the error when using wildcard cert on the multiple vhosts
    ensure_resource('file', "${nginx::config::conf_dir}/${cert}.crt", {
      owner  => $nginx::config::daemon_user,
      mode   => '0444',
      source => $ssl_cert,
    })
    ensure_resource('file', "${nginx::config::conf_dir}/${cert}.key", {
      owner  => $nginx::config::daemon_user,
      mode   => '0440',
      source => $ssl_key,
    })
    if ($ssl_dhparam != undef) {
      ensure_resource('file', "${nginx::config::conf_dir}/${cert}.dh.pem", {
        owner  => $nginx::config::daemon_user,
        mode   => '0440',
        source => $ssl_dhparam,
      })
    }
    if ($ssl_stapling_file != undef) {
      ensure_resource('file', "${nginx::config::conf_dir}/${cert}.ocsp.resp", {
        owner  => $nginx::config::daemon_user,
        mode   => '0440',
        source => $ssl_stapling_file,
      })
    }
    if ($ssl_trusted_cert != undef) {
      ensure_resource('file', "${nginx::config::conf_dir}/${cert}.trusted.crt", {
        owner  => $nginx::config::daemon_user,
        mode   => '0440',
        source => $ssl_trusted_cert,
      })
    }
  }

  file{ "${name_sanitized}.conf symlink":
    ensure  => $vhost_symlink_ensure,
    path    => "${vhost_enable_dir}/${name_sanitized}.conf",
    target  => $config_file,
    require => Concat[$config_file],
    notify  => Service['nginx'],
  }

  create_resources('nginx::resource::map', $string_mappings)
  create_resources('nginx::resource::geo', $geo_mappings)
}
# Class: nginx::service
#
# This module manages NGINX service management and vhost rebuild
#
# Parameters:
#
# There are no default parameters for this class.
#
# Actions:
#
# Requires:
#
# Sample Usage:
#
# This class file is not called directly
class nginx::service(
  $configtest_enable = $nginx::configtest_enable,
  $service_restart   = $nginx::service_restart,
  $service_ensure    = $nginx::service_ensure,
) {

  $service_enable = $service_ensure ? {
    running => true,
    absent => false,
    stopped => false,
    'undef' => undef,
    default => true,
  }

  if $service_ensure == 'undef' {
    $service_ensure_real = undef
  } else {
    $service_ensure_real = $service_ensure
  }

  service { 'nginx':
    ensure     => $service_ensure_real,
    enable     => $service_enable,
    hasstatus  => true,
    hasrestart => true,
  }
  if $configtest_enable == true {
    Service['nginx'] {
      restart => $service_restart,
    }
  }
}
require 'spec_helper'
describe 'nginx::config' do

  describe 'with defaults' do
    [
      { :osfamily => 'debian', :operatingsystem => 'debian', },
      { :osfamily => 'debian', :operatingsystem => 'ubuntu', },
      { :osfamily => 'redhat', :operatingsystem => 'fedora', },
      { :osfamily => 'redhat', :operatingsystem => 'rhel', },
      { :osfamily => 'redhat', :operatingsystem => 'redhat', },
      { :osfamily => 'redhat', :operatingsystem => 'centos', },
      { :osfamily => 'redhat', :operatingsystem => 'scientific', },
      { :osfamily => 'redhat', :operatingsystem => 'amazon', },
      { :osfamily => 'suse',   :operatingsystem => 'suse', },
      { :osfamily => 'suse',   :operatingsystem => 'opensuse', },
      { :osfamily => 'gentoo', :operatingsystem => 'gentoo', },
      { :osfamily => 'linux',  :operatingsystem => 'gentoo', },
    ].each do |facts|

      context "when osfamily/operatingsystem is #{facts[:osfamily]}/#{facts[:operatingsystem]}" do

        let :facts do
          {
            :osfamily        => facts[:osfamily],
            :operatingsystem => facts[:operatingsystem],
          }
        end

        it { should contain_class("nginx::params") }

        it { should contain_file("/etc/nginx").only_with(
          :path   => "/etc/nginx",
          :ensure => 'directory',
          :owner => 'root',
          :group => 'root',
          :mode => '0644'
        )}
        it { should contain_file("/etc/nginx/conf.d").only_with(
          :path   => '/etc/nginx/conf.d',
          :ensure => 'directory',
          :owner => 'root',
          :group => 'root',
          :mode => '0644'
        )}
        it { should contain_file("/etc/nginx/conf.mail.d").only_with(
          :path   => '/etc/nginx/conf.mail.d',
          :ensure => 'directory',
          :owner => 'root',
          :group => 'root',
          :mode => '0644'
        )}
        it { should contain_file("/etc/nginx/conf.d/vhost_autogen.conf").with_ensure('absent') }
        it { should contain_file("/etc/nginx/conf.mail.d/vhost_autogen.conf").with_ensure('absent') }
        it { should contain_file("/var/nginx").with(
          :ensure => 'directory',
          :owner => 'root',
          :group => 'root',
          :mode => '0644'
        )}
        it { should contain_file("/var/nginx/client_body_temp").with(
          :ensure => 'directory',
          :group => 'root',
          :mode => '0644'
        )}
        it { should contain_file("/var/nginx/proxy_temp").with(
          :ensure => 'directory',
          :group => 'root',
          :mode => '0644'
        )}
        it { should contain_file('/etc/nginx/sites-enabled/default').with_ensure('absent') }
        it { should contain_file("/etc/nginx/nginx.conf").with(
          :ensure => 'file',
          :owner => 'root',
          :group => 'root',
          :mode => '0644'
        )}
        it { should contain_file("/etc/nginx/conf.d/proxy.conf").with(
          :ensure => 'file',
          :owner => 'root',
          :group => 'root',
          :mode => '0644'
        )}
        it { should contain_file("/tmp/nginx.d").with(
          :ensure => 'absent',
          :purge => true,
          :recurse => true
        )}
        it { should contain_file("/tmp/nginx.mail.d").with(
          :ensure => 'absent',
          :purge => true,
          :recurse => true
        )}
      end
    end
  end

  describe 'with defaults' do
    [
      { :osfamily => 'debian', :operatingsystem => 'debian', },
      { :osfamily => 'debian', :operatingsystem => 'ubuntu', },
    ].each do |facts|

      context "when osfamily/operatingsystem is #{facts[:osfamily]}/#{facts[:operatingsystem]}" do

        let :facts do
          {
            :osfamily        => facts[:osfamily],
            :operatingsystem => facts[:operatingsystem],
          }
        end
        it { should contain_file("/var/nginx/client_body_temp").with(:owner => 'www-data')}
        it { should contain_file("/var/nginx/proxy_temp").with(:owner => 'www-data')}
        it { should contain_file("/etc/nginx/nginx.conf").with_content %r{^user www-data;}}
      end
    end
  end

  describe 'with defaults' do
    [
      { :osfamily => 'redhat', :operatingsystem => 'fedora', },
      { :osfamily => 'redhat', :operatingsystem => 'rhel', },
      { :osfamily => 'redhat', :operatingsystem => 'redhat', },
      { :osfamily => 'redhat', :operatingsystem => 'centos', },
      { :osfamily => 'redhat', :operatingsystem => 'scientific', },
      { :osfamily => 'redhat', :operatingsystem => 'amazon', },
      { :osfamily => 'suse',   :operatingsystem => 'suse', },
      { :osfamily => 'suse',   :operatingsystem => 'opensuse', },
      { :osfamily => 'gentoo', :operatingsystem => 'gentoo', },
      { :osfamily => 'linux',  :operatingsystem => 'gentoo', },
    ].each do |facts|

      context "when osfamily/operatingsystem is #{facts[:osfamily]}/#{facts[:operatingsystem]}" do

        let :facts do
          {
            :osfamily        => facts[:osfamily],
            :operatingsystem => facts[:operatingsystem],
          }
        end
        it { should contain_file("/var/nginx/client_body_temp").with(:owner => 'nginx')}
        it { should contain_file("/var/nginx/proxy_temp").with(:owner => 'nginx')}
        it { should contain_file("/etc/nginx/nginx.conf").with_content %r{^user nginx;}}
      end
    end
  end

  describe 'os-independent items' do

    let :facts do
      {
        :osfamily        => 'debian',
        :operatingsystem => 'debian',
      }
    end

    describe "nginx.conf template content" do
      [
        {
          :title => 'should set worker_processes',
          :attr  => 'worker_processes',
          :value => '4',
          :match => 'worker_processes 4;',
        },
        {
          :title => 'should set worker_rlimit_nofile',
          :attr  => 'worker_rlimit_nofile',
          :value => '10000',
          :match => 'worker_rlimit_nofile 10000;',
        },
        {
          :title => 'should set error_log',
          :attr  => 'nginx_error_log',
          :value => '/path/to/error.log',
          :match => 'error_log  /path/to/error.log;',
        },
        {
          :title => 'should set worker_connections',
          :attr  => 'worker_connections',
          :value => '100',
          :match => '  worker_connections 100;',
        },
        {
          :title => 'should set access_log',
          :attr  => 'http_access_log',
          :value => '/path/to/access.log',
          :match => '  access_log  /path/to/access.log;',
        },
        {
          :title => 'should set server_tokens',
          :attr  => 'server_tokens',
          :value => 'on',
          :match => '  server_tokens on;',
        },
        {
          :title => 'should set proxy_cache_path',
          :attr  => 'proxy_cache_path',
          :value => '/path/to/proxy.cache',
          :match => '  proxy_cache_path    /path/to/proxy.cache levels=1 keys_zone=d2:100m max_size=500m inactive=20m;',
        },
        {
          :title    => 'should not set proxy_cache_path',
          :attr     => 'proxy_cache_path',
          :value    => false,
          :notmatch => /  proxy_cache_path    \/path\/to\/proxy\.cache levels=1 keys_zone=d2:100m max_size=500m inactive=20m;/,
        },
        {
          :title => 'should contain ordered appended directives from hash',
          :attr  => 'http_cfg_append',
          :value => { 'test1' => 'test value 1', 'test2' => 'test value 2', 'allow' => 'test value 3' },
          :match => [
            '  allow test value 3;',
            '  test1 test value 1;',
            '  test2 test value 2;',
          ],
        },
        {
          :title => 'should contain duplicate appended directives from list of hashes',
          :attr  => 'http_cfg_append',
          :value => [[ 'allow', 'test value 1'], ['allow', 'test value 2' ]],
          :match => [
            '  allow test value 1;',
            '  allow test value 2;',
          ],
        },
        {
            :title => 'should set pid',
            :attr  => 'pid',
            :value => '/path/to/pid',
            :match => 'pid        /path/to/pid;',
        },
        {
            :title => 'should set tcp_nodelay',
            :attr  => 'http_tcp_nodelay',
            :value => 'on',
            :match => '  tcp_nodelay        on;',
        },
        {
            :title => 'should set tcp_nopush',
            :attr  => 'http_tcp_nopush',
            :value => 'on',
            :match => '  tcp_nopush on;',
        },
        {
            :title => 'should set keepalive_timeout',
            :attr  => 'keepalive_timeout',
            :value => '123',
            :match => '  keepalive_timeout  123;',
        },
      ].each do |param|
        context "when #{param[:attr]} is #{param[:value]}" do
          let :params do { param[:attr].to_sym => param[:value] } end

          it { should contain_file("/etc/nginx/nginx.conf").with_mode('0644') }
          it param[:title] do
            verify_contents(subject, "/etc/nginx/nginx.conf", Array(param[:match]))
            Array(param[:notmatch]).each do |item|
              should contain_file("/etc/nginx/nginx.conf").without_content(item)
            end
          end
        end
      end
    end

    describe "proxy.conf template content" do
      [
        {
          :title => 'should set proxy_buffers',
          :attr  => 'proxy_buffers',
          :value => '50 5k',
          :match => 'proxy_buffers           50 5k;',
        },
        {
          :title => 'should set proxy_buffer_size',
          :attr  => 'proxy_buffer_size',
          :value => '2k',
          :match => 'proxy_buffer_size       2k;',
        },
        {
          :title => 'should set proxy_http_version',
          :attr  => 'proxy_http_version',
          :value => '1.1',
          :match => 'proxy_http_version      1.1;',
        },
        {
          :title => 'should contain ordered appended directives',
          :attr  => 'proxy_set_header',
          :value => ['header1','header2'],
          :match => [
            'proxy_set_header        header1;',
            'proxy_set_header        header2;',
          ],
        },
        {
            :title    => 'should set client_body_temp_path',
            :attr     => 'client_body_temp_path',
            :value    => '/path/to/body_temp',
            :match => 'client_body_temp_path   /path/to/body_temp;',
        },
        {
            :title    => 'should set proxy_temp_path',
            :attr     => 'proxy_temp_path',
            :value    => '/path/to/proxy_temp',
            :match => 'proxy_temp_path         /path/to/proxy_temp;',
        },
      ].each do |param|
        context "when #{param[:attr]} is #{param[:value]}" do
          let :params do { param[:attr].to_sym => param[:value] } end

          it { should contain_file("/etc/nginx/conf.d/proxy.conf").with_mode('0644') }
          it param[:title] do
            verify_contents(subject, "/etc/nginx/conf.d/proxy.conf", Array(param[:match]))
            Array(param[:notmatch]).each do |item|
              should contain_file("/etc/nginx/conf.d/proxy.conf").without_content(item)
            end
          end
        end
      end
    end

    context "when confd_purge true" do
      let(:params) {{:confd_purge => true}}
      it { should contain_file('/etc/nginx/conf.d').with(
        :purge => true,
        :recurse => true
      )}
    end

    context "when confd_purge false" do
      let(:params) {{:confd_purge => false}}
      it { should contain_file('/etc/nginx/conf.d').without([
        'ignore',
        'purge',
        'recurse'
      ])}
    end

    context "when vhost_purge true" do
      let(:params) {{:vhost_purge => true}}
      it { should contain_file('/etc/nginx/sites-available').with(
        :purge => true,
        :recurse => true
      )}
      it { should contain_file('/etc/nginx/sites-enabled').with(
        :purge => true,
        :recurse => true
      )}
    end

    context "when vhost_purge false" do
      let(:params) {{:vhost_purge => false}}
      it { should contain_file('/etc/nginx/sites-available').without([
        'ignore',
        'purge',
        'recurse'
      ])}
      it { should contain_file('/etc/nginx/sites-enabled').without([
        'ignore',
        'purge',
        'recurse'
      ])}
    end
  end
end
require 'spec_helper'

describe 'nginx' do
  let :params do
    {
      :nginx_upstreams => { 'upstream1' => { 'members' => ['localhost:3000']} },
      :nginx_vhosts    => { 'test2.local' => { 'www_root' => '/' } },
      :nginx_locations => { 'test2.local' => { 'vhost' => 'test2.local', 'www_root' => '/'} },
      :nginx_mailhosts => { 'smtp.test2.local' => { 'auth_http' => 'server2.example/cgi-bin/auth', 'protocol' => 'smtp', 'listen_port' => 587} }
    }
  end

  shared_examples "a Linux OS" do
    it { should compile.with_all_deps }
    it { should contain_class('nginx') }
    it { should contain_anchor('nginx::begin') }
    it { should contain_nginx__package.that_requires('Anchor[nginx::begin]') }
    it { should contain_nginx__config.that_requires('Class[nginx::package]') }
    it { should contain_nginx__service.that_subscribes_to('Anchor[nginx::begin]') }
    it { should contain_nginx__service.that_subscribes_to('Class[nginx::package]') }
    it { should contain_nginx__service.that_subscribes_to('Class[nginx::config]') }
    it { should contain_anchor('nginx::end').that_requires('Class[nginx::service]') }
    it { should contain_class("nginx::params") }
    it { should contain_nginx__resource__upstream("upstream1") }
    it { should contain_nginx__resource__vhost("test2.local") }
    it { should contain_nginx__resource__location("test2.local") }
    it { should contain_nginx__resource__mailhost("smtp.test2.local") }
  end

  context "Debian OS" do
    it_behaves_like "a Linux OS" do
      let :facts do
        {
          :operatingsystem => 'Debian',
          :osfamily        => 'Debian',
          :lsbdistcodename => 'precise',
        }
      end
    end
  end

  context "RedHat OS" do
    it_behaves_like "a Linux OS" do
      let :facts do
        {
          :operatingsystem => 'RedHat',
          :osfamily        => 'RedHat',
        }
      end
    end
  end

  context "Suse OS" do
    it_behaves_like "a Linux OS" do
      let :facts do
        {
          :operatingsystem => 'SuSE',
          :osfamily        => 'Suse',
        }
      end
    end
  end
end
require 'spec_helper'

describe 'nginx::package' do

  shared_examples 'redhat' do |operatingsystem|
    let(:facts) {{ :operatingsystem => operatingsystem, :osfamily => 'RedHat' }}

    context "using defaults" do
      it { should contain_package('nginx') }
      it { should contain_yumrepo('nginx-release').with(
        'baseurl'  => 'http://nginx.org/packages/rhel/6/$basearch/',
        'descr'    => 'nginx repo',
        'enabled'  => '1',
        'gpgcheck' => '1',
        'priority' => '1',
        'gpgkey'   => 'http://nginx.org/keys/nginx_signing.key'
      )}
      it { should contain_file('/etc/yum.repos.d/nginx-release.repo') }
      it { should contain_anchor('nginx::package::begin').that_comes_before('Class[nginx::package::redhat]') }
      it { should contain_anchor('nginx::package::end').that_requires('Class[nginx::package::redhat]') }
    end

    context "manage_repo => false" do
      let(:params) {{ :manage_repo => false }}
      it { should contain_package('nginx') }
      it { should_not contain_yumrepo('nginx-release') }
      it { should_not contain_file('/etc/yum.repos.d/nginx-release.repo') }
    end

    context "lsbmajdistrelease = 5" do
      let(:facts) {{ :operatingsystem => operatingsystem, :osfamily => 'RedHat', :lsbmajdistrelease => 5 }}
      it { should contain_package('nginx') }
      it { should contain_yumrepo('nginx-release').with(
        'baseurl'  => 'http://nginx.org/packages/rhel/5/$basearch/'
      )}
      it { should contain_file('/etc/yum.repos.d/nginx-release.repo') }
    end

    describe 'installs the requested package version' do
      let(:facts) {{ :operatingsystem => 'redhat', :osfamily => 'redhat' }}
      let(:params) {{ :package_ensure => '3.0.0' }}

      it 'installs 3.0.0 exactly' do
        should contain_package('nginx').with({
          'ensure' => '3.0.0'
        })
      end
    end
  end

  shared_examples 'debian' do |operatingsystem, lsbdistcodename|
    let(:facts) {{ :operatingsystem => operatingsystem, :osfamily => 'Debian', :lsbdistcodename => lsbdistcodename }}

    context "using defaults" do
      it { should contain_package('nginx') }
      it { should_not contain_package('passenger') }
      it { should contain_apt__source('nginx').with(
        'location'   => "http://nginx.org/packages/#{operatingsystem}",
        'repos'      => 'nginx',
        'key'        => '7BD9BF62',
        'key_source' => 'http://nginx.org/keys/nginx_signing.key'
      )}
      it { should contain_anchor('nginx::package::begin').that_comes_before('Class[nginx::package::debian]') }
      it { should contain_anchor('nginx::package::end').that_requires('Class[nginx::package::debian]') }
    end

    context "package_source => 'passenger'" do
      let(:params) {{ :package_source => 'passenger' }}
      it { should contain_package('nginx') }
      it { should contain_package('passenger') }
      it { should contain_apt__source('nginx').with(
        'location'   => 'https://oss-binaries.phusionpassenger.com/apt/passenger',
        'repos'      => "main",
        'key'        => '561F9B9CAC40B2F7',
        'key_source' => 'https://oss-binaries.phusionpassenger.com/auto-software-signing-gpg-key.txt'
      )}
    end

    context "manage_repo => false" do
      let(:params) {{ :manage_repo => false }}
      it { should contain_package('nginx') }
      it { should_not contain_apt__source('nginx') }
      it { should_not contain_package('passenger') }
    end
  end

  shared_examples 'suse' do |operatingsystem|
    let(:facts) {{ :operatingsystem => operatingsystem, :osfamily => 'Suse'}}
    [
      'nginx',
    ].each do |package|
      it { should contain_package("#{package}") }
    end
    it { should contain_anchor('nginx::package::begin').that_comes_before('Class[nginx::package::suse]') }
    it { should contain_anchor('nginx::package::end').that_requires('Class[nginx::package::suse]') }
  end


  context 'redhat' do
    it_behaves_like 'redhat', 'centos'
    it_behaves_like 'redhat', 'rhel'
    it_behaves_like 'redhat', 'redhat'
    it_behaves_like 'redhat', 'scientific'
    it_behaves_like 'redhat', 'amazon'
  end

  context 'debian' do
    it_behaves_like 'debian', 'debian', 'wheezy'
    it_behaves_like 'debian', 'ubuntu', 'precise'
  end

  context 'suse' do
    it_behaves_like 'suse', 'opensuse'
    it_behaves_like 'suse', 'suse'
  end

  context 'amazon with facter < 1.7.2' do
    let(:facts) {{ :operatingsystem => 'Amazon', :osfamily => 'Linux' }}
      it { should contain_package('nginx') }
      it { should contain_yumrepo('nginx-release').with(
        'baseurl'  => 'http://nginx.org/packages/rhel/6/$basearch/',
        'descr'    => 'nginx repo',
        'enabled'  => '1',
        'gpgcheck' => '1',
        'priority' => '1',
        'gpgkey'   => 'http://nginx.org/keys/nginx_signing.key'
      )}
      it { should contain_file('/etc/yum.repos.d/nginx-release.repo') }
      it { should contain_anchor('nginx::package::begin').that_comes_before('Class[nginx::package::redhat]') }
      it { should contain_anchor('nginx::package::end').that_requires('Class[nginx::package::redhat]') }
  end

  context 'fedora' do
    # fedora is identical to the rest of osfamily RedHat except for not
    # including nginx-release
    let(:facts) {{ :operatingsystem => 'Fedora', :osfamily => 'RedHat', :lsbmajdistrelease => 6 }}
    it { should contain_package('nginx') }
    it { should_not contain_yumrepo('nginx-release') }
    it { should_not contain_file('/etc/yum.repos.d/nginx-release.repo') }
  end

  context 'other' do
    let(:facts) {{ :operatingsystem => 'xxx', :osfamily => 'linux' }}
    it { expect { subject }.to raise_error(Puppet::Error, /Module nginx is not supported on xxx/) }
  end
end
require 'spec_helper'

describe 'nginx::params' do
  context "On a Debian OS" do
    let :facts do {
      :osfamily        => 'debian',
      :operatingsystem => 'debian',
    } end

    it { should contain_nginx__params }
    it { should have_class_count(1) }    #only nginx::params itself
    it { should have_resource_count(0) } #params class should never declare resources

  end
end
require 'spec_helper'
describe 'nginx::service' do

  let :facts do {
    :osfamily        => 'Debian',
    :operatingsystem => 'debian',
  } end

  let :params do {
      :configtest_enable => false,
      :service_restart => '/etc/init.d/nginx configtest && /etc/init.d/nginx restart',
      :service_ensure => 'running',
  } end   

  context "using default parameters" do

    it { should contain_service('nginx').with(
      :ensure     => 'running',
      :enable     => true,
      :hasstatus  => true,
      :hasrestart => true
    )}

    it { should contain_service('nginx').without_restart }

  end

  describe "when configtest_enable => true" do
    let(:params) {{ :configtest_enable => true,  :service_restart => '/etc/init.d/nginx configtest && /etc/init.d/nginx restart'}}
    it { should contain_service('nginx').with_restart('/etc/init.d/nginx configtest && /etc/init.d/nginx restart') }

    context "when service_restart => 'a restart command'" do
      let(:params) {{ :configtest_enable => true, :service_restart => 'a restart command' }}
      it { should contain_service('nginx').with_restart('a restart command') }
    end
  end

end
require 'spec_helper'

describe 'nginx::resource::geo' do
  let :title do
    'client_network'
  end

  let :default_params do
    {
      :default  => 'extra',
      :networks => {
        '172.16.0.0/12'  => 'intra',
        '192.168.0.0/16' => 'intra',
        '10.0.0.0/8'     => 'intra',
      },
      :proxies => [ '1.2.3.4', '4.3.2.1' ]
    }
  end

  let :facts do
    {
      :osfamily        => 'RedHat',
      :operatingsystem => 'CentOS',
    }
  end

  let :pre_condition do
    [
      'include ::nginx::params',
      'include ::nginx::config',
    ]
  end

  describe 'os-independent items' do
    describe 'basic assumptions' do
      let :params do default_params end

      it { should contain_file("/etc/nginx/conf.d/#{title}-geo.conf").with(
        {
          'owner'   => 'root',
          'group'   => 'root',
          'mode'    => '0644',
          'ensure'  => 'file',
          'content' => /geo \$#{title}/,
        }
      )}
    end

    describe "geo.conf template content" do
      [
        {
          :title => 'should set address',
          :attr  => 'address',
          :value => '$remote_addr',
          :match => 'geo $remote_addr $client_network {'
        },
        {
          :title => 'should set ranges',
          :attr  => 'ranges',
          :value => true,
          :match => '  ranges;'
        },
        {
          :title => 'should set default',
          :attr  => 'default',
          :value => 'extra',
          :match => [ '  default extra;' ],
        },
        {
          :title => 'should contain ordered network directives',
          :attr  => 'networks',
          :value => {
            '192.168.0.0/16' => 'intra',
            '172.16.0.0/12'  => 'intra',
            '10.0.0.0/8'     => 'intra',
          },
          :match => [
            '  10.0.0.0/8 intra;',
            '  172.16.0.0/12 intra;',
            '  192.168.0.0/16 intra;',
          ],
        },
        {
          :title => 'should set multiple proxies',
          :attr  => 'proxies',
          :value => [ '1.2.3.4', '4.3.2.1' ],
          :match => [
            '  proxy 1.2.3.4;',
            '  proxy 4.3.2.1;'
          ]
        },
        {
          :title => 'should set proxy_recursive',
          :attr  => 'proxy_recursive',
          :value => true,
          :match => '  proxy_recursive;'
        },
        {
          :title => 'should set delete',
          :attr  => 'delete',
          :value => '192.168.0.0/16',
          :match => '  delete 192.168.0.0/16;'
        },
      ].each do |param|
        context "when #{param[:attr]} is #{param[:value]}" do
          let :params do default_params.merge({ param[:attr].to_sym => param[:value] }) end

          it { should contain_file("/etc/nginx/conf.d/#{title}-geo.conf").with_mode('0644') }
          it param[:title] do
            verify_contents(subject, "/etc/nginx/conf.d/#{title}-geo.conf", Array(param[:match]))
            Array(param[:notmatch]).each do |item|
              should contain_file("/etc/nginx/conf.d/#{title}-geo.conf").without_content(item)
            end
          end
        end
      end

      context 'when ensure => absent' do
        let :params do default_params.merge(
          {
            :ensure => 'absent'
          }
        ) end

        it { should contain_file("/etc/nginx/conf.d/#{title}-geo.conf").with_ensure('absent') }
      end
    end
  end
end
require 'spec_helper'
require 'digest/md5'

describe 'nginx::resource::location' do
  let :title do
    'rspec-test'
  end
  let :facts do
    {
      :osfamily        => 'Debian',
      :operatingsystem => 'debian',
    }
  end
  let :pre_condition do
    [
      'include ::nginx::params',
      'include ::nginx::config',
    ]
  end

  describe 'os-independent items' do

    describe 'basic assumptions' do
      let :params do {
        :www_root => "/var/www/rspec",
        :vhost    => 'vhost1',
      } end

      it { should contain_class("nginx::params") }
      it { should contain_class("nginx::config") }
      it { should contain_concat__fragment("f25e14942fb58942ee13b1465a4e1719").with_content(/location rspec-test/) }
      it { should_not contain_file('/etc/nginx/fastcgi_params') }
      it { should_not contain_concat__fragment("vhost1-800-rspec-test-ssl") }
      it { should_not contain_file("/etc/nginx/rspec-test_htpasswd") }
    end

    describe "vhost/location_header template content" do
      [
        {
          :title => 'should set the location',
          :attr  => 'location',
          :value => 'my_location',
          :match => '  location my_location {',
        },
        {
          :title    => 'should not set internal',
          :attr     => 'internal',
          :value    => false,
          :notmatch => /internal;/
        },
        {
          :title => 'should set internal',
          :attr  => 'internal',
          :value => true,
          :match => '    internal;'
        },
        {
          :title => 'should set location_allow',
          :attr  => 'location_allow',
          :value => %w( 127.0.0.1 10.0.0.1 ),
          :match => [
            '    allow 127.0.0.1;',
            '    allow 10.0.0.1;',
          ],
        },
        {
          :title => 'should set location_deny',
          :attr  => 'location_deny',
          :value => %w( 127.0.0.1 10.0.0.1 ),
          :match => [
            '    deny 127.0.0.1;',
            '    deny 10.0.0.1;',
          ],
        },
        {
          :title => 'should contain ordered prepended directives',
          :attr  => 'location_cfg_prepend',
          :value => { 'test1' => 'test value 1', 'test2' => ['test value 2a', 'test value 2b'],
                      'test3' => { 'subtest1' => ['"sub test value1a"', '"sub test value1b"'],
                                  'subtest2' => '"sub test value2"' } },
          :match => [
            '    test1 test value 1;',
            '    test2 test value 2a;',
            '    test2 test value 2b;',
            '    test3 subtest1 "sub test value1a";',
            '    test3 subtest1 "sub test value1b";',
            '    test3 subtest2 "sub test value2";',
          ],
        },
        {
          :title => 'should contain custom prepended directives',
          :attr  => 'location_custom_cfg_prepend',
          :value => { 'test1' => 'bar', 'test2' => ['foobar', 'barbaz'],
                      'test3' => { 'subtest1' => ['"sub test value1a"', '"sub test value1b"'],
                                  'subtest2' => '"sub test value2"' } },
          :match => [
            /^[ ]+test1\s+bar/,
            /^[ ]+test2\s+foobar/,
            /^[ ]+test2\s+barbaz/,
            /^[ ]+test3\s+subtest1 "sub test value1a"/,
            /^[ ]+test3\s+subtest1 "sub test value1b"/,
            /^[ ]+test3\s+subtest2 "sub test value2"/,
          ],
        },
        {
          :title => 'should contain raw_prepend directives',
          :attr  => 'raw_prepend',
          :value => [
            'if (a) {',
            '  b;',
            '}'
          ],
          :match => /^\s+if \(a\) {\n\s++b;\n\s+\}/,
        },
      ].each do |param|
        context "when #{param[:attr]} is #{param[:value]}" do
          let :default_params do { :location => 'location', :proxy => 'proxy_value', :vhost => 'vhost1' } end
          let :params do default_params.merge({ param[:attr].to_sym => param[:value] }) end

          it { should contain_concat__fragment(Digest::MD5.hexdigest("vhost1-500-#{params[:location]}")) }

          it param[:title] do
            fragment = Digest::MD5.hexdigest("vhost1-500-#{params[:location]}")
            matches  = Array(param[:match])

            if matches.all? { |m| m.is_a? Regexp }
              matches.each { |item| should contain_concat__fragment(fragment).with_content(item) }
            else
              lines = subject.resource('concat::fragment', fragment).send(:parameters)[:content].split("\n")
              (lines & matches).should == matches
            end

            Array(param[:notmatch]).each do |item|
              should contain_concat__fragment(Digest::MD5.hexdigest("vhost1-500-#{params[:location]}")).without_content(item)
            end
          end
        end
      end
    end

    describe "vhost/location_footer template content" do
      [
        {
          :title => 'should contain ordered appended directives',
          :attr  => 'location_cfg_append',
          :value => { 'test1' => 'test value 1', 'test2' => ['test value 2a', 'test value 2b'],
                      'test3' => { 'subtest1' => ['"sub test value1a"', '"sub test value1b"'],
                                  'subtest2' => '"sub test value2"' } },
          :match => [
            '    test1 test value 1;',
            '    test2 test value 2a;',
            '    test2 test value 2b;',
            '    test3 subtest1 "sub test value1a";',
            '    test3 subtest1 "sub test value1b";',
            '    test3 subtest2 "sub test value2";',
          ],
        },
        {
          :title => 'should contain custom appended directives',
          :attr  => 'location_custom_cfg_append',
          :value => { 'test1' => 'bar', 'test2' => ['foobar', 'barbaz'],
                      'test3' => { 'subtest1' => ['"sub test value1a"', '"sub test value1b"'],
                                  'subtest2' => '"sub test value2"' } },
          :match => [
            /^[ ]+test1\s+bar/,
            /^[ ]+test2\s+foobar/,
            /^[ ]+test2\s+barbaz/,
            /^[ ]+test3\s+subtest1 "sub test value1a"/,
            /^[ ]+test3\s+subtest1 "sub test value1b"/,
            /^[ ]+test3\s+subtest2 "sub test value2"/,
          ],
        },
        {
          :title => 'should contain raw_append directives',
          :attr  => 'raw_append',
          :value => [
            'if (a) {',
            '  b;',
            '}'
          ],
          :match => /^\s+if \(a\) {\n\s++b;\n\s+\}/,
        },
      ].each do |param|
        context "when #{param[:attr]} is #{param[:value]}" do
          let :default_params do { :location => 'location', :proxy => 'proxy_value', :vhost => 'vhost1' } end
          let :params do default_params.merge({ param[:attr].to_sym => param[:value] }) end

          it { should contain_concat__fragment(Digest::MD5.hexdigest("vhost1-500-#{params[:location]}")) }

          it param[:title] do
            fragment = Digest::MD5.hexdigest("vhost1-500-#{params[:location]}")
            matches  = Array(param[:match])

            if matches.all? { |m| m.is_a? Regexp }
              matches.each { |item| should contain_concat__fragment(fragment).with_content(item) }
            else
              lines = subject.resource('concat::fragment', fragment).send(:parameters)[:content].split("\n")
              (lines & matches).should == matches
            end

            Array(param[:notmatch]).each do |item|
              should contain_concat__fragment(Digest::MD5.hexdigest("vhost1-500-#{params[:location]}")).without_content(item)
            end
          end

          it "should end with a closing brace" do
            fragment = Digest::MD5.hexdigest("vhost1-500-#{params[:location]}")
            content = subject.resource('concat::fragment', fragment).send(:parameters)[:content]
            (content.split("\n").reject {|l| l =~ /^(\s*#|$)/ }.last).strip.should == '}'
          end
        end
      end
    end

    describe "vhost_location_alias template content" do
      let :default_params do
        { :location => 'location', :vhost => 'vhost1', :location_alias => 'value' }
      end

      context "when location_alias is 'value'" do
        let :params do default_params end
        it { should contain_concat__fragment(Digest::MD5.hexdigest("vhost1-500-location")) }
        it "should set alias" do
          should contain_concat__fragment(Digest::MD5.hexdigest("vhost1-500-location")).
                  with_content(/^[ ]+alias\s+value;/)
        end
      end

      context "when autoindex is 'on'" do
        let :params do default_params.merge({ :autoindex => 'on' }) end
        it { should contain_concat__fragment(Digest::MD5.hexdigest("vhost1-500-location")) }
        it "should set autoindex" do
          should contain_concat__fragment(Digest::MD5.hexdigest("vhost1-500-location")).
                  with_content(/^[ ]+autoindex\s+on;/)
        end
      end

      context "when autoindex is not set" do
        let :params do default_params end
        it { should contain_concat__fragment(Digest::MD5.hexdigest("vhost1-500-location")) }
        it "should not set autoindex" do
          should contain_concat__fragment(Digest::MD5.hexdigest("vhost1-500-location")).
                  without_content(/^[ ]+autoindex[^;]+;/)
        end
      end
    end

    describe "vhost_location_directory template content" do
      let :default_params do
        {
          :location => 'location',
          :www_root => '/var/www/root',
          :vhost    => 'vhost1'
        }
      end

      [
        {
          :title => 'should set www_root',
          :attr  => 'www_root',
          :value => '/',
          :match => '    root  /;'
        },
        {
          :title => 'should set try_file(s)',
          :attr  => 'try_files',
          :value => ['name1','name2'],
          :match => '    try_files name1 name2;',
        },
        {
          :title => 'should set index_file(s)',
          :attr  => 'index_files',
          :value => ['name1','name2'],
          :match => '    index  name1 name2;',
        },
        {
          :title => 'should contain rewrite rules',
          :attr  => 'rewrite_rules',
          :value => [
            '^(/download/.*)/media/(.*)\..*$ $1/mp3/$2.mp3 last',
            '^(/download/.*)/audio/(.*)\..*$ $1/mp3/$2.ra  last',
            '^/users/(.*)$ /show?user=$1? last',
          ],
          :match => [
            '    rewrite ^(/download/.*)/media/(.*)\..*$ $1/mp3/$2.mp3 last;',
            '    rewrite ^(/download/.*)/audio/(.*)\..*$ $1/mp3/$2.ra  last;',
            '    rewrite ^/users/(.*)$ /show?user=$1? last;',
          ],
        },
        {
          :title    => 'should not set rewrite_rules',
          :attr     => 'rewrite_rules',
          :value    => [],
          :notmatch => /rewrite/
        },
        {
          :title => 'should set auth_basic',
          :attr  => 'auth_basic',
          :value => 'value',
          :match => '    auth_basic           "value";',
        },
        {
          :title => 'should set auth_basic_user_file',
          :attr  => 'auth_basic_user_file',
          :value => 'value',
          :match => '    auth_basic_user_file value;',
        },
      ].each do |param|
        context "when #{param[:attr]} is #{param[:value]}" do
          let :params do default_params.merge({ param[:attr].to_sym => param[:value] }) end

          it { should contain_concat__fragment(Digest::MD5.hexdigest("vhost1-500-#{params[:location]}")) }
          it param[:title] do
            fragment = Digest::MD5.hexdigest("vhost1-500-#{params[:location]}")
            matches  = Array(param[:match])

            if matches.all? { |m| m.is_a? Regexp }
              matches.each { |item| should contain_concat__fragment(fragment).with_content(item) }
            else
              lines = subject.resource('concat::fragment', fragment).send(:parameters)[:content].split("\n")
              (lines & matches).should == matches
            end

            Array(param[:notmatch]).each do |item|
              should contain_concat__fragment(Digest::MD5.hexdigest("vhost1-500-#{params[:location]}")).without_content(item)
            end
          end
        end
      end

      context "when autoindex is 'on'" do
        let :params do default_params.merge({ :autoindex => 'on' }) end
        it { should contain_concat__fragment(Digest::MD5.hexdigest("vhost1-500-location")) }
        it "should set autoindex" do
          should contain_concat__fragment(Digest::MD5.hexdigest("vhost1-500-location")).
                  with_content(/^[ ]+autoindex\s+on;/)
        end
      end

      context "when autoindex is not set" do
        let :params do default_params end
        it { should contain_concat__fragment(Digest::MD5.hexdigest("vhost1-500-location")) }
        it "should not set autoindex" do
          should contain_concat__fragment(Digest::MD5.hexdigest("vhost1-500-location")).
                  without_content(/^[ ]+autoindex[^;]+;/)
        end
      end
    end

    describe "vhost_location_empty template content" do
      [
        {
          :title => 'should contain ordered config directives',
          :attr  => 'location_custom_cfg',
          :value => { 'test1' => ['test value 1a', 'test value 1b'], 'test2' => 'test value 2', 'allow' => 'test value 3',
                      'test4' => { 'subtest1' => ['"sub test value1a"', '"sub test value1b"'],
                                  'subtest2' => '"sub test value2"' } },
          :match => [
            '    allow test value 3;',
            '    test1 test value 1a;',
            '    test1 test value 1b;',
            '    test2 test value 2;',
            '    test4 subtest1 "sub test value1a";',
            '    test4 subtest1 "sub test value1b";',
            '    test4 subtest2 "sub test value2";',
          ],
        },
      ].each do |param|
        context "when #{param[:attr]} is #{param[:value]}" do
          let :default_params do { :location => 'location', :location_custom_cfg => {'test1'=>'value1'}, :vhost => 'vhost1' } end
          let :params do default_params.merge({ param[:attr].to_sym => param[:value] }) end

          it { should contain_concat__fragment(Digest::MD5.hexdigest("vhost1-500-#{params[:location]}")) }
          it param[:title] do
            fragment = Digest::MD5.hexdigest("vhost1-500-#{params[:location]}")
            matches  = Array(param[:match])

            if matches.all? { |m| m.is_a? Regexp }
              matches.each { |item| should contain_concat__fragment(fragment).with_content(item) }
            else
              lines = subject.resource('concat::fragment', fragment).send(:parameters)[:content].split("\n")
              (lines & matches).should == matches
            end

            Array(param[:notmatch]).each do |item|
              should contain_concat__fragment(Digest::MD5.hexdigest("vhost1-500-#{params[:location]}")).without_content(item)
            end
          end
        end
      end
    end

    describe "vhost_location_fastcgi template content" do
      let :default_params do
        {
          :location => 'location',
          :fastcgi  => 'localhost:9000',
          :vhost    => 'vhost1'
        }
      end

      [
        {
          :title => 'should set www_root',
          :attr  => 'www_root',
          :value => '/',
          :match => '    root  /;'
        },
        {
          :title => 'should set fastcgi_split_path',
          :attr  => 'fastcgi_split_path',
          :value => 'value',
          :match => '    fastcgi_split_path_info value;'
        },
        {
          :title => 'should set try_file(s)',
          :attr  => 'try_files',
          :value => ['name1','name2'],
          :match => '    try_files name1 name2;',
        },
        {
          :title => 'should set fastcgi_params',
          :attr  => 'fastcgi_params',
          :value => 'value',
          :match => /^[ ]+include\s+value;/
        },
        {
          :title => 'should set fastcgi_pass',
          :attr  => 'fastcgi',
          :value => 'value',
          :match => '    fastcgi_pass value;'
        },
      ].each do |param|
        context "when #{param[:attr]} is #{param[:value]}" do
          let :params do default_params.merge({ param[:attr].to_sym => param[:value] }) end

          it { should contain_concat__fragment(Digest::MD5.hexdigest("vhost1-500-#{params[:location]}")) }
          it param[:title] do
            fragment = Digest::MD5.hexdigest("vhost1-500-#{params[:location]}")
            matches  = Array(param[:match])

            if matches.all? { |m| m.is_a? Regexp }
              matches.each { |item| should contain_concat__fragment(fragment).with_content(item) }
            else
              lines = subject.resource('concat::fragment', fragment).send(:parameters)[:content].split("\n")
              (lines & matches).should == matches
            end

            Array(param[:notmatch]).each do |item|
              should contain_concat__fragment(Digest::MD5.hexdigest("vhost1-500-#{params[:location]}")).without_content(item)
            end
          end
        end
      end

      context "when fastcgi_script is 'value'" do
        let :params do default_params.merge({ :fastcgi_script => 'value' }) end
        it { should contain_concat__fragment(Digest::MD5.hexdigest("vhost1-500-#{params[:location]}")) }
        it "should set fastcgi_script" do
          should contain_concat__fragment(Digest::MD5.hexdigest("vhost1-500-#{params[:location]}")).
                  with_content(%r|^[ ]+fastcgi_param\s+SCRIPT_FILENAME\s+value;|)
        end
      end

      context "when fastcgi_script is not set" do
        let :params do default_params end
        it { should contain_concat__fragment(Digest::MD5.hexdigest("vhost1-500-#{params[:location]}")) }
        it "should not set fastcgi_script" do
          should contain_concat__fragment(Digest::MD5.hexdigest("vhost1-500-#{params[:location]}")).
                  without_content(/^[ ]+fastcgi_param\s+SCRIPT_FILENAME\s+.+?;/)
        end
      end
    end

    describe "vhost_location_proxy template content" do
      [
        {
          :title => 'should set proxy_cache',
          :attr  => 'proxy_cache',
          :value => 'value',
          :match => /^[ ]+proxy_cache\s+value;/,
        },
        {
          :title    => 'should not set proxy_cache',
          :attr     => 'proxy_cache',
          :value    => false,
          :notmatch => /proxy_cache\b/
        },
        {
          :title => 'should set proxy_pass',
          :attr  => 'proxy',
          :value => 'value',
          :match => /^[ ]+proxy_pass\s+value;/,
        },
        {
          :title => 'should set proxy_read_timeout',
          :attr  => 'proxy_read_timeout',
          :value => 'value',
          :match => '    proxy_read_timeout  value;',
        },
        {
          :title => 'should set proxy_connect_timeout',
          :attr  => 'proxy_connect_timeout',
          :value => 'value',
          :match => '    proxy_connect_timeout  value;',
        },
        {
          :title => 'should set proxy_read_timeout',
          :attr  => 'proxy_read_timeout',
          :value => 'value',
          :match => '    proxy_read_timeout  value;',
        },
        {
          :title => 'should set proxy headers',
          :attr  => 'proxy_set_header',
          :value => [ 'X-TestHeader1 value1', 'X-TestHeader2 value2' ],
          :match => [
            /^[ ]+proxy_set_header\s+X-TestHeader1 value1;/,
            /^[ ]+proxy_set_header\s+X-TestHeader2 value2;/,
          ]
        },
        {
          :title => 'should set proxy_method',
          :attr  => 'proxy_method',
          :value => 'value',
          :match => '    proxy_method        value;',
        },
        {
          :title => 'should set proxy_set_body',
          :attr  => 'proxy_set_body',
          :value => 'value',
          :match => '    proxy_set_body      value;',
        },
        {
          :title => 'should contain rewrite rules',
          :attr  => 'rewrite_rules',
          :value => [
            '^(/download/.*)/media/(.*)\..*$ $1/mp3/$2.mp3 last',
            '^(/download/.*)/audio/(.*)\..*$ $1/mp3/$2.ra  last',
            '^/users/(.*)$ /show?user=$1? last',
          ],
          :match => [
            '    rewrite ^(/download/.*)/media/(.*)\..*$ $1/mp3/$2.mp3 last;',
            '    rewrite ^(/download/.*)/audio/(.*)\..*$ $1/mp3/$2.ra  last;',
            '    rewrite ^/users/(.*)$ /show?user=$1? last;',
          ],
        },
        {
          :title    => 'should not set rewrite_rules',
          :attr     => 'rewrite_rules',
          :value    => [],
          :notmatch => /rewrite/
        },
      ].each do |param|
        context "when #{param[:attr]} is #{param[:value]}" do
          let :default_params do { :location => 'location', :proxy => 'proxy_value', :vhost => 'vhost1' } end
          let :params do default_params.merge({ param[:attr].to_sym => param[:value] }) end

          it { should contain_concat__fragment(Digest::MD5.hexdigest("vhost1-500-#{params[:location]}")) }
          it param[:title] do
            fragment = Digest::MD5.hexdigest("vhost1-500-#{params[:location]}")
            matches  = Array(param[:match])

            if matches.all? { |m| m.is_a? Regexp }
              matches.each { |item| should contain_concat__fragment(fragment).with_content(item) }
            else
              lines = subject.resource('concat::fragment', fragment).send(:parameters)[:content].split("\n")
              (lines & matches).should == matches
            end

            Array(param[:notmatch]).each do |item|
              should contain_concat__fragment(Digest::MD5.hexdigest("vhost1-500-#{params[:location]}")).without_content(item)
            end
          end
        end
      end

      context "when proxy_cache_valid is 10m" do
        let :params do {
          :location => 'location',
          :proxy => 'proxy_value',
          :vhost => 'vhost1',
          :proxy_cache => 'true',
          :proxy_cache_valid => '10m',
        } end

        it { should contain_concat__fragment(Digest::MD5.hexdigest("vhost1-500-location")).with_content(/proxy_cache_valid   10m;/) }
      end
    end

    describe "vhost_location_stub_status template content" do
      let :params do { :location => 'location', :stub_status => true, :vhost => 'vhost1' }  end
      it do
        should contain_concat__fragment(Digest::MD5.hexdigest("vhost1-500-#{params[:location]}")).
                 with_content(/stub_status\s+on/)
      end
    end

    context 'attribute resources' do
      context 'when fastcgi => "localhost:9000"' do
        let :params do { :fastcgi => 'localhost:9000', :vhost => 'vhost1' } end

        it { should contain_file('/etc/nginx/fastcgi_params').with_mode('0770') }
      end

      context 'when ssl_only => true' do
        let :params do { :ssl_only => true, :vhost => 'vhost1', :www_root => '/', } end
        it { should_not contain_concat__fragment(Digest::MD5.hexdigest("vhost1-500-rspec-test")) }
      end

      context 'when ssl_only => false' do
        let :params do { :ssl_only => false, :vhost => 'vhost1', :www_root => '/', } end

        it { should contain_concat__fragment(Digest::MD5.hexdigest("vhost1-500-rspec-test")) }
      end

      context 'when ssl => true' do
        let :params do { :ssl => true, :vhost => 'vhost1', :www_root => '/', } end

        it { should contain_concat__fragment(Digest::MD5.hexdigest("vhost1-800-rspec-test-ssl")) }
      end

      context 'when ssl => false' do
        let :params do { :ssl => false, :vhost => 'vhost1', :www_root => '/', } end

        it { should_not contain_concat__fragment(Digest::MD5.hexdigest("vhost1-800-rspec-test-ssl")) }
      end

      context 'when auth_basic_user_file => true' do
        let :params do { :auth_basic_user_file => '/path/to/file', :vhost => 'vhost1', :www_root => '/', } end

        it { should contain_file("/etc/nginx/rspec-test_htpasswd") }
      end

      context 'when ensure => absent' do
        let :params do {
          :www_root             => '/',
          :vhost                => 'vhost1',
          :ensure               => 'absent',
          :ssl                  => true,
          :auth_basic_user_file => '/path/to/file',
        } end

        it { should contain_file("/etc/nginx/rspec-test_htpasswd").with_ensure('absent') }
      end

      context "vhost missing" do
        let :params do {
          :www_root => '/',
        } end

        it { expect { should contain_class('nginx::resource::location') }.to raise_error(Puppet::Error, /Cannot create a location reference without attaching to a virtual host/) }
      end

      context "location type missing" do
        let :params do {
          :vhost => 'vhost1',
        } end

        it { expect { should contain_class('nginx::resource::location') }.to raise_error(Puppet::Error, /Cannot create a location reference without a www_root, proxy, location_alias, fastcgi, stub_status, or location_custom_cfg defined/) }
      end

      context "www_root and proxy are set" do
        let :params do {
          :vhost    => 'vhost1',
          :www_root => '/',
          :proxy    => 'http://localhost:8000/uri/',
        } end

        it { expect { should contain_class('nginx::resource::location') }.to raise_error(Puppet::Error, /Cannot define both directory and proxy in a virtual host/) }
      end

      context 'when vhost name is sanitized' do
        let :title do 'www.rspec-location.com' end
        let :params do {
          :vhost => 'www rspec-vhost com',
          :www_root => '/',
          :ssl => true,
        } end

        it { should contain_concat__fragment(Digest::MD5.hexdigest("www_rspec-vhost_com-500-www.rspec-location.com")).with_target('/etc/nginx/sites-available/www_rspec-vhost_com.conf') }
        it { should contain_concat__fragment(Digest::MD5.hexdigest("www_rspec-vhost_com-800-www.rspec-location.com-ssl")).with_target('/etc/nginx/sites-available/www_rspec-vhost_com.conf') }
      end
    end
  end
end
require 'spec_helper'

describe 'nginx::resource::mailhost' do
  let :title do
    'www.rspec.example.com'
  end
  let :facts do
    {
      :osfamily        => 'debian',
      :operatingsystem => 'debian',
      :ipaddress6      => '::',
    }
  end
  let :default_params do
    {
      :listen_port => 25,
      :ipv6_enable => true,
    }
  end
  let :pre_condition do
    [
      'include ::nginx::config',
    ]
  end

  describe 'os-independent items' do

    describe 'basic assumptions' do
      let :params do default_params end
      it { should contain_class("nginx::config") }
      it { should contain_concat("/etc/nginx/conf.mail.d/#{title}.conf").with({
        'owner' => 'root',
        'group' => 'root',
        'mode'  => '0644',
      })}
      it { should contain_concat__fragment("#{title}-header") }
      it { should_not contain_concat__fragment("#{title}-ssl") }
    end

    describe "mailhost template content" do
      [
        {
          :title => 'should set the IPv4 listen IP',
          :attr  => 'listen_ip',
          :value => '127.0.0.1',
          :match => '  listen                127.0.0.1:25;',
        },
        {
          :title => 'should set the IPv4 listen port',
          :attr  => 'listen_port',
          :value => 45,
          :match => '  listen                *:45;',
        },
        {
          :title => 'should set the IPv4 listen options',
          :attr  => 'listen_options',
          :value => 'spdy default',
          :match => '  listen                *:25 spdy default;',
        },
        {
          :title => 'should enable IPv6',
          :attr  => 'ipv6_enable',
          :value => true,
          :match => '  listen [::]:80 default ipv6only=on;',
        },
        {
          :title    => 'should not enable IPv6',
          :attr     => 'ipv6_enable',
          :value    => false,
          :notmatch => /  listen \[::\]:80 default ipv6only=on;/,
        },
        {
          :title => 'should set the IPv6 listen IP',
          :attr  => 'ipv6_listen_ip',
          :value => '2001:0db8:85a3:0000:0000:8a2e:0370:7334',
          :match => '  listen [2001:0db8:85a3:0000:0000:8a2e:0370:7334]:80 default ipv6only=on;',
        },
        {
          :title => 'should set the IPv6 listen port',
          :attr  => 'ipv6_listen_port',
          :value => 45,
          :match => '  listen [::]:45 default ipv6only=on;',
        },
        {
          :title => 'should set the IPv6 listen options',
          :attr  => 'ipv6_listen_options',
          :value => 'spdy',
          :match => '  listen [::]:80 spdy;',
        },
        {
          :title => 'should set servername(s)',
          :attr  => 'server_name',
          :value => ['name1','name2'],
          :match => '  server_name           name1 name2;',
        },
        {
          :title => 'should set protocol',
          :attr  => 'protocol',
          :value => 'test-protocol',
          :match => '  protocol              test-protocol;',
        },
        {
          :title => 'should set xclient',
          :attr  => 'xclient',
          :value => 'test-xclient',
          :match => '  xclient               test-xclient;',
        },
        {
          :title => 'should set auth_http',
          :attr  => 'auth_http',
          :value => 'test-auth_http',
          :match => '  auth_http             test-auth_http;',
        },
        {
          :title => 'should set starttls',
          :attr  => 'starttls',
          :value => 'on',
          :match => '  starttls              on;',
        },
        {
          :title => 'should set starttls',
          :attr  => 'starttls',
          :value => 'only',
          :match => '  starttls              only;',
        },
        {
          :title    => 'should not enable SSL',
          :attr     => 'starttls',
          :value    => 'off',
          :notmatch => /  ssl_session_timeout  5m;/,
        },
      ].each do |param|
        context "when #{param[:attr]} is #{param[:value]}" do
          let :default_params do {
            :listen_port => 25,
            :ipv6_enable => true,
            :ssl_cert    => 'dummy.crt',
            :ssl_key     => 'dummy.key',
          } end
          let :params do default_params.merge({ param[:attr].to_sym => param[:value] }) end

          it { should contain_concat__fragment("#{title}-header") }
          it param[:title] do
            lines = subject.resource('concat::fragment', "#{title}-header").send(:parameters)[:content].split("\n")
            (lines & Array(param[:match])).should == Array(param[:match])
            Array(param[:notmatch]).each do |item|
              should contain_concat__fragment("#{title}-header").without_content(item)
            end
          end
        end
      end
    end

    describe "mailhost template content (SSL enabled)" do
      [
        {
          :title => 'should enable SSL',
          :attr  => 'starttls',
          :value => 'on',
          :match => '  ssl_session_timeout  5m;',
        },
        {
          :title => 'should enable SSL',
          :attr  => 'starttls',
          :value => 'only',
          :match => '  ssl_session_timeout  5m;',
        },
        {
          :title    => 'should not enable SSL',
          :attr     => 'starttls',
          :value    => 'off',
          :notmatch => /  ssl_session_timeout  5m;/,
        },
        {
          :title => 'should set ssl_certificate',
          :attr  => 'ssl_cert',
          :value => 'test-ssl-cert',
          :match => '  ssl_certificate      test-ssl-cert;',
        },
        {
          :title => 'should set ssl_certificate_key',
          :attr  => 'ssl_key',
          :value => 'test-ssl-cert-key',
          :match => '  ssl_certificate_key  test-ssl-cert-key;',
        },
      ].each do |param|
        context "when #{param[:attr]} is #{param[:value]}" do
          let :default_params do {
            :listen_port => 25,
            :starttls    => 'on',
            :ssl_cert    => 'dummy.crt',
            :ssl_key     => 'dummy.key',
          } end
          let :params do default_params.merge({ param[:attr].to_sym => param[:value] }) end

          it { should contain_concat__fragment("#{title}-header") }
          it param[:title] do
            lines = subject.resource('concat::fragment', "#{title}-header").send(:parameters)[:content].split("\n")
            (lines & Array(param[:match])).should == Array(param[:match])
            Array(param[:notmatch]).each do |item|
              should contain_concat__fragment("#{title}-header").without_content(item)
            end
          end
        end
      end
    end

    describe "mailhost_ssl template content" do
      [
        {
          :title => 'should set the IPv4 SSL listen port',
          :attr  => 'ssl_port',
          :value => '45',
          :match => '  listen       45;',
        },
        {
          :title => 'should enable IPv6',
          :attr  => 'ipv6_enable',
          :value => true,
          :match => '  listen [::]:80 default ipv6only=on;',
        },
        {
          :title    => 'should not enable IPv6',
          :attr     => 'ipv6_enable',
          :value    => false,
          :notmatch => /  listen \[::\]:80 default ipv6only=on;/,
        },
        {
          :title => 'should set the IPv6 listen IP',
          :attr  => 'ipv6_listen_ip',
          :value => '2001:0db8:85a3:0000:0000:8a2e:0370:7334',
          :match => '  listen [2001:0db8:85a3:0000:0000:8a2e:0370:7334]:80 default ipv6only=on;',
        },
        {
          :title => 'should set the IPv6 listen port',
          :attr  => 'ipv6_listen_port',
          :value => 45,
          :match => '  listen [::]:45 default ipv6only=on;',
        },
        {
          :title => 'should set the IPv6 listen options',
          :attr  => 'ipv6_listen_options',
          :value => 'spdy',
          :match => '  listen [::]:80 spdy;',
        },
        {
          :title => 'should set servername(s)',
          :attr  => 'server_name',
          :value => ['name1','name2'],
          :match => '  server_name           name1 name2;',
        },
        {
          :title => 'should set protocol',
          :attr  => 'protocol',
          :value => 'test-protocol',
          :match => '  protocol              test-protocol;',
        },
        {
          :title => 'should set xclient',
          :attr  => 'xclient',
          :value => 'test-xclient',
          :match => '  xclient               test-xclient;',
        },
        {
          :title => 'should set auth_http',
          :attr  => 'auth_http',
          :value => 'test-auth_http',
          :match => '  auth_http             test-auth_http;',
        },
        {
          :title => 'should set ssl_certificate',
          :attr  => 'ssl_cert',
          :value => 'test-ssl-cert',
          :match => '  ssl_certificate      test-ssl-cert;',
        },
        {
          :title => 'should set ssl_certificate_key',
          :attr  => 'ssl_key',
          :value => 'test-ssl-cert-key',
          :match => '  ssl_certificate_key  test-ssl-cert-key;',
        },
      ].each do |param|
        context "when #{param[:attr]} is #{param[:value]}" do
          let :default_params do {
            :listen_port => 25,
            :ipv6_enable => true,
            :ssl         => true,
            :ssl_cert    => 'dummy.crt',
            :ssl_key     => 'dummy.key',
          } end
          let :params do default_params.merge({ param[:attr].to_sym => param[:value] }) end

          it { should contain_concat__fragment("#{title}-ssl") }
          it param[:title] do
            lines = subject.resource('concat::fragment', "#{title}-ssl").send(:parameters)[:content].split("\n")
            (lines & Array(param[:match])).should == Array(param[:match])
            Array(param[:notmatch]).each do |item|
              should contain_concat__fragment("#{title}-ssl").without_content(item)
            end
          end
        end
      end
    end

    context 'attribute resources' do
      context "SSL cert missing and ssl => true" do
        let :params do default_params.merge({
          :ssl     => true,
          :ssl_key => 'key',
        }) end

        it { expect { should contain_class('nginx::resource::vhost') }.to raise_error(Puppet::Error, %r{nginx: SSL certificate/key \(ssl_cert/ssl_cert\) and/or SSL Private must be defined and exist on the target system\(s\)}) }
      end

      context "SSL key missing and ssl => true" do
        let :params do default_params.merge({
          :ssl      => true,
          :ssl_cert => 'cert',
        }) end

        it { expect { should contain_class('nginx::resource::vhost') }.to raise_error(Puppet::Error, %r{nginx: SSL certificate/key \(ssl_cert/ssl_cert\) and/or SSL Private must be defined and exist on the target system\(s\)}) }
      end

      context "SSL cert missing and starttls => 'on'" do
        let :params do default_params.merge({
          :starttls => 'on',
          :ssl_key  => 'key',
        }) end

        it { expect { should contain_class('nginx::resource::vhost') }.to raise_error(Puppet::Error, %r{nginx: SSL certificate/key \(ssl_cert/ssl_cert\) and/or SSL Private must be defined and exist on the target system\(s\)}) }
      end

      context "SSL key missing and starttls => 'on'" do
        let :params do default_params.merge({
          :starttls => 'on',
          :ssl_cert => 'cert',
        }) end

        it { expect { should contain_class('nginx::resource::vhost') }.to raise_error(Puppet::Error, %r{nginx: SSL certificate/key \(ssl_cert/ssl_cert\) and/or SSL Private must be defined and exist on the target system\(s\)}) }
      end

      context "SSL cert missing and starttls => 'only'" do
        let :params do default_params.merge({
          :starttls => 'only',
          :ssl_key  => 'key',
        }) end

        it { expect { should contain_class('nginx::resource::vhost') }.to raise_error(Puppet::Error, %r{nginx: SSL certificate/key \(ssl_cert/ssl_cert\) and/or SSL Private must be defined and exist on the target system\(s\)}) }
      end

      context "SSL key missing and starttls => 'only'" do
        let :params do default_params.merge({
          :starttls => 'only',
          :ssl_cert => 'cert',
        }) end

        it { expect { should contain_class('nginx::resource::vhost') }.to raise_error(Puppet::Error, %r{nginx: SSL certificate/key \(ssl_cert/ssl_cert\) and/or SSL Private must be defined and exist on the target system\(s\)}) }
      end

      context 'when listen_port != ssl_port' do
        let :params do default_params.merge({
          :listen_port => 80,
          :ssl_port    => 443,
        }) end

        it { should contain_concat__fragment("#{title}-header") }
      end

      context 'when listen_port == ssl_port' do
        let :params do default_params.merge({
          :listen_port => 80,
          :ssl_port    => 80,
        }) end

        it { should_not contain_concat__fragment("#{title}-header") }
      end

      context 'when ssl => true' do
        let :params do default_params.merge({
          :ensure   => 'absent',
          :ssl      => true,
          :ssl_key  => 'dummy.key',
          :ssl_cert => 'dummy.cert',
        }) end

        it { should contain_concat__fragment("#{title}-header") }
        it { should contain_concat__fragment("#{title}-ssl") }
      end

      context 'when ssl => false' do
        let :params do default_params.merge({
          :ensure => 'absent',
          :ssl    => false,
        }) end

        it { should contain_concat__fragment("#{title}-header") }
        it { should_not contain_concat__fragment("#{title}-ssl") }
      end
    end
  end
end
require 'spec_helper'

describe 'nginx::resource::map' do
  let :title do
    'backend_pool'
  end

  let :default_params do
    {
      :string   => '$uri',
      :default  => 'pool_a',
      :mappings => {
        'foo' => 'pool_b',
        'bar' => 'pool_c',
        'baz' => 'pool_d',
      },
    }
  end

  let :facts do
    {
      :osfamily        => 'RedHat',
      :operatingsystem => 'CentOS',
    }
  end

  let :pre_condition do
    [
      'include ::nginx::params',
      'include ::nginx::config',
    ]
  end

  describe 'os-independent items' do
    describe 'basic assumptions' do
      let :params do default_params end

      it { should contain_file("/etc/nginx/conf.d/#{title}-map.conf").with(
        {
          'owner'   => 'root',
          'group'   => 'root',
          'mode'    => '0644',
          'ensure'  => 'file',
          'content' => /map \$uri \$#{title}/,
        }
      )}
    end

    describe "map.conf template content" do
      [
        {
          :title => 'should set hostnames',
          :attr  => 'hostnames',
          :value => true,
          :match => '  hostnames;'
        },
        {
          :title => 'should set default',
          :attr  => 'default',
          :value => 'pool_a',
          :match => [ '  default pool_a;' ],
        },
        {
          :title => 'should contain ordered mappings',
          :attr  => 'mappings',
          :value => {
            'foo' => 'pool_b',
            'bar' => 'pool_c',
            'baz' => 'pool_d',
          },
          :match => [
            '  bar pool_c;',
            '  baz pool_d;',
            '  foo pool_b;',
          ],
        },
      ].each do |param|
        context "when #{param[:attr]} is #{param[:value]}" do
          let :params do default_params.merge({ param[:attr].to_sym => param[:value] }) end

          it { should contain_file("/etc/nginx/conf.d/#{title}-map.conf").with_mode('0644') }
          it param[:title] do
            verify_contents(subject, "/etc/nginx/conf.d/#{title}-map.conf", Array(param[:match]))
            Array(param[:notmatch]).each do |item|
              should contain_file("/etc/nginx/conf.d/#{title}-map.conf").without_content(item)
            end
          end
        end
      end

      context 'when ensure => absent' do
        let :params do default_params.merge(
          {
            :ensure => 'absent'
          }
        ) end

        it { should contain_file("/etc/nginx/conf.d/#{title}-map.conf").with_ensure('absent') }
      end
    end
  end
end
require 'spec_helper'

describe 'nginx::resource::upstream' do
  let :title do
    'upstream-test'
  end

  let :default_params do
    {
      :members => ['test'],
    }
  end

  let :pre_condition do
      [
      'include ::nginx::params',
      'include ::nginx::config',
      ]
  end

  let :default_facts do
    {
      :osfamily        => 'RedHat',
      :operatingsystem => 'CentOS',
      :concat_basedir  => '/var/lib/puppet/concat'
    }
  end

  let :pre_condition do
    [
      'include ::nginx::params',
      'include ::nginx::config',
    ]
  end

  describe 'os-independent items' do
    let :facts do default_facts end

    describe 'basic assumptions' do
      let :params do default_params end

      it { should contain_class("nginx::params") }
      it { should contain_class('concat::setup') }
      it { should contain_file("/etc/nginx/conf.d/#{title}-upstream.conf") }
      it { should contain_concat__fragment("#{title}_upstream_header").with_content(/upstream #{title}/) }

      it {
        should contain_concat__fragment("#{title}_upstream_header").with(
        {
          'target' => "/etc/nginx/conf.d/#{title}-upstream.conf",
          'order'  => 10,
        }
      )}

      it {
        should contain_concat__fragment("#{title}_upstream_members").with(
        {
          'target' => "/etc/nginx/conf.d/#{title}-upstream.conf",
          'order'  => 50,
        }
      )}

      it {
        should contain_concat__fragment("#{title}_upstream_footer").with(
        {
          'target' => "/etc/nginx/conf.d/#{title}-upstream.conf",
          'order'  => 90,
        }).with_content("}\n")
      }
    end

    describe "upstream.conf template content" do
      let :facts do default_facts end
      [
        {
          :title    => 'should contain ordered prepended directives',
          :attr     => 'upstream_cfg_prepend',
          :fragment => 'header',
          :value => {
            'test3' => 'test value 3',
            'test6' => {'subkey1' => ['subvalue1', 'subvalue2']},
            'test1' => 'test value 1',
            'test2' => 'test value 2',
            'test5' => {'subkey1' => 'subvalue1'},
            'test4' => ['test value 1', 'test value 2'],
          },
          :match => [
            '  test1 test value 1;',
            '  test2 test value 2;',
            '  test3 test value 3;',
            '  test4 test value 1;',
            '  test4 test value 2;',
            '  test5 subkey1 subvalue1;',
            '  test6 subkey1 subvalue1;',
            '  test6 subkey1 subvalue2;',
          ],
        },
        {
          :title    => 'should set server',
          :attr     => 'members',
          :fragment => 'members',
          :value    => %W( test3 test1 test2 ),
          :match    => [
            '  server     test3  fail_timeout=10s;',
            '  server     test1  fail_timeout=10s;',
            '  server     test2  fail_timeout=10s;',
          ],
        },
      ].each do |param|
        context "when #{param[:attr]} is #{param[:value]}" do
          let :params do default_params.merge({ param[:attr].to_sym => param[:value] }) end

          it { should contain_file("/etc/nginx/conf.d/#{title}-upstream.conf").with_mode('0644') }
          it { should contain_concat__fragment("#{title}_upstream_#{param[:fragment]}") }
          it param[:title] do
            lines = subject.resource('concat::fragment', "#{title}_upstream_#{param[:fragment]}").send(:parameters)[:content].split("\n")
            (lines & Array(param[:match])).should == Array(param[:match])
            Array(param[:notmatch]).each do |item|
              should contain_concat__fragment("#{title}_upstream_#{param[:fragment]}").without_content(item)
            end
          end
        end
      end

      context 'when ensure => absent' do
        let :params do default_params.merge(
          {
            :ensure => 'absent'
          }
        ) end

        it { should contain_file("/etc/nginx/conf.d/#{title}-upstream.conf").with_ensure('absent') }
      end
    end
  end
end
require 'spec_helper'

describe 'nginx::resource::vhost' do
  let :title do
    'www.rspec.example.com'
  end
  let :default_params do
    {
      :www_root    => '/',
      :ipv6_enable => true,
    }
  end
  let :facts do
    {
      :osfamily        => 'Debian',
      :operatingsystem => 'debian',
      :ipaddress6      => '::',
    }
  end
  let :pre_condition do
    [
      'include ::nginx::params',
      'include ::nginx::config',
    ]
  end

  describe 'os-independent items' do

    describe 'basic assumptions' do
      let :params do default_params end
      it { should contain_class("nginx::params") }
      it { should contain_class("nginx::config") }
      it { should contain_concat("/etc/nginx/sites-available/#{title}.conf").with({
        'owner' => 'root',
        'group' => 'root',
        'mode'  => '0644',
      })}
      it { should contain_concat__fragment("#{title}-header").with_content(%r{access_log[ ]+/var/log/nginx/www\.rspec\.example\.com\.access\.log}) }
      it { should contain_concat__fragment("#{title}-header").with_content(%r{error_log[ ]+/var/log/nginx/www\.rspec\.example\.com\.error\.log}) }
      it { should contain_concat__fragment("#{title}-footer") }
      it { should contain_nginx__resource__location("#{title}-default") }
      it { should_not contain_file("/etc/nginx/fastcgi_params") }
      it { should contain_file("#{title}.conf symlink").with({
        'ensure' => 'link',
        'path'   => "/etc/nginx/sites-enabled/#{title}.conf",
        'target' => "/etc/nginx/sites-available/#{title}.conf"
      })}
    end

    describe "vhost_header template content" do
      [
        {
          :title    => 'should not contain www to non-www rewrite',
          :attr     => 'rewrite_www_to_non_www',
          :value    => false,
          :notmatch => %r|
            ^
            \s+listen\s+\*:443\s+ssl;\n
            \s+server_name\s+www\.rspec\.example\.com;\n
            \s+return\s+301\s+https://rspec\.example\.com\$uri;
          |x,
        },
        {
          :title => 'should contain www to non-www rewrite',
          :attr  => 'rewrite_www_to_non_www',
          :value => true,
          :match => [
            '  listen       *:80;',
            '  server_name  www.rspec.example.com;',
            '  return       301 http://rspec.example.com$uri;',
          ],
        },
        {
          :title => 'should set the IPv4 listen IP',
          :attr  => 'listen_ip',
          :value => '127.0.0.1',
          :match => '  listen                127.0.0.1:80;',
        },
        {
          :title => 'should set the IPv4 listen port',
          :attr  => 'listen_port',
          :value => 45,
          :match => '  listen                *:45;',
        },
        {
          :title => 'should set the IPv4 listen options',
          :attr  => 'listen_options',
          :value => 'spdy default',
          :match => '  listen                *:80 spdy default;',
        },
        {
          :title => 'should enable IPv6',
          :attr  => 'ipv6_enable',
          :value => true,
          :match => '  listen [::]:80 default ipv6only=on;',
        },
        {
          :title    => 'should not enable IPv6',
          :attr     => 'ipv6_enable',
          :value    => false,
          :notmatch => /  listen \[::\]:80 default ipv6only=on;/,
        },
        {
          :title => 'should set the IPv6 listen IP',
          :attr  => 'ipv6_listen_ip',
          :value => '2001:0db8:85a3:0000:0000:8a2e:0370:7334',
          :match => '  listen [2001:0db8:85a3:0000:0000:8a2e:0370:7334]:80 default ipv6only=on;',
        },
        {
          :title => 'should set the IPv6 listen port',
          :attr  => 'ipv6_listen_port',
          :value => 45,
          :match => '  listen [::]:45 default ipv6only=on;',
        },
        {
          :title => 'should set the IPv6 listen options',
          :attr  => 'ipv6_listen_options',
          :value => 'spdy',
          :match => '  listen [::]:80 spdy;',
        },
        {
          :title => 'should set servername(s)',
          :attr  => 'server_name',
          :value => ['www.foo.com','foo.com'],
          :match => '  server_name           www.foo.com foo.com;',
        },
        {
          :title => 'should rewrite www servername to non-www',
          :attr  => 'rewrite_www_to_non_www',
          :value => true,
          :match => '  server_name           rspec.example.com;',
        },
        {
          :title => 'should not rewrite www servername to non-www',
          :attr  => 'rewrite_www_to_non_www',
          :value => false,
          :match => '  server_name           www.rspec.example.com;',
        },
        {
          :title => 'should set auth_basic',
          :attr  => 'auth_basic',
          :value => 'value',
          :match => '  auth_basic           "value";',
        },
        {
          :title => 'should set auth_basic_user_file',
          :attr  => 'auth_basic_user_file',
          :value => 'value',
          :match => '  auth_basic_user_file value;',
        },
        {
          :title => 'should set the client_body_timeout',
          :attr  => 'client_body_timeout',
          :value => 'value',
          :match => /^[ ]+client_body_timeout\s+value;/
        },
        {
          :title => 'should set the client_header_timeout',
          :attr  => 'client_header_timeout',
          :value => 'value',
          :match => /^[ ]+client_header_timeout\s+value;/
        },
        {
          :title => 'should set the gzip_types',
          :attr  => 'gzip_types',
          :value => 'value',
          :match => /^[ ]+gzip_types\s+value;/
        },
        {
          :title => 'should contain raw_prepend directives',
          :attr  => 'raw_prepend',
          :value => [
            'if (a) {',
            '  b;',
            '}'
          ],
          :match => /^\s+if \(a\) {\n\s++b;\n\s+\}/,
        },
        {
          :title => 'should contain ordered prepended directives',
          :attr  => 'vhost_cfg_prepend',
          :value => { 'test1' => ['test value 1a', 'test value 1b'], 'test2' => 'test value 2', 'allow' => 'test value 3' },
          :match => [
            '  allow test value 3;',
            '  test1 test value 1a;',
            '  test1 test value 1b;',
            '  test2 test value 2;',
          ],
        },
        {
          :title => 'should set root',
          :attr  => 'use_default_location',
          :value => false,
          :match => '  root /;',
        },
        {
          :title    => 'should not set root',
          :attr     => 'use_default_location',
          :value    => true,
          :notmatch => /  root \/;/,
        },
        {
          :title => 'should set proxy_set_header',
          :attr  => 'proxy_set_header',
          :value => ['header1','header2'],
          :match => [
            '  proxy_set_header        header1;',
            '  proxy_set_header        header2;',
          ],
        },
        {
          :title => 'should rewrite to HTTPS',
          :attr  => 'rewrite_to_https',
          :value => true,
          :match => [
            '  if ($ssl_protocol = "") {',
            '       return 301 https://$host$request_uri;',
          ],
        },
        {
          :title    => 'should not rewrite to HTTPS',
          :attr     => 'rewrite_to_https',
          :value    => false,
          :notmatch => [
            /if \(\$ssl_protocol = ""\) \{/,
            /       return 301 https:\/\/\$host\$request_uri;/,
          ],
        },
        {
          :title => 'should set access_log',
          :attr  => 'access_log',
          :value => '/path/to/access.log',
          :match => '  access_log            /path/to/access.log;',
        },
        {
          :title => 'should set error_log',
          :attr  => 'error_log',
          :value => '/path/to/error.log',
          :match => '  error_log             /path/to/error.log;',
        },
      ].each do |param|
        context "when #{param[:attr]} is #{param[:value]}" do
          let :params do default_params.merge({ param[:attr].to_sym => param[:value] }) end

          it { should contain_concat__fragment("#{title}-header") }
          it param[:title] do
            matches  = Array(param[:match])

            if matches.all? { |m| m.is_a? Regexp }
              matches.each { |item| should contain_concat__fragment("#{title}-header").with_content(item) }
            else
              lines = subject.resource('concat::fragment', "#{title}-header").send(:parameters)[:content].split("\n")
              (lines & Array(param[:match])).should == Array(param[:match])
            end
            Array(param[:notmatch]).each do |item|
              should contain_concat__fragment("#{title}-header").without_content(item)
            end
          end
        end
      end
    end

    describe "vhost_footer template content" do
      [
        {
          :title    => 'should not contain www to non-www rewrite',
          :attr     => 'rewrite_www_to_non_www',
          :value    => false,
          :notmatch => %r|
            ^
            \s+listen\s+\*:443\s+ssl;\n
            \s+server_name\s+www\.rspec\.example\.com;\n
            \s+return\s+301\s+https://rspec\.example\.com\$uri;
          |x,
        },
        {
          :title => 'should contain include directives',
          :attr  => 'include_files',
          :value => [ '/file1', '/file2' ],
          :match => [
            %r'^[ ]+include\s+/file1;',
            %r'^[ ]+include\s+/file2;',
          ],
        },
        {
          :title => 'should contain ordered appended directives',
          :attr  => 'vhost_cfg_append',
          :value => { 'test1' => 'test value 1', 'test2' => ['test value 2a', 'test value 2b'], 'allow' => 'test value 3' },
          :match => [
            '  allow test value 3;',
            '  test1 test value 1;',
            '  test2 test value 2a;',
            '  test2 test value 2b;',
          ],
        },
        {
          :title => 'should contain raw_append directives',
          :attr  => 'raw_append',
          :value => [
            'if (a) {',
            '  b;',
            '}'
          ],
          :match => /^\s+if \(a\) {\n\s++b;\n\s+\}/,
        },
      ].each do |param|
        context "when #{param[:attr]} is #{param[:value]}" do
          let :params do default_params.merge({ param[:attr].to_sym => param[:value] }) end

          it { should contain_concat__fragment("#{title}-footer") }
          it param[:title] do
            matches  = Array(param[:match])

            if matches.all? { |m| m.is_a? Regexp }
              matches.each { |item| should contain_concat__fragment("#{title}-footer").with_content(item) }
            else
              lines  = subject.resource('concat::fragment', "#{title}-footer").send(:parameters)[:content].split("\n")
              (lines & Array(param[:match])).should == Array(param[:match])
            end
            Array(param[:notmatch]).each do |item|
              should contain_concat__fragment("#{title}-footer").without_content(item)
            end
          end
        end
      end
    end

    describe "vhost_ssl_header template content" do
      [
        {
          :title    => 'should not contain www to non-www rewrite',
          :attr     => 'rewrite_www_to_non_www',
          :value    => false,
          :notmatch => %r|
            ^
            \s+listen\s+\*:443\s+ssl;\n
            \s+server_name\s+www\.rspec\.example\.com;\n
            \s+return\s+301\s+https://rspec\.example\.com\$uri;
          |x,
        },
        {
          :title => 'should contain www to non-www rewrite',
          :attr  => 'rewrite_www_to_non_www',
          :value => true,
          :match => [
            '  listen       *:443 ssl;',
            '  server_name  www.rspec.example.com;',
            '  return       301 https://rspec.example.com$uri;',
          ],
        },
        {
          :title => 'should set the IPv4 listen IP',
          :attr  => 'listen_ip',
          :value => '127.0.0.1',
          :match => '  listen       127.0.0.1:443 ssl;',
        },
        {
          :title => 'should set the IPv4 SSL listen port',
          :attr  => 'ssl_port',
          :value => 45,
          :match => '  listen       *:45 ssl;',
        },
        {
          :title => 'should set SPDY',
          :attr  => 'spdy',
          :value => 'on',
          :match => '  listen       *:443 ssl spdy;',
        },
        {
          :title => 'should not set SPDY',
          :attr  => 'spdy',
          :value => 'off',
          :match => '  listen       *:443 ssl;',
        },
        {
          :title => 'should set the IPv4 listen options',
          :attr  => 'listen_options',
          :value => 'default',
          :match => '  listen       *:443 ssl default;',
        },
        {
          :title => 'should enable IPv6',
          :attr  => 'ipv6_enable',
          :value => true,
          :match => '  listen [::]:443 ssl default ipv6only=on;',
        },
        {
          :title    => 'should disable IPv6',
          :attr     => 'ipv6_enable',
          :value    => false,
          :notmatch => /  listen \[::\]:443 ssl default ipv6only=on;/,
        },
        {
          :title => 'should set the IPv6 listen IP',
          :attr  => 'ipv6_listen_ip',
          :value => '2001:0db8:85a3:0000:0000:8a2e:0370:7334',
          :match => '  listen [2001:0db8:85a3:0000:0000:8a2e:0370:7334]:443 ssl default ipv6only=on;',
        },
        {
          :title => 'should set the IPv6 listen port',
          :attr  => 'ssl_port',
          :value => 45,
          :match => '  listen [::]:45 ssl default ipv6only=on;',
        },
        {
          :title => 'should set the IPv6 listen options',
          :attr  => 'ipv6_listen_options',
          :value => 'spdy default',
          :match => '  listen [::]:443 ssl spdy default;',
        },
        {
          :title => 'should set servername(s)',
          :attr  => 'server_name',
          :value => ['www.foo.com','foo.com'],
          :match => '  server_name  www.foo.com foo.com;',
        },
        {
          :title => 'should rewrite www servername to non-www',
          :attr  => 'rewrite_www_to_non_www',
          :value => true,
          :match => '  server_name  rspec.example.com;',
        },
        {
          :title => 'should not rewrite www servername to non-www',
          :attr  => 'rewrite_www_to_non_www',
          :value => false,
          :match => '  server_name  www.rspec.example.com;',
        },
        {
          :title => 'should set the SSL cache',
          :attr  => 'ssl_cache',
          :value => 'shared:SSL:1m',
          :match => '  ssl_session_cache         shared:SSL:1m;',
        },
        {
          :title => 'should set the SSL protocols',
          :attr  => 'ssl_protocols',
          :value => 'SSLv3',
          :match => '  ssl_protocols             SSLv3;',
        },
        {
          :title => 'should set the SSL ciphers',
          :attr  => 'ssl_ciphers',
          :value => 'HIGH',
          :match => '  ssl_ciphers               HIGH;',
        },
        {
          :title => 'should set auth_basic',
          :attr  => 'auth_basic',
          :value => 'value',
          :match => '  auth_basic                "value";',
        },
        {
          :title => 'should set auth_basic_user_file',
          :attr  => 'auth_basic_user_file',
          :value => 'value',
          :match => '  auth_basic_user_file      "value";',
        },
        {
          :title => 'should set the client_body_timeout',
          :attr  => 'client_body_timeout',
          :value => 'value',
          :match => /^[ ]+client_body_timeout\s+value;/
        },
        {
          :title => 'should set the client_header_timeout',
          :attr  => 'client_header_timeout',
          :value => 'value',
          :match => /^[ ]+client_header_timeout\s+value;/
        },
        {
          :title => 'should set the gzip_types',
          :attr  => 'gzip_types',
          :value => 'value',
          :match => /^[ ]+gzip_types\s+value;/
        },
        {
          :title => 'should set access_log',
          :attr  => 'access_log',
          :value => '/path/to/access.log',
          :match => '  access_log            /path/to/access.log;',
        },
        {
          :title => 'should set error_log',
          :attr  => 'error_log',
          :value => '/path/to/error.log',
          :match => '  error_log             /path/to/error.log;',
        },
        {
          :title => 'should contain raw_prepend directives',
          :attr  => 'raw_prepend',
          :value => [
            'if (a) {',
            '  b;',
            '}'
          ],
          :match => /^\s+if \(a\) {\n\s++b;\n\s+\}/,
        },
        {
          :title => 'should contain ordered prepend directives',
          :attr  => 'vhost_cfg_prepend',
          :value => { 'test1' => 'test value 1', 'test2' => ['test value 2a', 'test value 2b'], 'allow' => 'test value 3' },
          :match => [
            '  allow test value 3;',
            '  test1 test value 1;',
            '  test2 test value 2a;',
            '  test2 test value 2b;',
          ]
        },
        {
          :title => 'should contain ordered ssl prepend directives',
          :attr  => 'vhost_cfg_ssl_prepend',
          :value => { 'test1' => 'test value 1', 'test2' => ['test value 2a', 'test value 2b'], 'allow' => 'test value 3' },
          :match => [
            '  allow test value 3;',
            '  test1 test value 1;',
            '  test2 test value 2a;',
            '  test2 test value 2b;',
          ]
        },
        {
          :title => 'should set root',
          :attr  => 'use_default_location',
          :value => false,
          :match => '  root /;',
        },
        {
          :title    => 'should not set root',
          :attr     => 'use_default_location',
          :value    => true,
          :notmatch => /  root \/;/,
        },
      ].each do |param|
        context "when #{param[:attr]} is #{param[:value]}" do
          let :params do default_params.merge({
            param[:attr].to_sym => param[:value],
            :ssl                => true,
            :ssl_key            => 'dummy.key',
            :ssl_cert           => 'dummy.crt',
          }) end
          it { should contain_concat__fragment("#{title}-ssl-header") }
          it param[:title] do
            matches  = Array(param[:match])

            if matches.all? { |m| m.is_a? Regexp }
              matches.each { |item| should contain_concat__fragment("#{title}-ssl-header").with_content(item) }
            else
              lines = subject.resource('concat::fragment', "#{title}-ssl-header").send(:parameters)[:content].split("\n")
              (lines & Array(param[:match])).should == Array(param[:match])
            end
            Array(param[:notmatch]).each do |item|
              should contain_concat__fragment("#{title}-ssl-header").without_content(item)
            end
          end
        end
      end
    end

    describe "vhost_ssl_footer template content" do
      [
        {
          :title    => 'should not contain www to non-www rewrite',
          :attr     => 'rewrite_www_to_non_www',
          :value    => false,
          :notmatch => %r|
            ^
            \s+listen\s+\*:443\s+ssl;\n
            \s+server_name\s+www\.rspec\.example\.com;\n
            \s+return\s+301\s+https://rspec\.example\.com\$uri;
          |x,
        },
        {
          :title => 'should contain include directives',
          :attr  => 'include_files',
          :value => [ '/file1', '/file2' ],
          :match => [
            %r'^[ ]+include\s+/file1;',
            %r'^[ ]+include\s+/file2;',
          ],
        },
        {
          :title => 'should contain ordered appended directives',
          :attr  => 'vhost_cfg_append',
          :value => { 'test1' => 'test value 1', 'test2' => 'test value 2', 'allow' => 'test value 3' },
          :match => [
            '  allow test value 3;',
            '  test1 test value 1;',
            '  test2 test value 2;',
          ]
        },
        {
          :title => 'should contain raw_append directives',
          :attr  => 'raw_append',
          :value => [
            'if (a) {',
            '  b;',
            '}'
          ],
          :match => /^\s+if \(a\) {\n\s++b;\n\s+\}/,
        },
        {
          :title => 'should contain ordered ssl appended directives',
          :attr  => 'vhost_cfg_ssl_append',
          :value => { 'test1' => 'test value 1', 'test2' => ['test value 2a', 'test value 2b'], 'allow' => 'test value 3' },
          :match => [
            '  allow test value 3;',
            '  test1 test value 1;',
            '  test2 test value 2a;',
            '  test2 test value 2b;',
          ]
        },
      ].each do |param|
        context "when #{param[:attr]} is #{param[:value]}" do
          let :params do default_params.merge({
            param[:attr].to_sym => param[:value],
            :ssl                => true,
            :ssl_key            => 'dummy.key',
            :ssl_cert           => 'dummy.crt',
          }) end

          it { should contain_concat__fragment("#{title}-ssl-footer") }
          it param[:title] do
            matches  = Array(param[:match])

            if matches.all? { |m| m.is_a? Regexp }
              matches.each { |item| should contain_concat__fragment("#{title}-ssl-footer").with_content(item) }
            else
              lines = subject.resource('concat::fragment', "#{title}-ssl-footer").send(:parameters)[:content].split("\n")
              (lines & Array(param[:match])).should == Array(param[:match])
            end
            Array(param[:notmatch]).each do |item|
              should contain_concat__fragment("#{title}-ssl-footer").without_content(item)
            end
          end
        end
      end
    end

    context 'attribute resources' do
      context "with SSL enabled, www rewrite to naked domain with multiple server_names" do
        let :title do 'foo.com' end
        let(:params) do
          {
            :ssl                    => true,
            :ssl_cert               => 'cert',
            :ssl_key                => 'key',
            :server_name            => %w(www.foo.com bar.foo.com foo.com),
            :use_default_location   => false,
            :rewrite_www_to_non_www => true,
          }
        end

        it "should set the server_name of the rewrite server stanza to the first server_name with 'www.' stripped" do
          should contain_concat__fragment("#{title}-ssl-header").with_content(/^[ ]+server_name\s+foo.com;/)
        end
      end

      context "with SSL disabled, www rewrite to naked domain with multiple server_names" do
        let :title do 'foo.com' end
        let(:params) do
          {
            :server_name            => %w(www.foo.com bar.foo.com foo.com),
            :use_default_location   => false,
            :rewrite_www_to_non_www => true,
          }
        end

        it "should set the server_name of the rewrite server stanza to the first server_name with 'www.' stripped" do
          should contain_concat__fragment("#{title}-header").with_content(/^[ ]+server_name\s+foo.com;/)
        end
      end

      context "SSL cert missing" do
        let(:params) {{ :ssl => true, :ssl_key => 'key' }}

        it { expect { should contain_class('nginx::resource::vhost') }.to raise_error(Puppet::Error) }
      end

      context "SSL key missing" do
        let(:params) {{ :ssl => true, :ssl_cert => 'cert' }}

        it { expect { should contain_class('nginx::resource::vhost') }.to raise_error(Puppet::Error) }
      end

      context 'when use_default_location => true' do
        let :params do default_params.merge({
          :use_default_location => true,
        }) end

        it { should contain_nginx__resource__location("#{title}-default") }
      end

      context 'when use_default_location => false' do
        let :params do default_params.merge({
          :use_default_location => false,
        }) end

        it { should_not contain_nginx__resource__location("#{title}-default") }
      end

      context 'when location_cfg_prepend => { key => value }' do
        let :params do default_params.merge({
          :location_cfg_prepend => { 'key' => 'value' },
        }) end

        it { should contain_nginx__resource__location("#{title}-default").with_location_cfg_prepend({ 'key' => 'value' }) }
      end

      context "when location_raw_prepend => [ 'foo;' ]" do
        let :params do default_params.merge({
          :location_raw_prepend => [ 'foo;' ],
        }) end

        it { should contain_nginx__resource__location("#{title}-default").with_raw_prepend([ 'foo;' ]) }
      end

      context "when location_raw_append => [ 'foo;' ]" do
        let :params do default_params.merge({
          :location_raw_append => [ 'foo;' ],
        }) end

        it { should contain_nginx__resource__location("#{title}-default").with_raw_append([ 'foo;' ]) }
      end

      context 'when location_cfg_append => { key => value }' do
        let :params do default_params.merge({
          :location_cfg_append => { 'key' => 'value' },
        }) end

        it { should contain_nginx__resource__location("#{title}-default").with_location_cfg_append({ 'key' => 'value' }) }
      end

      context 'when fastcgi => "localhost:9000"' do
        let :params do default_params.merge({
          :fastcgi => 'localhost:9000',
        }) end

        it { should contain_file('/etc/nginx/fastcgi_params').with_mode('0770') }
      end

      context 'when listen_port == ssl_port' do
        let :params do default_params.merge({
          :listen_port => 80,
          :ssl_port    => 80,
        }) end

        it { should_not contain_concat__fragment("#{title}-header") }
        it { should_not contain_concat__fragment("#{title}-footer") }
      end

      context 'when listen_port != ssl_port' do
        let :params do default_params.merge({
          :listen_port => 80,
          :ssl_port    => 443,
        }) end

        it { should contain_concat__fragment("#{title}-header") }
        it { should contain_concat__fragment("#{title}-footer") }
      end

      context 'when ensure => absent' do
        let :params do default_params.merge({
          :ensure   => 'absent',
          :ssl      => true,
          :ssl_key  => 'dummy.key',
          :ssl_cert => 'dummy.cert',
        }) end

        it { should contain_nginx__resource__location("#{title}-default").with_ensure('absent') }
        it { should contain_file("#{title}.conf symlink").with_ensure('absent') }
      end

      context 'when ssl => true and ssl_port == listen_port' do
        let :params do default_params.merge({
          :ssl         => true,
          :listen_port => 80,
          :ssl_port    => 80,
          :ssl_key     => 'dummy.key',
          :ssl_cert    => 'dummy.cert',
        }) end

        it { should contain_nginx__resource__location("#{title}-default").with_ssl_only(true) }
        it { should contain_concat__fragment("#{title}-ssl-header").with_content(%r{access_log[ ]+/var/log/nginx/ssl-www\.rspec\.example\.com\.access\.log}) }
        it { should contain_concat__fragment("#{title}-ssl-header").with_content(%r{error_log[ ]+/var/log/nginx/ssl-www\.rspec\.example\.com\.error\.log}) }
        it { should contain_concat__fragment("#{title}-ssl-footer") }
        it { should contain_file("/etc/nginx/#{title}.crt") }
        it { should contain_file("/etc/nginx/#{title}.key") }
      end

      context 'when passenger_cgi_param is set' do
        let :params do default_params.merge({
          :passenger_cgi_param => { 'test1' => 'test value 1', 'test2' => 'test value 2', 'test3' => 'test value 3' }
        }) end

        it { should contain_concat__fragment("#{title}-header").with_content( /passenger_set_cgi_param  test1 test value 1;/ ) }
        it { should contain_concat__fragment("#{title}-header").with_content( /passenger_set_cgi_param  test2 test value 2;/ ) }
        it { should contain_concat__fragment("#{title}-header").with_content( /passenger_set_cgi_param  test3 test value 3;/ ) }
      end

      context 'when passenger_cgi_param is set and ssl => true' do
        let :params do default_params.merge({
          :passenger_cgi_param => { 'test1' => 'test value 1', 'test2' => 'test value 2', 'test3' => 'test value 3' },
          :ssl                 => true,
          :ssl_key             => 'dummy.key',
          :ssl_cert            => 'dummy.cert',
        }) end

        it { should contain_concat__fragment("#{title}-ssl-header").with_content( /passenger_set_cgi_param  test1 test value 1;/ ) }
        it { should contain_concat__fragment("#{title}-ssl-header").with_content( /passenger_set_cgi_param  test2 test value 2;/ ) }
        it { should contain_concat__fragment("#{title}-ssl-header").with_content( /passenger_set_cgi_param  test3 test value 3;/ ) }
      end

      context 'when vhost name is sanitized' do
        let :title do 'www rspec-vhost com' end
        let :params do default_params end

        it { should contain_concat('/etc/nginx/sites-available/www_rspec-vhost_com.conf') }
      end
    end
  end
end
require 'puppetlabs_spec_helper/module_spec_helper'

RSpec.configure do |c|
  c.default_facts = {
    :kernel          => 'Linux',
    :concat_basedir  => '/var/lib/puppet/concat',
  }
end
require 'rspec-system/spec_helper'
require 'rspec-system-puppet/helpers'
require 'rspec-system-serverspec/helpers'
include RSpecSystemPuppet::Helpers

RSpec.configure do |c|
  # Project root
  proj_root = File.expand_path(File.join(File.dirname(__FILE__), '..'))

  # Enable colour
  c.tty = true

  # This is where we 'setup' the nodes before running our tests
  c.before :suite do
    # Install puppet
    puppet_install

    # Install modules and dependencies
    puppet_module_install(:source => proj_root, :module_name => 'nginx')
    shell('puppet module install puppetlabs-apt')
    shell('puppet module install puppetlabs-stdlib')
    shell('puppet module install puppetlabs-concat')

    # Fake keys.
    # Valid self-signed SSL key with 10 year expiry.
    # Required for nginx to start when SSL enabled
    shell('echo "-----BEGIN PRIVATE KEY-----
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAOPchwRZRF4KmU6E
g7C6Pq9zhdLiQt9owdcLZNiZS+UVRQjeDHSy3titzh5YwSoQonlnSqd0g/PJ6kNA
O3CNOMVuzAddnAaHzW1J4Rt6sZwOuidtJC4t/hFCgz5NqOMgYOOfratQx00A7ZXK
TXMgNG79lDP5L/N06Ox53sOxhy4hAgMBAAECgYEAlfktCKi0fe0d8Hb5slUzMwmn
GCECAMeTZbXDH2jucg4ozOhRbHHaiOUEmCa0pLokJiHdGhBvVQMd5Dufo7nflZzE
mpZY0lCZE7HSeK6Bcbru/8w3vm3iBQTGK+MCaDtH5nQU7m/3cOXaenOX0ZmsTzRs
QE/V84S1fuO8bBPSz20CQQD9d4LxrBByosFxRdHsTb/nnqx/rzLEf4M3MC7uydPv
fDDbSRRSYpNxonQJfU3JrOk1WPWoXY30VQCv395s57X7AkEA5iOBT+ME8/PxuUUC
ZDjg21tAdkaiCQ5kgeVTmkD1k/gTwreOV2AexWGrrcW/MLaIhpDCpQkw37y5vrYw
UyDdkwJAAU+j8sIUF7O10nMtAc7pJjaQ59wtJA0QzbFHHN8YZI285vV60G5IGvdf
KElopJlrX2ZFZwiM2m2yIjbDPMb6DwJAbNoiUbzZHOInVTA0316fzGEu7kKeZZYv
J9lmX7GV9nUCM7lKVD2ckFOQNlMwCURs8ukJh7H/MfQ8Dt5xoQAMjQJBAOWpK6k6
b0fTREZFZRGZBJcSu959YyMzhpSFA+lXkLNTWX8j1/D88H731oMSImoQNWcYx2dH
sCwOCDqu1nZ2LJ8=
    shell('echo "-----BEGIN CERTIFICATE-----
MIIDRjCCAq+gAwIBAgIJAL9m0V4sHW2tMA0GCSqGSIb3DQEBBQUAMIG7MQswCQYD
VQQGEwItLTESMBAGA1UECAwJU29tZVN0YXRlMREwDwYDVQQHDAhTb21lQ2l0eTEZ
MBcGA1UECgwQU29tZU9yZ2FuaXphdGlvbjEfMB0GA1UECwwWU29tZU9yZ2FuaXph
dGlvbmFsVW5pdDEeMBwGA1UEAwwVbG9jYWxob3N0LmxvY2FsZG9tYWluMSkwJwYJ
KoZIhvcNAQkBFhpyb290QGxvY2FsaG9zdC5sb2NhbGRvbWFpbjAeFw0xMzExMzAw
NzA3NDlaFw0yMzExMjgwNzA3NDlaMIG7MQswCQYDVQQGEwItLTESMBAGA1UECAwJ
U29tZVN0YXRlMREwDwYDVQQHDAhTb21lQ2l0eTEZMBcGA1UECgwQU29tZU9yZ2Fu
aXphdGlvbjEfMB0GA1UECwwWU29tZU9yZ2FuaXphdGlvbmFsVW5pdDEeMBwGA1UE
AwwVbG9jYWxob3N0LmxvY2FsZG9tYWluMSkwJwYJKoZIhvcNAQkBFhpyb290QGxv
Y2FsaG9zdC5sb2NhbGRvbWFpbjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
49yHBFlEXgqZToSDsLo+r3OF0uJC32jB1wtk2JlL5RVFCN4MdLLe2K3OHljBKhCi
eWdKp3SD88nqQ0A7cI04xW7MB12cBofNbUnhG3qxnA66J20kLi3+EUKDPk2o4yBg
45+tq1DHTQDtlcpNcyA0bv2UM/kv83To7Hnew7GHLiECAwEAAaNQME4wHQYDVR0O
BBYEFP5Kkot/7pStLaYPtT+vngE0v6N8MB8GA1UdIwQYMBaAFP5Kkot/7pStLaYP
tT+vngE0v6N8MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAwYYQKVRN
HaHIWGMBuXApE7t4PNdYWZ5Y56tI+HT59yVoDjc1YSnuzkKlWUPibVYoLpX/ROKr
aIZ8kxsBjLvpi9KQTHi7Wl6Sw3ecoYdKy+2P8S5xOIpWjs8XVmOWf7Tq1+9KPv3z
HLw/FDCzntkdq3G4em15CdFlO9BTY4HXiHU=
  end
end
require 'spec_helper_system'

# Here we put the more basic fundamental tests, ultra obvious stuff.
describe "basic tests:" do
  context 'make sure we have copied the module across' do
    # No point diagnosing any more if the module wasn't copied properly
    context shell 'ls /etc/puppet/modules/nginx' do
      its(:stdout) { should =~ /Modulefile/ }
      its(:stderr) { should be_empty }
      its(:exit_code) { should be_zero }
    end
  end

  #puppet smoke test
  context puppet_apply 'notice("foo")' do
    its(:stdout) { should =~ /foo/ }
    its(:stderr) { should be_empty }
    its(:exit_code) { should be_zero }
  end

  it 'nginx class should work with no errors' do
    pp = <<-EOS
      class { 'nginx': }
    EOS

    # Run it twice and test for idempotency
    puppet_apply(pp) do |r|
      [0,2].should include(r.exit_code)
      r.refresh
      r.exit_code.should be_zero
    end
  end
end
require 'spec_helper_system'

describe "nginx class:" do
  case node.facts['osfamily']
  when 'RedHat'
    package_name = 'nginx'
  when 'Debian'
    package_name = 'nginx'
  when 'Suse'
    package_name = 'nginx-0.8'
  end

  context 'should run successfully' do
    it 'should run successfully' do
      pp = "class { 'nginx': }"

      puppet_apply(pp) do |r|
        #r.stderr.should be_empty
        [0,2].should include r.exit_code
        r.refresh
        #r.stderr.should be_empty
        r.exit_code.should be_zero
      end
    end
  end

  describe package(package_name) do
    it { should be_installed }
  end

  describe service('nginx') do
    it { should be_running }
  end

end
require 'spec_helper_system'

describe "nginx::resource::mailhost define:" do
  it 'should run successfully' do

    pp = "
    class { 'nginx':
      mail => true,
    }
    nginx::resource::vhost { 'www.puppetlabs.com':
      ensure   => present,
      www_root => '/var/www/www.puppetlabs.com',
    }
    nginx::resource::mailhost { 'domain1.example':
      ensure      => present,
      auth_http   => 'localhost/cgi-bin/auth',
      protocol    => 'smtp',
      listen_port => 587,
      ssl_port    => 465,
      xclient     => 'off',
    }
    "

    puppet_apply(pp) do |r|
      [0,2].should include r.exit_code
      r.refresh
      # Not until deprecated variables fixed.
      #r.stderr.should be_empty
      r.exit_code.should be_zero
    end
  end

  describe file('/etc/nginx/conf.mail.d/domain1.example.conf') do
   it { should be_file }
   it { should contain "auth_http             localhost/cgi-bin/auth;" }
  end

  describe file('/etc/nginx/sites-available/www.puppetlabs.com.conf') do
    it { should be_file }
  end

end
require 'spec_helper_system'

describe "nginx::resource::upstream define:" do
  it 'should run successfully' do

    pp = "
    class { 'nginx': }
    nginx::resource::upstream { 'puppet_rack_app':
      ensure  => present,
      members => [
        'localhost:3000',
        'localhost:3001',
        'localhost:3002',
      ],
    }
    nginx::resource::vhost { 'rack.puppetlabs.com':
      ensure => present,
      proxy  => 'http://puppet_rack_app',
    }
    "

    puppet_apply(pp) do |r|
      [0,2].should include r.exit_code
      r.refresh
      r.stderr.should be_empty
      r.exit_code.should be_zero
    end
  end

  describe file('/etc/nginx/conf.d/puppet_rack_app-upstream.conf') do
   it { should be_file }
   it { should contain "server     localhost:3000" }
   it { should contain "server     localhost:3001" }
   it { should contain "server     localhost:3002" }
   it { should_not contain "server     localhost:3003" }
  end

  describe file('/etc/nginx/sites-available/rack.puppetlabs.com.conf') do
    it { should be_file }
    it { should contain "proxy_pass          http://puppet_rack_app;" }
  end

end
require 'spec_helper_system'

describe "nginx::resource::vhost define:" do
  context 'new vhost on port 80' do
    it 'should configure a nginx vhost' do

      pp = "
      class { 'nginx': }
      nginx::resource::vhost { 'www.puppetlabs.com':
        ensure   => present,
        www_root => '/var/www/www.puppetlabs.com',
      }
      host { 'www.puppetlabs.com': ip => '127.0.0.1', }
      file { ['/var/www','/var/www/www.puppetlabs.com']: ensure => directory }
      file { '/var/www/www.puppetlabs.com/index.html': ensure  => file, content => 'Hello from www\n', }
      "

      puppet_apply(pp) do |r|
        [0,2].should include r.exit_code
        r.refresh
        r.stderr.should be_empty
        r.exit_code.should be_zero
      end
    end

    describe file('/etc/nginx/sites-available/www.puppetlabs.com.conf') do
      it { should be_file }
      it { should contain "www.puppetlabs.com" }
    end

    describe file('/etc/nginx/sites-enabled/www.puppetlabs.com.conf') do
      it { should be_linked_to '/etc/nginx/sites-available/www.puppetlabs.com.conf' }
    end

    describe service('nginx') do
      it { should be_running }
    end

    it 'should answer to www.puppetlabs.com' do
      shell("/usr/bin/curl http://www.puppetlabs.com:80") do |r|
        r.stdout.should == "Hello from www\n"
        r.exit_code.should be_zero
      end
    end
  end

  context 'should run successfully with ssl' do
    it 'should configure a nginx SSL vhost' do

      pp = "
      class { 'nginx': }
      nginx::resource::vhost { 'www.puppetlabs.com':
        ensure   => present,
        ssl      => true,
        ssl_cert => '/tmp/blah.cert',
        ssl_key  => '/tmp/blah.key',
        www_root => '/var/www/www.puppetlabs.com',
      }
      host { 'www.puppetlabs.com': ip => '127.0.0.1', }
      file { ['/var/www','/var/www/www.puppetlabs.com']: ensure => directory }
      file { '/var/www/www.puppetlabs.com/index.html': ensure  => file, content => 'Hello from www\n', }
      "

      puppet_apply(pp) do |r|
        [0,2].should include r.exit_code
        r.refresh
        r.stderr.should be_empty
        r.exit_code.should be_zero
      end
    end

    describe file('/etc/nginx/sites-available/www.puppetlabs.com.conf') do
      it { should be_file }
      it { should contain "ssl on;" }
    end

    describe file('/etc/nginx/sites-enabled/www.puppetlabs.com.conf') do
      it { should be_linked_to '/etc/nginx/sites-available/www.puppetlabs.com.conf' }
    end

    describe service('nginx') do
      it { should be_running }
    end

    it 'should answer to http://www.puppetlabs.com' do
      shell("/usr/bin/curl http://www.puppetlabs.com:80") do |r|
        r.stdout.should == "Hello from www\n"
        r.exit_code.should == 0
      end
    end

    it 'should answer to https://www.puppetlabs.com' do
      # use --insecure because it's a self-signed cert
      shell("/usr/bin/curl --insecure https://www.puppetlabs.com:443") do |r|
        r.stdout.should == "Hello from www\n"
        r.exit_code.should == 0
      end
    end
  end
end
<%
  # sorting ip addresses in ascending order is more efficient for nginx - so we need
  # to convert them to numbers first via IPAddr
  require 'ipaddr'
-%>
geo <%= @address ? "#{@address} " : '' %>$<%= @name %> {
<% if @ranges -%>
  ranges;
<% end -%>
<% if @default -%>
  default <%= @default %>;
<% end -%>
<% if @delete -%>
  delete <%= @delete %>;
<% end -%>
<% if @proxies -%>
  <%- [@proxies].flatten.each do |proxy| -%>
  proxy <%= proxy %>;
  <%- end -%>
<% end -%>
<% if @proxy_recursive && @proxies -%>
  proxy_recursive;
<% end -%>
<% if @networks -%>
  <%- @networks.sort_by{|k,v| IPAddr.new(k.split('-').first).to_i }.each do |key,value| -%>
  <%= key %> <%= value %>;
  <%- end -%>
<% end -%>
}
map <%= @string %> $<%= @name %> {
<% if @hostnames -%>
  hostnames;
<% end -%>
<% if @default -%>
  default <%= @default %>;
<% end -%>
<% if @mappings -%>
  <%- @mappings.sort_by{|k,v| k}.each do |key,value| -%>
  <%= key %> <%= value %>;
  <%- end -%>
<% end -%>
}
<% if @super_user -%>
user <%= @daemon_user %>;
<% end -%>
worker_processes <%= @worker_processes %>;
<% if @worker_rlimit_nofile %>worker_rlimit_nofile <%= @worker_rlimit_nofile %>;<% end -%>

error_log  <%= @nginx_error_log %>;
<% if @pid -%>
pid        <%= @pid %>;
<% end -%>

events {
  worker_connections <%= @worker_connections -%>;
  <% if @multi_accept == 'on' -%>
    multi_accept on;
  <% end -%>
  <% if @events_use -%>
    use <%= @events_use %>;
  <% end -%>
}

http {
  include       <%= @conf_dir %>/mime.types;
  default_type  application/octet-stream;

  access_log  <%= @http_access_log %>;

<% if @sendfile == 'on' -%>
  sendfile    on;
<% if @http_tcp_nopush == 'on' -%>
  tcp_nopush on;
<% end -%>
<% end -%>

  server_tokens <%= @server_tokens %>;

  types_hash_max_size <%= @types_hash_max_size %>;
  types_hash_bucket_size <%= @types_hash_bucket_size %>;

  server_names_hash_bucket_size <%= @names_hash_bucket_size %>;
  server_names_hash_max_size <%= @names_hash_max_size %>;

  keepalive_timeout  <%= @keepalive_timeout %>;
  tcp_nodelay        <%= @http_tcp_nodelay %>;

<% if @gzip == 'on' -%>
  gzip         on;
  gzip_disable "MSIE [1-6]\.(?!.*SV1)";
<% end -%>

<% if @proxy_cache_path -%>
  proxy_cache_path    <%= @proxy_cache_path %> levels=<%= @proxy_cache_levels %> keys_zone=<%= @proxy_cache_keys_zone %> max_size=<%= @proxy_cache_max_size %> inactive=<%= @proxy_cache_inactive %>;
<% end -%>

<% if @fastcgi_cache_path -%>
  fastcgi_cache_path    	<%= @fastcgi_cache_path %> levels=<%= @fastcgi_cache_levels %> keys_zone=<%= @fastcgi_cache_keys_zone %> max_size=<%= @fastcgi_cache_max_size %> inactive=<%= @fastcgi_cache_inactive %>;
<% end -%>
<% if @fastcgi_cache_key -%>
  fastcgi_cache_key		<%= @fastcgi_cache_key %>;
<% end -%>
<% if @fastcgi_cache_use_stale -%>
  fastcgi_cache_use_stale 	<%= @fastcgi_cache_use_stale %>;
<% end -%>

<% if @http_cfg_append -%><% @http_cfg_append.sort_by{|k,v| k}.each do |key,value| -%>
  <%= key %> <%= value %>;
<% end -%>
<% end -%>

  include <%= @conf_dir %>/conf.d/*.conf;
  include <%= @conf_dir %>/sites-enabled/*;

}
<% if @mail -%>
mail {
  include <%= @conf_dir %>/conf.mail.d/*.conf;
}
<% end -%>
proxy_temp_path         <%= @proxy_temp_path %>;
client_body_temp_path   <%= @client_body_temp_path %>;
proxy_redirect          <%= @proxy_redirect %>;
client_max_body_size    <%= @client_max_body_size %>;
client_body_buffer_size <%= @client_body_buffer_size %>;
proxy_connect_timeout   <%= @proxy_connect_timeout %>;
proxy_send_timeout      <%= @proxy_send_timeout %>;
proxy_read_timeout      <%= @proxy_read_timeout %>;
proxy_buffers           <%= @proxy_buffers %>;
proxy_buffer_size       <%= @proxy_buffer_size %>;
proxy_http_version      <%= @proxy_http_version %>;
<% @proxy_set_header.each do |header| %>
proxy_set_header        <%= header %>;<% end %>
proxy_headers_hash_bucket_size <%= @proxy_headers_hash_bucket_size %>;
upstream <%= @name %> {
<% if @upstream_cfg_prepend -%><% @upstream_cfg_prepend.sort_by{|k,v| k}.each do |key,value| %>
<% if value.is_a?(Hash) -%><% value.each do |subkey,subvalue| -%>
<% Array(subvalue).each do |asubvalue| -%>
  <%= key %> <%= subkey %> <%= asubvalue %>;
<% end -%>
<% end -%><% else -%>
<% Array(value).each do |asubvalue| -%>
  <%= key %> <%= asubvalue %>;
<% end -%>
<% end -%>
<% end -%><% end -%>
  server     <%= @server %>:<%= @port %>  fail_timeout=<%= @upstream_fail_timeout %>;
  <% @members.each do |i| %>
  server     <%= i %>  fail_timeout=<%= @upstream_fail_timeout %>;<% end %>

server {
  listen                <%= @listen_ip %>:<%= @listen_port %><% if @listen_options %> <%= @listen_options %><% end %>;
  <% # check to see if ipv6 support exists in the kernel before applying %>
  <% if @ipv6_enable && (defined? @ipaddress6) %>
  listen [<%= @ipv6_listen_ip %>]:<%= @ipv6_listen_port %><% if @ipv6_listen_options %> <%= @ipv6_listen_options %><% end %>;
  <% end %>
  server_name           <%= @server_name.join(" ") %>;
  protocol              <%= @protocol %>;
  xclient               <%= @xclient %>;
  auth_http             <%= @auth_http %>;
  starttls              <%= @starttls %>;
  <% if @starttls == 'on' || @starttls == 'only' %>
  ssl_certificate      <%= @ssl_cert %>;
  ssl_certificate_key  <%= @ssl_key %>;

  ssl_session_timeout  5m;

  ssl_protocols  SSLv3 TLSv1;
  ssl_ciphers  ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv3:+EXP;
  ssl_prefer_server_ciphers   on;
  <%- end -%>
}

server {
  listen       <%= @ssl_port %>;
  <% # check to see if ipv6 support exists in the kernel before applying %>
  <% if @ipv6_enable && (defined? @ipaddress6) %>
  listen [<%= @ipv6_listen_ip %>]:<%= @ipv6_listen_port %> <% if @ipv6_listen_options %><%= @ipv6_listen_options %><% end %>;
  <% end %>
  server_name           <%= @server_name.join(" ") %>;
  protocol              <%= @protocol %>;
  xclient               <%= @xclient %>;
  auth_http             <%= @auth_http %>;

  ssl on;
  ssl_certificate      <%= @ssl_cert %>;
  ssl_certificate_key  <%= @ssl_key %>;

  ssl_session_timeout  5m;

  ssl_protocols  SSLv3 TLSv1;
  ssl_ciphers  ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv3:+EXP;
  ssl_prefer_server_ciphers   on;

}
# This file managed by puppet on host <%= @fqdn %>

fastcgi_param	QUERY_STRING		  $query_string;
fastcgi_param	REQUEST_METHOD	  $request_method;
fastcgi_param	CONTENT_TYPE		  $content_type;
fastcgi_param	CONTENT_LENGTH	  $content_length;

fastcgi_param	SCRIPT_FILENAME	  $request_filename;
fastcgi_param	SCRIPT_NAME		    $fastcgi_script_name;
fastcgi_param	REQUEST_URI		    $request_uri;
fastcgi_param	DOCUMENT_URI		  $document_uri;
fastcgi_param	DOCUMENT_ROOT		  $document_root;
fastcgi_param	SERVER_PROTOCOL	  $server_protocol;

fastcgi_param	GATEWAY_INTERFACE	CGI/1.1;
fastcgi_param	SERVER_SOFTWARE		nginx/$nginx_version;

fastcgi_param	REMOTE_ADDR		    $remote_addr;
fastcgi_param	REMOTE_PORT		    $remote_port;
fastcgi_param	SERVER_ADDR		    $server_addr;
fastcgi_param	SERVER_PORT		    $server_port;
fastcgi_param	SERVER_NAME		    $server_name;

fastcgi_param	HTTPS			        $https;

# PHP only, required if PHP was built with --enable-force-cgi-redirect
fastcgi_param	REDIRECT_STATUS		200;
<% if @location_cfg_append -%>
  <%- @location_cfg_append.sort_by {|k,v| k}.each do |key,value| -%>
    <%- if value.is_a?(Hash) -%>
      <%- value.each do |subkey,subvalue| -%>
        <%- Array(subvalue).each do |asubvalue| -%>
    <%= key %> <%= subkey %> <%= asubvalue %>;
        <%- end -%>
      <%- end -%>
    <%- else -%>
      <%- Array(value).each do |asubvalue| -%>
    <%= key %> <%= asubvalue %>;
      <%- end -%>
    <%- end -%>
  <%- end -%>
<% end -%>
<% if @location_custom_cfg_append -%>
  <%- @location_custom_cfg_append.each do |key,value| -%>
    <%- if value.is_a?(Hash) -%>
      <%- value.each do |subkey,subvalue| -%>
        <%- Array(subvalue).each do |asubvalue| -%>
    <%= key %> <%= subkey %> <%= asubvalue %>
        <%- end -%>
      <%- end -%>
    <%- else -%>
      <%- Array(value).each do |asubvalue| -%>
    <%= key %> <%= asubvalue %>
      <%- end -%>
    <%- end -%>
  <%- end -%>
<% end -%>
<% if @raw_append && Array(@raw_append).size > 0 -%>
    <%- Array(@raw_append).each do |line| -%>
    <%= line %>
    <%- end -%>
<% end -%>
  }
  location <%= @location %> {
<% if @internal -%>
    internal;
<% end -%>
<% if @location_allow -%>
    <%- @location_allow.each do |allow_rule| -%>
    allow <%= allow_rule %>;
    <%- end -%>
<% end -%>
<% if @location_deny -%>
    <%- @location_deny.each do |deny_rule| -%>
    deny <%= deny_rule %>;
    <%- end -%>
<% end -%>
<% if @location_custom_cfg_prepend -%>
  <%- @location_custom_cfg_prepend.each do |key,value| -%>
    <%- if value.is_a?(Hash) -%>
      <%- value.each do |subkey,subvalue| -%>
        <%- Array(subvalue).each do |asubvalue| -%>
    <%= key %> <%= subkey %> <%= asubvalue %>
        <%- end -%>
      <%- end -%>
    <%- else -%>
      <%- Array(value).each do |asubvalue| -%>
    <%= key %> <%= asubvalue %>
      <%- end -%>
    <%- end -%>
  <%- end -%>
<% end -%>
<% if @location_cfg_prepend -%>
  <%- @location_cfg_prepend.sort_by {|k,v| k}.each do |key,value| -%>
    <%- if value.is_a?(Hash) -%>
      <%- value.each do |subkey,subvalue| -%>
        <%- Array(subvalue).each do |asubvalue| -%>
    <%= key %> <%= subkey %> <%= asubvalue %>;
        <%- end -%>
      <%- end -%>
    <%- else -%>
      <%- Array(value).each do |asubvalue| -%>
    <%= key %> <%= asubvalue %>;
      <%- end -%>
    <%- end -%>
  <%- end -%>
<% end -%>
<% if @raw_prepend && Array(@raw_prepend).size > 0 %>
    <%- Array(@raw_prepend).each do |line| -%>
    <%= line %>
    <%- end -%>
<% end %>
    alias      <%= @location_alias %>;
<% if defined? @autoindex -%>
    autoindex <%= @autoindex %>;
<% end -%>
<% if defined? @www_root -%>
    root  <%= @www_root %>;
<% end -%>
<% if @try_files -%>
    try_files<% @try_files.each do |try| -%> <%= try %><% end -%>;
<% end -%>
<% if defined? @autoindex -%>
     autoindex <%= @autoindex %>;
<% end -%>
<% if @index_files.count > 0 -%>
    index <% Array(@index_files).each do |i| %> <%= i %><% end %>;
<% end -%>
<% @rewrite_rules.each do |rewrite_rule| -%>
    rewrite <%= rewrite_rule %>;
<% end -%>
<% if defined? @auth_basic -%>
    auth_basic           "<%= @auth_basic %>";
<% end -%>
<% if defined? @auth_basic_user_file -%>
    auth_basic_user_file <%= @auth_basic_user_file %>;
<% end -%>
<% if @location_custom_cfg -%>
  <%- @location_custom_cfg.sort_by {|k,v| k}.each do |key,value| -%>
    <%- if value.is_a?(Hash) -%>
      <%- value.each do |subkey,subvalue| -%>
        <%- Array(subvalue).each do |asubvalue| -%>
    <%= key %> <%= subkey %> <%= asubvalue %>;
        <%- end -%>
      <%- end -%>
    <%- else -%>
      <%- Array(value).each do |asubvalue| -%>
    <%= key %> <%= asubvalue %>;
      <%- end -%>
    <%- end -%>
  <%- end -%>
<% end -%>
<% if defined? @www_root -%>
    root  <%= @www_root %>;
<% end -%>
<% if @fastcgi_split_path -%>
    fastcgi_split_path_info <%= @fastcgi_split_path %>;
<% end -%>
<% if @try_files -%>
    try_files<% @try_files.each do |try| -%> <%= try %><% end -%>;
<% end -%>
    include <%= @fastcgi_params %>;
    fastcgi_pass <%= @fastcgi %>;
<% if defined? @fastcgi_script %>
    fastcgi_param SCRIPT_FILENAME <%= @fastcgi_script %>;
<% end -%>
<% if @proxy_cache -%>
    proxy_cache         <%= @proxy_cache %>;
    proxy_cache_valid   <%= @proxy_cache_valid %>;
<% end -%>
    proxy_pass          <%= @proxy %>;
    proxy_read_timeout  <%= @proxy_read_timeout %>;
    proxy_connect_timeout  <%= @proxy_connect_timeout %>;
    proxy_redirect  <%= @proxy_redirect %>;
<% @proxy_set_header.each do |header| -%>
    proxy_set_header        <%= header %>;
<% end -%>
<% if @proxy_method -%>
    proxy_method        <%= @proxy_method %>;
<% end -%>
<% if @proxy_set_body -%>
    proxy_set_body      <%= @proxy_set_body %>;
<% end -%>
<% @rewrite_rules.each do |rewrite_rule| -%>
    rewrite <%= rewrite_rule %>;
<% end -%>
<% if defined? @auth_basic -%>
    auth_basic           "<%= @auth_basic %>";
<% end -%>
<% if defined? @auth_basic_user_file -%>
    auth_basic_user_file <%= @auth_basic_user_file %>;
<% end -%>
    stub_status on;
<% if @include_files -%>
  <%- @include_files.each do |file| -%>
  include <%= file %>;
  <%- end -%>
<% end -%>
<%# make sure that allow comes before deny by forcing the allow key (if it -%>
<%# exists) to be first in the output order.  The hash keys also need to be -%>
<%# sorted so that the ordering is stable. -%>
<% if @vhost_cfg_append -%>
  <%- @vhost_cfg_append.sort_by{ |k, v| k.to_s == 'allow' ? '' : k.to_s }.each do |key,value| -%>
    <%- if value.is_a?(Hash) -%>
      <%- value.each do |subkey,subvalue| -%>
        <%- Array(subvalue).each do |asubvalue| -%>
  <%= key %> <%= subkey %> <%= asubvalue %>;
        <%- end -%>
      <%- end -%>
    <%- else -%>
      <%- Array(value).each do |asubvalue| -%>
  <%= key %> <%= asubvalue %>;
      <%- end -%>
    <%- end -%>
  <%- end -%>
<% end -%>
<% Array(@raw_append).each do |line| -%>
  <%= line %>
<% end -%>
}
<% if @rewrite_www_to_non_www -%>
server {
  listen       <%= @listen_ip %>:<%= @listen_port %>;
  server_name  www.<%= @server_name[0].gsub(/^www\./, '') %>;
  return       301 http://<%= @server_name[0].gsub(/^www\./, '') %>$uri;
}

<% end -%>
server {
  listen                <%= @listen_ip %>:<%= @listen_port %><% if @listen_options %> <%= @listen_options %><% end %>;
<% # check to see if ipv6 support exists in the kernel before applying %>
<% if @ipv6_enable && (defined? @ipaddress6) %>
  listen [<%= @ipv6_listen_ip %>]:<%= @ipv6_listen_port %> <% if @ipv6_listen_options %><%= @ipv6_listen_options %><% end %>;
<% end %>
  server_name           <%= @rewrite_www_to_non_www ? @server_name[0].gsub(/^www\./, '') : @server_name.join(" ") %>;
<% if defined? @auth_basic -%>
  auth_basic           "<%= @auth_basic %>";
<% end -%>
<% if defined? @auth_basic_user_file -%>
  auth_basic_user_file <%= @auth_basic_user_file %>;
<% end -%>
<% if defined? @client_body_timeout -%>
  client_body_timeout <%= @client_body_timeout %>;
<% end -%>
<% if defined? @client_header_timeout -%>
  client_header_timeout <%= @client_header_timeout %>;
<% end -%>
<% if defined? @client_max_body_size -%>
  client_max_body_size <%= @client_max_body_size %>;
<% end -%>
<% if defined? @gzip_types -%>
  gzip_types <%= @gzip_types %>;
<% end -%>
<%# make sure that allow comes before deny by forcing the allow key (if it -%>
<%# exists) to be first in the output order.  The hash keys also need to be -%>
<%# sorted so that the ordering is stable. -%>
<% if @vhost_cfg_prepend -%>
  <%- @vhost_cfg_prepend.sort_by{ |k, v| k.to_s == 'allow' ? '' : k.to_s }.each do |key,value| -%>
    <%- if value.is_a?(Hash) -%>
      <%- value.each do |subkey,subvalue| -%>
        <%- Array(subvalue).each do |asubvalue| -%>
  <%= key %> <%= subkey %> <%= asubvalue %>;
        <%- end -%>
      <%- end -%>
    <%- else -%>
      <%- Array(value).each do |asubvalue| -%>
  <%= key %> <%= asubvalue %>;
      <%- end -%>
    <%- end -%>
  <%- end -%>
<% end -%>
<% Array(@raw_prepend).each do |line| -%>
  <%= line %>
<% end %>
<% if @root -%>
  root <%= @root %>;
<% end -%>
<% if @passenger_cgi_param -%>
  <%- @passenger_cgi_param.keys.sort.each do |key| -%>
  passenger_set_cgi_param  <%= key %> <%= @passenger_cgi_param[key] %>;
  <%- end -%>
<% end -%>
<% if @resolver.count > 0 -%>
  resolver                  <% Array(@resolver).each do |r| %> <%= r %><% end %>;
<% end -%>
<% @proxy_set_header.each do |header| -%>
  proxy_set_header        <%= header %>;
<% end -%>
<% if @add_header -%>
  <%- @add_header.each do |key,value| -%>
  add_header              <%= key %> <%= value %>;
  <%- end -%>
<% end -%>
<% if @rewrite_to_https -%>
  if ($ssl_protocol = "") {
       return 301 https://$host$request_uri;
  }
<% end -%>
<% if @index_files.count > 0 -%>
    index <% Array(@index_files).each do |i| %> <%= i %><% end %>;
<% end -%>
<% if defined? @log_by_lua -%>
  log_by_lua '<%= @log_by_lua %>';
<% end -%>
<% if defined? @log_by_lua_file -%>
  log_by_lua_file "<%= @log_by_lua_file %>";
<% end -%>

  access_log            <%= @access_log_real %>;
  error_log             <%= @error_log_real %>;

<% if @include_files %>
  <%- @include_files.each do |file| -%>
  include <%= file %>;
  <%- end -%>
<% end -%>
<% if @vhost_cfg_append -%>
  <%- @vhost_cfg_append.sort_by{ |k, v| k.to_s == 'allow' ? '' : k.to_s }.each do |key,value| -%>
    <%- if value.is_a?(Hash) -%>
      <%- value.each do |subkey,subvalue| -%>
        <%- Array(subvalue).each do |asubvalue| -%>
  <%= key %> <%= subkey %> <%= asubvalue %>;
        <%- end -%>
      <%- end -%>
    <%- else -%>
      <%- Array(value).each do |asubvalue| -%>
  <%= key %> <%= asubvalue %>;
      <%- end -%>
    <%- end -%>
  <%- end -%>
<% end -%>
<% if @vhost_cfg_ssl_append -%>
  <%- @vhost_cfg_ssl_append.sort_by{ |k, v| k.to_s == 'allow' ? '' : k.to_s }.each do |key,value| -%>
    <%- if value.is_a?(Hash) -%>
      <%- value.each do |subkey,subvalue| -%>
        <%- Array(subvalue).each do |asubvalue| -%>
  <%= key %> <%= subkey %> <%= asubvalue %>;
        <%- end -%>
      <%- end -%>
    <%- else -%>
      <%- Array(value).each do |asubvalue| -%>
  <%= key %> <%= asubvalue %>;
      <%- end -%>
    <%- end -%>
  <%- end -%>
<% end -%>
<% Array(@raw_append).each do |line| -%>
  <%= line %>
<% end -%>
}
<% if @rewrite_www_to_non_www -%>
server {
  listen       <%= @listen_ip %>:<%= @ssl_port %> ssl;
  server_name  www.<%= @server_name[0].gsub(/^www\./, '') %>;
  return       301 https://<%= @server_name[0].gsub(/^www\./, '') %>$uri;
}

<% end %>
server {
  listen       <%= @listen_ip %>:<%= @ssl_port %> <% if @ssl_listen_option %>ssl<% end %><% if @spdy == 'on' %> spdy<% end %><% if @listen_options %> <%= @listen_options %><% end %>;
  <%- if @ipv6_enable && (defined? @ipaddress6) %>
  listen [<%= @ipv6_listen_ip %>]:<%= @ssl_port %> ssl<% if @spdy == 'on' %> spdy<% end %><% if @ipv6_listen_options %> <%= @ipv6_listen_options %><% end %>;
  <%- end %>
  server_name  <%= @rewrite_www_to_non_www ? @server_name[0].gsub(/^www\./, '') : @server_name.join(" ") %>;

  ssl on;

  ssl_certificate           <%= scope.lookupvar('nginx::config::conf_dir') %>/<%= @name.gsub(' ', '_') %>.crt;
  ssl_certificate_key       <%= scope.lookupvar('nginx::config::conf_dir') %>/<%= @name.gsub(' ', '_') %>.key;
<% if defined? @ssl_dhparam -%>
  ssl_dhparam               <%= scope.lookupvar('nginx::config::conf_dir') %>/<%= @name.gsub(' ', '_') %>.dh.pem;
<% end -%>
  ssl_session_cache         <%= @ssl_cache %>;
  ssl_session_timeout       5m;
  ssl_protocols             <%= @ssl_protocols %>;
  ssl_ciphers               <%= @ssl_ciphers %>;
  ssl_prefer_server_ciphers on;
<% if @ssl_stapling -%>
  ssl_stapling              on;
<% end -%>
<% if defined? @ssl_stapling_file -%>
  ssl_stapling_file         <%= scope.lookupvar('nginx::config::conf_dir') %>/<%= @name.gsub(' ', '_') %>.ocsp.resp;
<% end -%>
<% if defined? @ssl_stapling_responder -%>
  ssl_stapling_responder    <%= @ssl_stapling_responder %>;
<% end -%>
<% if @ssl_stapling_verify -%>
  ssl_stapling_verify       on;
<% end -%>
<% if defined? @ssl_trusted_cert -%>
  ssl_trusted_certificate   <%= scope.lookupvar('nginx::config::conf_dir') %>/<%= @name.gsub(' ', '_') %>.trusted.crt;
<% end -%>
<% if @resolver.count > 0 -%>
  resolver                  <% Array(@resolver).each do |r| %> <%= r %><% end %>;
<% end -%>
<% if defined? @auth_basic -%>
  auth_basic                "<%= @auth_basic %>";
<% end -%>
<% if defined? @auth_basic_user_file -%>
  auth_basic_user_file      "<%= @auth_basic_user_file %>";
<% end -%>
<% if defined? @client_body_timeout -%>
  client_body_timeout <%= @client_body_timeout %>;
<% end -%>
<% if defined? @client_header_timeout -%>
  client_header_timeout <%= @client_header_timeout %>;
<% end -%>
<% if defined? @client_max_body_size -%>
  client_max_body_size <%= @client_max_body_size %>;
<% end -%>
<% if defined? @gzip_types -%>
  gzip_types <%= @gzip_types %>;
<% end -%>
<% if @index_files.count > 0 -%>
    index <% Array(@index_files).each do |i| %> <%= i %><% end %>;
<% end -%>

  access_log            <%= @ssl_access_log_real %>;
  error_log             <%= @ssl_error_log_real %>;

<% if @vhost_cfg_prepend -%>
  <%- @vhost_cfg_prepend.sort_by{ |k, v| k.to_s == 'allow' ? '' : k.to_s }.each do |key,value| -%>
    <%- if value.is_a?(Hash) -%>
      <%- value.each do |subkey,subvalue| -%>
        <%- Array(subvalue).each do |asubvalue| -%>
  <%= key %> <%= subkey %> <%= asubvalue %>;
        <%- end -%>
      <%- end -%>
    <%- else -%>
      <%- Array(value).each do |asubvalue| -%>
  <%= key %> <%= asubvalue %>;
      <%- end -%>
    <%- end -%>
  <%- end -%>
<% end -%>
<% if @vhost_cfg_ssl_prepend -%>
  <%- @vhost_cfg_ssl_prepend.sort_by{ |k, v| k.to_s == 'allow' ? '' : k.to_s }.each do |key,value| -%>
    <%- if value.is_a?(Hash) -%>
      <%- value.each do |subkey,subvalue| -%>
        <%- Array(subvalue).each do |asubvalue| -%>
  <%= key %> <%= subkey %> <%= asubvalue %>;
        <%- end -%>
      <%- end -%>
    <%- else -%>
      <%- Array(value).each do |asubvalue| -%>
  <%= key %> <%= asubvalue %>;
      <%- end -%>
    <%- end -%>
  <%- end -%>
<% end -%>
<% Array(@raw_prepend).each do |line| -%>
  <%= line %>
<% end %>
<% if @root -%>
  root <%= @root %>;
<% end -%>
<% Array(@passenger_cgi_param).each do |key,value| -%>
  passenger_set_cgi_param  <%= key %> <%= value %>;
<% end -%>
<% Array(@proxy_set_header).each do |header| -%>
  proxy_set_header        <%= header %>;
<% end -%>
<% Array(@add_header).each do |key,value| -%>
  add_header              <%= key %> <%= value %>;
<% end -%>
# The notify before should always come BEFORE all resources
# managed by the nginx class
# and the notify last should always come AFTER all resources
# managed by the nginx class.
node default {
  notify { 'before': }
  -> class { 'nginx': }
  -> notify { 'last': }
}
include nginx

nginx::resource::location { 'www.test.com-alias':
    ensure         => present,
    location       => '/some/url',
    location_alias => '/new/url/',
    vhost          => 'www.test.com',
}
include nginx

nginx::resource::upstream { 'proxypass':
  ensure  => present,
  members => [
        'localhost:3000',
        'localhost:3001',
        'localhost:3002',
  ],
}
include nginx

nginx::resource::vhost { 'test.local test':
  ensure       => present,
  ipv6_enable  => true,
  proxy        => 'http://proxypass',
}

nginx::resource::vhost { 'test.local:8080':
  ensure       => present,
  listen_port  => 8080,
  server_name  => ['test.local test'],
  ipv6_enable  => true,
  proxy        => 'http://proxypass',
}

include nginx

nginx::resource::vhost { 'test2.local test2':
  ensure   => present,
  www_root => '/var/www/nginx-default',
  ssl      => true,
  ssl_cert => 'puppet:///modules/sslkey/whildcard_mydomain.crt',
  ssl_key  => 'puppet:///modules/sslkey/whildcard_mydomain.key'
}

nginx::resource::location { 'test2.local-bob':
  ensure   => present,
  www_root => '/var/www/bob',
  location => '/bob',
  vhost    => 'test2.local test2',
}

fixtures:
  repositories:
    "stdlib": "git://github.com/puppetlabs/puppetlabs-stdlib.git"
  symlinks:
    "ntp": "#{source_dir}"
default_set: 'centos-64-x64'
sets:
  'centos-59-x64':
    nodes:
      "main.foo.vm":
        prefab: 'centos-59-x64'
  'centos-64-x64':
    nodes:
      "main.foo.vm":
        prefab: 'centos-64-x64'
  'fedora-18-x64':
    nodes:
      "main.foo.vm":
        prefab: 'fedora-18-x64'
  'debian-607-x64':
    nodes:
      "main.foo.vm":
        prefab: 'debian-607-x64'
  'debian-70rc1-x64':
    nodes:
      "main.foo.vm":
        prefab: 'debian-70rc1-x64'
  'ubuntu-server-10044-x64':
    nodes:
      "main.foo.vm":
        prefab: 'ubuntu-server-10044-x64'
  'ubuntu-server-12042-x64':
    nodes:
      "main.foo.vm":
        prefab: 'ubuntu-server-12042-x64'
  'sles-11sp1-x64':
    nodes:
      "main.foo.vm":
        prefab: 'sles-11sp1-x64'
branches:
  only:
  - master
language: ruby
bundler_args: --without development
script: "bundle exec rake spec SPEC_OPTS='--format documentation'"
rvm:
- 1.8.7
- 1.9.3
- 2.0.0
env:
  matrix:
    - PUPPET_GEM_VERSION="~> 2.7.0"
    - PUPPET_GEM_VERSION="~> 3.0.0"
    - PUPPET_GEM_VERSION="~> 3.1.0"
    - PUPPET_GEM_VERSION="~> 3.2.0"
matrix:
  exclude:
    - rvm: 1.9.3
      env: PUPPET_GEM_VERSION="~> 2.7.0"
    - rvm: 2.0.0
      env: PUPPET_GEM_VERSION="~> 2.7.0"
    - rvm: 2.0.0
      env: PUPPET_GEM_VERSION="~> 3.0.0"
    - rvm: 2.0.0
      env: PUPPET_GEM_VERSION="~> 3.1.0"
    - rvm: 1.8.7
      env: PUPPET_GEM_VERSION="~> 3.2.0"
notifications:
  email: false
##2014-04-09 - Supported Release 3.0.4
###Summary
This is a supported release.

The only functional change in this release is to split up the restrict
defaults to be per operating system so that we can provide safer defaults
for AIX, to resolve cases where IPv6 are disabled.

####Features
- Rework restrict defaults.

####Bugfixes
- Fix up a comment.
- Fix a test to work better on PE.

#####Known Bugs
* No known bugs

##2014-03-04 - Supported Release 3.0.3
###Summary
This is a supported release. Correct stdlib compatibility

####Bugfixes
- Remove `dirname()` call for correct stdlib compatibility.
- Improved tests

####Known Bugs
* No known bugs


## 2014-02-13 - Release 3.0.2
###Summary

No functional changes: Update the README and allow custom gem sources.

## 2013-12-17 - Release 3.0.1
### Summary

Work around a packaging bug with symlinks, no other functional changes.

## 2013-12-13 - Release 3.0.0
### Summary

Final release of 3.0, enjoy!


## 2013-10-14 - Version 3.0.0-rc1

###Summary

This release changes the behavior of restrict and adds AIX osfamily support.

####Backwards-incompatible Changes:

`restrict` no longer requires you to pass in parameters as:

restrict => [ 'restrict x', 'restrict y' ]

but just as:

restrict => [ 'x', 'y' ]

As the template now prefixes each line with restrict.

####Features
- Change the behavior of `restrict` so you no longer need the restrict
keyword.
- Add `udlc` parameter to enable undisciplined local clock regardless of the
machines status as a virtual machine.
- Add AIX support.

####Fixes
- Use class{} instead of including and then anchoring. (style)
- Extend Gentoo coverage to Facter 1.7.

##2013-09-05 - Version 2.0.1

###Summary

Correct the LICENSE file.

####Bugfixes
- Add in the appropriate year and name in LICENSE.


##2013-07-31 - Version 2.0.0

###Summary

The 2.0 release focuses on merging all the distro specific
templates into a single reusable template across all platforms.

To aid in that goal we now allow you to change the driftfile,
ntp keys, and perferred_servers.

####Backwards-incompatible changes

As all the distro specific templates have been removed and a
unified one created you may be missing functionality you
previously relied on.  Please test carefully before rolling
out globally.

Configuration directives that might possibly be affected:
- `filegen`
- `fudge` (for virtual machines)
- `keys`
- `logfile`
- `restrict`
- `restrictkey`
- `statistics`
- `trustedkey`

####Features:
- All templates merged into a single template.
- NTP Keys support added.
- Add preferred servers support.
- Parameters in `ntp` class:
  - `driftfile`: path for the ntp driftfile.
  - `keys_enable`: Enable NTP keys feature.
  - `keys_file`: Path for the NTP keys file.
  - `keys_trusted`: Which keys to trust.
  - `keys_controlkey`: Which key to use for the control key.
  - `keys_requestkey`: Which key to use for the request key.
  - `preferred_servers`: Array of servers to prefer.
  - `restrict`: Array of restriction options to apply.

###2013-07-15 - Version 1.0.1
####Bugfixes
- Fix deprecated warning in `autoupdate` parameter.
- Correctly quote is_virtual fact.


##2013-07-08 - Version 1.0.0
####Features
- Completely refactored to split across several classes.
- rspec-puppet tests rewritten to cover more options.
- rspec-system tests added.
- ArchLinux handled via osfamily instead of special casing.
- parameters in `ntp` class:
  - `autoupdate`: deprecated in favor of directly setting package_ensure.
  - `panic`: set to false if you wish to allow large clock skews. 

##2011-11-10 Dan Bode <dan@puppetlabs.com> - 0.0.4
* Add Amazon Linux as a supported platform
* Add unit tests


##2011-06-16 Jeff McCune <jeff@puppetlabs.com> - 0.0.3
* Initial release under puppetlabs
Puppet Labs modules on the Puppet Forge are open projects, and community contributions
are essential for keeping them great. We can’t access the huge number of platforms and
myriad of hardware, software, and deployment configurations that Puppet is intended to serve.

We want to keep it as easy as possible to contribute changes so that our modules work
in your environment. There are a few guidelines that we need contributors to follow so
that we can have a chance of keeping on top of things.

You can read the complete module contribution guide [on the Puppet Labs wiki.](http://projects.puppetlabs.com/projects/module-site/wiki/Module_contributing)
source ENV['GEM_SOURCE'] || "https://rubygems.org"

group :development, :test do
  gem 'rake',                    :require => false
  gem 'puppetlabs_spec_helper',  :require => false
  gem 'puppet-lint',             :require => false
  gem 'serverspec',              :require => false
  gem 'beaker',                  :require => false
  gem 'beaker-rspec',            :require => false
  gem 'specinfra', '>=0.7.0'
end

if puppetversion = ENV['PUPPET_GEM_VERSION']
  gem 'puppet', puppetversion, :require => false
else
  gem 'puppet', :require => false
end

# vim:ft=ruby
                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright [2013] [Puppet Labs]

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

name    'puppetlabs-ntp'
version '3.0.4'
source 'git://github.com/puppetlabs/puppetlabs-ntp'
author 'Puppet Labs'
license 'Apache Version 2.0'
summary 'NTP Module'
description 'NTP Module for Debian, Ubuntu, CentOS, RHEL, OEL, Fedora, FreeBSD, ArchLinux and Gentoo.'
project_page 'http://github.com/puppetlabs/puppetlabs-ntp'

## Add dependencies, if any:
dependency 'puppetlabs/stdlib', '>= 0.1.6'
#ntp

####Table of Contents

1. [Overview](#overview)
2. [Module Description - What the module does and why it is useful](#module-description)
3. [Setup - The basics of getting started with ntp](#setup)
    * [What ntp affects](#what-ntp-affects)
    * [Setup requirements](#setup-requirements)
    * [Beginning with ntp](#beginning-with-ntp)
4. [Usage - Configuration options and additional functionality](#usage)
5. [Reference - An under-the-hood peek at what the module is doing and how](#reference)
5. [Limitations - OS compatibility, etc.](#limitations)
6. [Development - Guide for contributing to the module](#development)

##Overview

The ntp module installs, configures, and manages the NTP service.

##Module Description

The ntp module handles installing, configuring, and running NTP across a range of operating systems and distributions.

##Setup

###What ntp affects

* ntp package.
* ntp configuration file.
* ntp service.

###Beginning with ntp

`include '::ntp'` is enough to get you up and running.  If you wish to pass in
parameters specifying which servers to use, then:

```puppet
class { '::ntp':
  servers => [ 'ntp1.corp.com', 'ntp2.corp.com' ],
}
```

##Usage

All interaction with the ntp module can do be done through the main ntp class.
This means you can simply toggle the options in `::ntp` to have full functionality of the module.

###I just want NTP, what's the minimum I need?

```puppet
include '::ntp'
```

###I just want to tweak the servers, nothing else.

```puppet
class { '::ntp':
  servers => [ 'ntp1.corp.com', 'ntp2.corp.com' ],
}
```

###I'd like to make sure I restrict who can connect as well.

```puppet
class { '::ntp':
  servers  => [ 'ntp1.corp.com', 'ntp2.corp.com' ],
  restrict => ['127.0.0.1'],
}
```

###I'd like to opt out of having the service controlled; we use another tool for that.

```puppet
class { '::ntp':
  servers        => [ 'ntp1.corp.com', 'ntp2.corp.com' ],
  restrict       => ['127.0.0.1'],
  manage_service => false,
}
```

###Looks great!  But I'd like a different template; we need to do something unique here.

```puppet
class { '::ntp':
  servers         => [ 'ntp1.corp.com', 'ntp2.corp.com' ],
  restrict        => ['127.0.0.1'],
  manage_service  => false,
  config_template => 'different/module/custom.template.erb',
}
```

##Reference

###Classes

####Public Classes

* ntp: Main class, includes all other classes.

####Private Classes

* ntp::install: Handles the packages.
* ntp::config: Handles the configuration file.
* ntp::service: Handles the service.

###Parameters

The following parameters are available in the ntp module:

####`autoupdate`

**Deprecated:** This parameter determined whether the ntp module should be
automatically updated to the latest version available.  Replaced by `package_ensure`.

####`config`

Sets the file that ntp configuration is written into.

####`config_template`

Determines which template Puppet should use for the ntp configuration.

####`driftfile`

Sets the location of the drift file for ntp.

####`keys_controlkey`

The key to use as the control key.

####`keys_enable`

Whether the ntp keys functionality is enabled.

####`keys_file`

Location of the keys file.

####`keys_requestkey`

Which of the keys is the request key.

#### `keys_trusted`

Array of trusted keys.

####`package_ensure`

Sets the ntp package to be installed. Can be set to 'present', 'latest', or a specific version. 

####`package_name`

Determines the name of the package to install.

####`panic`

Determines if ntp should 'panic' in the event of a very large clock skew.
This defaults to false for virtual machines, as they don't do a great job with keeping time.

####`preferred_servers`

List of ntp servers to prefer.  Will append 'prefer' for any server in this list
that also appears in the servers list.

####`restrict`

Sets the restrict options in the ntp configuration.  The lines are
prefixed with 'restrict', so you just need to list the rest of the restriction.

####`servers`

Selects the servers to use for ntp peers.

####`service_enable`

Determines if the service should be enabled at boot.

####`service_ensure`

Determines if the service should be running or not.

####`service_manage`

Selects whether Puppet should manage the service.

####`service_name`

Selects the name of the ntp service for Puppet to manage.

####`udlc`

Enables configs for undisciplined local clock, regardless of
status as a virtual machine. 


##Limitations

This module has been built on and tested against Puppet 2.7 and higher.

The module has been tested on:

* RedHat Enterprise Linux 5/6
* Debian 6/7
* CentOS 5/6
* Ubuntu 12.04
* Gentoo
* Arch Linux
* FreeBSD

Testing on other platforms has been light and cannot be guaranteed. 

##Development

Puppet Labs modules on the Puppet Forge are open projects, and community
contributions are essential for keeping them great. We can’t access the
huge number of platforms and myriad of hardware, software, and deployment
configurations that Puppet is intended to serve.

We want to keep it as easy as possible to contribute changes so that our
modules work in your environment. There are a few guidelines that we need
contributors to follow so that we can have a chance of keeping on top of things.

You can read the complete module contribution guide [on the Puppet Labs wiki.](http://projects.puppetlabs.com/projects/module-site/wiki/Module_contributing)

###Contributors

The list of contributors can be found at: [https://github.com/puppetlabs/puppetlabs-ntp/graphs/contributors](https://github.com/puppetlabs/puppetlabs-ntp/graphs/contributors)
require 'puppetlabs_spec_helper/rake_tasks'
#
class ntp::config inherits ntp {

  if $keys_enable {
    # Workaround for the lack of dirname() in stdlib 3.2.
    $directory = inline_template('<%= File.dirname(keys_file) %>')
    file { $directory:
      ensure  => directory,
      owner   => 0,
      group   => 0,
      mode    => '0755',
      recurse => true,
    }
  }

  file { $config:
    ensure  => file,
    owner   => 0,
    group   => 0,
    mode    => '0644',
    content => template($config_template),
  }

}
class ntp (
  $autoupdate        = $ntp::params::autoupdate,
  $config            = $ntp::params::config,
  $config_template   = $ntp::params::config_template,
  $driftfile         = $ntp::params::driftfile,
  $keys_enable       = $ntp::params::keys_enable,
  $keys_file         = $ntp::params::keys_file,
  $keys_controlkey   = $ntp::params::keys_controlkey,
  $keys_requestkey   = $ntp::params::keys_requestkey,
  $keys_trusted      = $ntp::params::keys_trusted,
  $package_ensure    = $ntp::params::package_ensure,
  $package_name      = $ntp::params::package_name,
  $panic             = $ntp::params::panic,
  $preferred_servers = $ntp::params::preferred_servers,
  $restrict          = $ntp::params::restrict,
  $servers           = $ntp::params::servers,
  $service_enable    = $ntp::params::service_enable,
  $service_ensure    = $ntp::params::service_ensure,
  $service_manage    = $ntp::params::service_manage,
  $service_name      = $ntp::params::service_name,
  $udlc              = $ntp::params::udlc
) inherits ntp::params {

  validate_absolute_path($config)
  validate_string($config_template)
  validate_absolute_path($driftfile)
  validate_bool($keys_enable)
  validate_re($keys_controlkey, ['^\d+$', ''])
  validate_re($keys_requestkey, ['^\d+$', ''])
  validate_array($keys_trusted)
  validate_string($package_ensure)
  validate_array($package_name)
  validate_bool($panic)
  validate_array($preferred_servers)
  validate_array($restrict)
  validate_array($servers)
  validate_bool($service_enable)
  validate_string($service_ensure)
  validate_bool($service_manage)
  validate_string($service_name)
  validate_bool($udlc)

  if $autoupdate {
    notice('autoupdate parameter has been deprecated and replaced with package_ensure.  Set this to latest for the same behavior as autoupdate => true.')
  }

  # Anchor this as per #8040 - this ensures that classes won't float off and
  # mess everything up.  You can read about this at:
  # http://docs.puppetlabs.com/puppet/2.7/reference/lang_containment.html#known-issues
  anchor { 'ntp::begin': } ->
  class { '::ntp::install': } ->
  class { '::ntp::config': } ~>
  class { '::ntp::service': } ->
  anchor { 'ntp::end': }

}
#
class ntp::install inherits ntp {

  package { 'ntp':
    ensure => $package_ensure,
    name   => $package_name,
  }

}
class ntp::params {

  $autoupdate        = false
  $config_template   = 'ntp/ntp.conf.erb'
  $keys_enable       = false
  $keys_controlkey   = ''
  $keys_requestkey   = ''
  $keys_trusted      = []
  $package_ensure    = 'present'
  $preferred_servers = []
  $service_enable    = true
  $service_ensure    = 'running'
  $service_manage    = true
  $udlc              = false

  # On virtual machines allow large clock skews.
  $panic = str2bool($::is_virtual) ? {
    true    => false,
    default => true,
  }

  case $::osfamily {
    'AIX': {
      $config = '/etc/ntp.conf'
      $keysfile = '/etc/ntp.keys'
      $driftfile = '/etc/ntp.drift'
      $package_name = [ 'bos.net.tcp.client' ]
      $restrict          = [
        'default nomodify notrap nopeer noquery',
        '127.0.0.1',
      ]
      $service_name = 'xntpd'
      $servers = [
        '0.debian.pool.ntp.org iburst',
        '1.debian.pool.ntp.org iburst',
        '2.debian.pool.ntp.org iburst',
        '3.debian.pool.ntp.org iburst',
      ]
    }
    'Debian': {
      $config          = '/etc/ntp.conf'
      $keys_file       = '/etc/ntp/keys'
      $driftfile       = '/var/lib/ntp/drift'
      $package_name    = [ 'ntp' ]
      $restrict          = [
        'default kod nomodify notrap nopeer noquery',
        '-6 default kod nomodify notrap nopeer noquery',
        '127.0.0.1',
        '-6 ::1',
      ]
      $service_name    = 'ntp'
      $servers         = [
        '0.debian.pool.ntp.org iburst',
        '1.debian.pool.ntp.org iburst',
        '2.debian.pool.ntp.org iburst',
        '3.debian.pool.ntp.org iburst',
      ]
    }
    'RedHat': {
      $config          = '/etc/ntp.conf'
      $driftfile       = '/var/lib/ntp/drift'
      $keys_file       = '/etc/ntp/keys'
      $package_name    = [ 'ntp' ]
      $restrict          = [
        'default kod nomodify notrap nopeer noquery',
        '-6 default kod nomodify notrap nopeer noquery',
        '127.0.0.1',
        '-6 ::1',
      ]
      $service_name    = 'ntpd'
      $servers         = [
        '0.centos.pool.ntp.org',
        '1.centos.pool.ntp.org',
        '2.centos.pool.ntp.org',
      ]
    }
    'SuSE': {
      $config          = '/etc/ntp.conf'
      $driftfile       = '/var/lib/ntp/drift/ntp.drift'
      $keys_file       = '/etc/ntp/keys'
      $package_name    = [ 'ntp' ]
      $restrict          = [
        'default kod nomodify notrap nopeer noquery',
        '-6 default kod nomodify notrap nopeer noquery',
        '127.0.0.1',
        '-6 ::1',
      ]
      $service_name    = 'ntp'
      $servers         = [
        '0.opensuse.pool.ntp.org',
        '1.opensuse.pool.ntp.org',
        '2.opensuse.pool.ntp.org',
        '3.opensuse.pool.ntp.org',
      ]
    }
    'FreeBSD': {
      $config          = '/etc/ntp.conf'
      $driftfile       = '/var/db/ntpd.drift'
      $keys_file       = '/etc/ntp/keys'
      $package_name    = ['net/ntp']
      $restrict          = [
        'default kod nomodify notrap nopeer noquery',
        '-6 default kod nomodify notrap nopeer noquery',
        '127.0.0.1',
        '-6 ::1',
      ]
      $service_name    = 'ntpd'
      $servers         = [
        '0.freebsd.pool.ntp.org iburst maxpoll 9',
        '1.freebsd.pool.ntp.org iburst maxpoll 9',
        '2.freebsd.pool.ntp.org iburst maxpoll 9',
        '3.freebsd.pool.ntp.org iburst maxpoll 9',
      ]
    }
    'Archlinux': {
      $config          = '/etc/ntp.conf'
      $driftfile       = '/var/lib/ntp/drift'
      $keys_file       = '/etc/ntp/keys'
      $package_name    = [ 'ntp' ]
      $restrict          = [
        'default kod nomodify notrap nopeer noquery',
        '-6 default kod nomodify notrap nopeer noquery',
        '127.0.0.1',
        '-6 ::1',
      ]
      $service_name    = 'ntpd'
      $servers         = [
        '0.pool.ntp.org',
        '1.pool.ntp.org',
        '2.pool.ntp.org',
      ]
    }
    # Gentoo was added as its own $::osfamily in Facter 1.7.0
    'Gentoo': {
      $config          = '/etc/ntp.conf'
      $driftfile       = '/var/lib/ntp/drift'
      $keys_file       = '/etc/ntp/keys'
      $package_name    = ['net-misc/ntp']
      $restrict          = [
        'default kod nomodify notrap nopeer noquery',
        '-6 default kod nomodify notrap nopeer noquery',
        '127.0.0.1',
        '-6 ::1',
      ]
      $service_name    = 'ntpd'
      $servers         = [
        '0.gentoo.pool.ntp.org',
        '1.gentoo.pool.ntp.org',
        '2.gentoo.pool.ntp.org',
        '3.gentoo.pool.ntp.org',
      ]
    }
    'Linux': {
      # Account for distributions that don't have $::osfamily specific settings.
      # Before Facter 1.7.0 Gentoo did not have its own $::osfamily
      case $::operatingsystem {
        'Gentoo': {
          $config          = '/etc/ntp.conf'
          $driftfile       = '/var/lib/ntp/drift'
          $keys_file       = '/etc/ntp/keys'
          $package_name    = ['net-misc/ntp']
          $restrict          = [
            'default kod nomodify notrap nopeer noquery',
            '-6 default kod nomodify notrap nopeer noquery',
            '127.0.0.1',
            '-6 ::1',
          ]
          $service_name    = 'ntpd'
          $servers         = [
            '0.gentoo.pool.ntp.org',
            '1.gentoo.pool.ntp.org',
            '2.gentoo.pool.ntp.org',
            '3.gentoo.pool.ntp.org',
          ]
        }
        default: {
          fail("The ${module_name} module is not supported on an ${::operatingsystem} distribution.")
        }
      }
    }
    default: {
      fail("The ${module_name} module is not supported on an ${::osfamily} based system.")
    }
  }
}
#
class ntp::service inherits ntp {

  if ! ($service_ensure in [ 'running', 'stopped' ]) {
    fail('service_ensure parameter must be running or stopped')
  }

  if $service_manage == true {
    service { 'ntp':
      ensure     => $service_ensure,
      enable     => $service_enable,
      name       => $service_name,
      hasstatus  => true,
      hasrestart => true,
    }
  }

}
{
  "operatingsystem_support": [
    {
      "operatingsystem": "RedHat",
      "operatingsystemrelease": [
        "5",
        "6"
      ]
    },
    {
      "operatingsystem": "CentOS",
      "operatingsystemrelease": [
        "5",
        "6"
      ]
    },
    {
      "operatingsystem": "OracleLinux",
      "operatingsystemrelease": [
        "5",
        "6"
      ]
    },
    {
      "operatingsystem": "Scientific",
      "operatingsystemrelease": [
        "5",
        "6"
      ]
    },
    {
      "operatingsystem": "SLES",
      "operatingsystemrelease": [
        "11 SP1"
      ]
    },
    {
      "operatingsystem": "Debian",
      "operatingsystemrelease": [
        "6",
        "7"
      ]
    },
    {
      "operatingsystem": "Ubuntu",
      "operatingsystemrelease": [
        "10.04",
        "12.04"
      ]
    },
    {
      "operatingsystem": "AIX",
      "operatingsystemrelease": [
        "5.3",
        "6.1",
        "7.1"
      ]
    }
  ],
  "requirements": [
    {
      "name": "pe",
      "version_requirement": "3.2.x"
    },
    {
      "name": "puppet",
      "version_requirement": "3.x"
    }
  ],
  "name": "puppetlabs-ntp",
  "version": "3.0.4",
  "source": "git://github.com/puppetlabs/puppetlabs-ntp",
  "author": "Puppet Labs",
  "license": "Apache Version 2.0",
  "summary": "NTP Module",
  "description": "NTP Module for Debian, Ubuntu, CentOS, RHEL, OEL, Fedora, FreeBSD, ArchLinux and Gentoo.",
  "project_page": "http://github.com/puppetlabs/puppetlabs-ntp",
  "dependencies": [
    {
      "name": "puppetlabs/stdlib",
      "version_requirement": ">= 0.1.6"
    }
  ]
}
require 'spec_helper_acceptance'

describe 'ntp class:', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
  it 'should run successfully' do
    pp = "class { 'ntp': }"

    # Apply twice to ensure no errors the second time.
    apply_manifest(pp, :catch_failures => true) do |r|
      expect(r.stderr).to eq("")
    end
    apply_manifest(pp, :catch_failures => true) do |r|
      expect(r.stderr).to eq("")
      expect(r.exit_code).to be_zero
    end
  end

  context 'service_ensure => stopped:' do
    it 'runs successfully' do
      pp = "class { 'ntp': service_ensure => stopped }"

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stderr).to eq("")
      end
    end
  end

  context 'service_ensure => running:' do
    it 'runs successfully' do
      pp = "class { 'ntp': service_ensure => running }"

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stderr).to eq("")
      end
    end
  end
end
HOSTS:
  centos-64-x64:
    roles:
      - master
      - database
      - dashboard
    platform: el-6-x86_64
    box : centos-64-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: pe
HOSTS:
  centos-64-x64:
    roles:
      - master
    platform: el-6-x86_64
    box : centos-64-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: foss
HOSTS:
  centos-65-x64:
    roles:
      - master
    platform: el-6-x86_64
    box : centos-65-x64-vbox436-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-65-x64-virtualbox-nocm.box
    hypervisor : vagrant
CONFIG:
  type: foss
HOSTS:
  centos-64-x64:
    roles:
      - master
    platform: el-6-x86_64
    box : centos-64-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: foss
HOSTS:
  fedora-18-x64:
    roles:
      - master
    platform: fedora-18-x86_64
    box : fedora-18-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/fedora-18-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: foss
HOSTS:
  sles-11-x64.local:
    roles:
      - master
    platform: sles-11-x64
    box : sles-11sp1-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/sles-11sp1-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
    type: foss
HOSTS:
  ubuntu-server-10044-x64:
    roles:
      - master
    platform: ubuntu-10.04-amd64
    box : ubuntu-server-10044-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/ubuntu-server-10044-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: foss
HOSTS:
  ubuntu-server-12042-x64:
    roles:
      - master
    platform: ubuntu-12.04-amd64
    box : ubuntu-server-12042-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/ubuntu-server-12042-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: foss
require 'spec_helper_acceptance'

case fact('osfamily')
when 'FreeBSD'
  line = '0.freebsd.pool.ntp.org iburst maxpoll 9'
when 'Debian'
  line = '0.debian.pool.ntp.org iburst'
when 'RedHat'
  line = '0.centos.pool.ntp.org'
when 'SuSE'
  line = '0.opensuse.pool.ntp.org'
when 'Gentoo'
  line = '0.gentoo.pool.ntp.org'
when 'Linux'
  case fact('operatingsystem')
  when 'ArchLinux'
    line = '0.pool.ntp.org'
  when 'Gentoo'
    line = '0.gentoo.pool.ntp.org'
  end
when 'AIX'
  line = '0.debian.pool.ntp.org iburst'
end

describe 'ntp::config class', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
  it 'sets up ntp.conf' do
    apply_manifest(%{
      class { 'ntp': }
    }, :catch_failures => true)
  end

  describe file('/etc/ntp.conf') do
    it { should be_file }
    it { should contain line }
  end
end
require 'spec_helper_acceptance'

case fact('osfamily')
when 'FreeBSD'
  packagename = 'net/ntp'
when 'Gentoo'
  packagename = 'net-misc/ntp'
when 'Linux'
  case fact('operatingsystem')
  when 'ArchLinux'
    packagename = 'ntp'
  when 'Gentoo'
    packagename = 'net-misc/ntp'
  end
when 'AIX'
  packagename = 'bos.net.tcp.client'
else
  packagename = 'ntp'
end

describe 'ntp::install class', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
  it 'installs the package' do
    apply_manifest(%{
      class { 'ntp': }
    }, :catch_failures => true)
  end

  describe package(packagename) do
    it { should be_installed }
  end
end
require 'spec_helper_acceptance'

case fact('osfamily')
when 'FreeBSD'
  packagename = 'net/ntp'
when 'Gentoo'
  packagename = 'net-misc/ntp'
when 'Linux'
  case fact('operatingsystem')
  when 'ArchLinux'
    packagename = 'ntp'
  when 'Gentoo'
    packagename = 'net-misc/ntp'
  end
when 'AIX'
  packagename = 'bos.net.tcp.client'
else
  packagename = 'ntp'
end

describe "ntp class:", :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
  it 'applies successfully' do
    pp = "class { 'ntp': }"

    apply_manifest(pp, :catch_failures => true) do |r|
      expect(r.stderr).to eq("")
    end
  end

  describe 'autoconfig' do
    it 'raises a deprecation warning' do
      pp = "class { 'ntp': autoupdate => true }"

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/autoupdate parameter has been deprecated and replaced with package_ensure/)
      end
    end
  end

  describe 'config' do
    it 'sets the ntp.conf location' do
      pp = "class { 'ntp': config => '/etc/antp.conf' }"
      apply_manifest(pp, :catch_failures => true)
    end

    describe file('/etc/antp.conf') do
      it { should be_file }
    end
  end

  describe 'config_template' do
    it 'sets up template' do
      modulepath = default['distmoduledir']
      shell("mkdir -p #{modulepath}/test/templates")
      shell("echo 'testcontent' >> #{modulepath}/test/templates/ntp.conf")
    end

    it 'sets the ntp.conf location' do
      pp = "class { 'ntp': config_template => 'test/ntp.conf' }"
      apply_manifest(pp, :catch_failures => true)
    end

    describe file('/etc/ntp.conf') do
      it { should be_file }
      it { should contain 'testcontent' }
    end
  end

  describe 'driftfile' do
    it 'sets the driftfile location' do
      pp = "class { 'ntp': driftfile => '/tmp/driftfile' }"
      apply_manifest(pp, :catch_failures => true)
    end

    describe file('/etc/ntp.conf') do
      it { should be_file }
      it { should contain 'driftfile /tmp/driftfile' }
    end
  end

  describe 'keys' do
    it 'enables the key parameters' do
      pp = <<-EOS
      class { 'ntp':
        keys_enable     => true,
        keys_file       => '/etc/ntp/keys',
        keys_controlkey => '/etc/ntp/controlkey',
        keys_requestkey => '1',
        keys_trusted    => [ '1', '2' ],
      }
      EOS
      # Rely on a shell command instead of a file{} here to avoid loops
      # within puppet when it tries to manage /etc/ntp/keys before /etc/ntp.
      shell("mkdir -p /etc/ntp && echo '1 M AAAABBBB' >> /etc/ntp/keys")
      apply_manifest(pp, :catch_failures => true)
    end

    describe file('/etc/ntp.conf') do
      it { should be_file }
      it { should contain 'keys /etc/ntp/keys' }
      it { should contain 'controlkey /etc/ntp/controlkey' }
      it { should contain 'requestkey 1' }
      it { should contain 'trustedkey 1 2' }
    end
  end

  describe 'package' do
    it 'installs the right package' do
      pp = <<-EOS
      class { 'ntp':
        package_ensure => present,
        package_name   => ['#{packagename}'],
      }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe package(packagename) do
      it { should be_installed }
    end
  end

  describe 'panic => false' do
    it 'enables the tinker panic setting' do
      pp = <<-EOS
      class { 'ntp':
        panic => false,
      }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe file('/etc/ntp.conf') do
      it { should contain 'tinker panic' }
    end
  end

  describe 'panic => true' do
    it 'disables the tinker panic setting' do
      pp = <<-EOS
      class { 'ntp':
        panic => true,
      }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe file('/etc/ntp.conf') do
      it { should_not contain 'tinker panic 0' }
    end
  end

  describe 'udlc' do
    it 'adds a udlc' do
      pp = "class { 'ntp': udlc => true }"
      apply_manifest(pp, :catch_failures => true)
    end

    describe file('/etc/ntp.conf') do
      it { should be_file }
      it { should contain '127.127.1.0' }
    end
  end

end
require 'spec_helper_acceptance'

case fact('osfamily')
when 'RedHat', 'FreeBSD', 'Linux', 'Gentoo'
  servicename = 'ntpd'
when 'AIX'
  servicename = 'xntpd'
else
  servicename = 'ntp'
end

describe 'ntp::service class', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
  describe 'basic test' do
    it 'sets up the service' do
      apply_manifest(%{
        class { 'ntp': }
      }, :catch_failures => true)
    end

    describe service(servicename) do
      it { should be_enabled }
      it { should be_running }
    end
  end

  describe 'service parameters' do
    it 'starts the service' do
      pp = <<-EOS
      class { 'ntp':
        service_enable => true,
        service_ensure => running,
        service_manage => true,
        service_name   => '#{servicename}'
      }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe service(servicename) do
      it { should be_running }
      it { should be_enabled }
    end
  end

  describe 'service is unmanaged' do
    it 'shouldnt stop the service' do
      pp = <<-EOS
      class { 'ntp':
        service_enable => false,
        service_ensure => stopped,
        service_manage => false,
        service_name   => '#{servicename}'
      }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    describe service(servicename) do
      it { should be_running }
      it { should be_enabled }
    end
  end
end
require 'spec_helper_acceptance'

describe 'preferred servers', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
  pp = <<-EOS
      class { '::ntp':
        servers           => ['a', 'b', 'c', 'd'],
        preferred_servers => ['c', 'd'],
      }
  EOS

  it 'applies cleanly' do
    apply_manifest(pp, :catch_failures => true) do |r|
      expect(r.stderr).to eq("")
    end
  end

  describe file('/etc/ntp.conf') do
    it { should be_file }
    it { should contain 'server a' }
    it { should contain 'server b' }
    it { should contain 'server c prefer' }
    it { should contain 'server d prefer' }
  end
end
require 'spec_helper_acceptance'

describe "ntp class with restrict:", :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
  context 'should run successfully' do
    pp = "class { 'ntp': restrict => ['test restrict']}"

    it 'runs twice' do
      2.times do
        apply_manifest(pp, :catch_failures => true) do |r|
          expect(r.stderr).to be_empty
        end
      end
    end
  end

  describe file('/etc/ntp.conf') do
    it { should contain('test restrict') }
  end

end
require 'spec_helper_acceptance'

describe 'unsupported distributions and OSes', :if => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
  it 'should fail' do
    pp = <<-EOS
    class { 'ntp': }
    EOS
    expect(apply_manifest(pp, :expect_failures => true).stderr).to match(/is not supported on an/i)
  end
end
require 'spec_helper'

describe 'ntp' do

  ['Debian', 'RedHat','SuSE', 'FreeBSD', 'Archlinux', 'Gentoo', 'Gentoo (Facter < 1.7)'].each do |system|
    if system == 'Gentoo (Facter < 1.7)'
      let(:facts) {{ :osfamily => 'Linux', :operatingsystem => 'Gentoo' }}
    else
      let(:facts) {{ :osfamily => system }}
    end

    it { should include_class('ntp::install') }
    it { should include_class('ntp::config') }
    it { should include_class('ntp::service') }

    describe "ntp::config on #{system}" do
      it { should contain_file('/etc/ntp.conf').with_owner('0') }
      it { should contain_file('/etc/ntp.conf').with_group('0') }
      it { should contain_file('/etc/ntp.conf').with_mode('0644') }

      describe 'allows template to be overridden' do
        let(:params) {{ :config_template => 'my_ntp/ntp.conf.erb' }}
        it { should contain_file('/etc/ntp.conf').with({
          'content' => /server foobar/})
        }
      end

      describe "keys for osfamily #{system}" do
        context "when enabled" do
          let(:params) {{
            :keys_enable     => true,
            :keys_file       => '/etc/ntp/ntp.keys',
            :keys_trusted    => ['1', '2', '3'],
            :keys_controlkey => '2',
            :keys_requestkey => '3',
          }}

          it { should contain_file('/etc/ntp').with({
            'ensure'  => 'directory'})
          }
          it { should contain_file('/etc/ntp.conf').with({
            'content' => /trustedkey 1 2 3/})
          }
          it { should contain_file('/etc/ntp.conf').with({
            'content' => /controlkey 2/})
          }
          it { should contain_file('/etc/ntp.conf').with({
            'content' => /requestkey 3/})
          }
        end
      end

      context "when disabled" do
        let(:params) {{
          :keys_enable     => false,
          :keys_file       => '/etc/ntp/ntp.keys',
          :keys_trusted    => ['1', '2', '3'],
          :keys_controlkey => '2',
          :keys_requestkey => '3',
        }}

        it { should_not contain_file('/etc/ntp').with({
          'ensure'  => 'directory'})
        }
        it { should_not contain_file('/etc/ntp.conf').with({
          'content' => /trustedkey 1 2 3/})
        }
        it { should_not contain_file('/etc/ntp.conf').with({
          'content' => /controlkey 2/})
        }
        it { should_not contain_file('/etc/ntp.conf').with({
          'content' => /requestkey 3/})
        }
      end

      describe 'preferred servers' do
        context "when set" do
          let(:params) {{
            :servers           => ['a', 'b', 'c', 'd'],
            :preferred_servers => ['a', 'b']
          }}

          it { should contain_file('/etc/ntp.conf').with({
            'content' => /server a prefer\nserver b prefer\nserver c\nserver d/})
          }
        end
        context "when not set" do
          let(:params) {{
            :servers           => ['a', 'b', 'c', 'd'],
            :preferred_servers => []
          }}

          it { should_not contain_file('/etc/ntp.conf').with({
            'content' => /server a prefer/})
          }
        end
      end

      describe "ntp::install on #{system}" do
        let(:params) {{ :package_ensure => 'present', :package_name => ['ntp'], }}

        it { should contain_package('ntp').with(
          :ensure => 'present',
          :name   => 'ntp'
        )}

        describe 'should allow package ensure to be overridden' do
          let(:params) {{ :package_ensure => 'latest', :package_name => ['ntp'] }}
          it { should contain_package('ntp').with_ensure('latest') }
        end

        describe 'should allow the package name to be overridden' do
          let(:params) {{ :package_ensure => 'present', :package_name => ['hambaby'] }}
          it { should contain_package('ntp').with_name('hambaby') }
        end
      end

      describe 'ntp::service' do
        let(:params) {{
          :service_manage => true,
          :service_enable => true,
          :service_ensure => 'running',
          :service_name   => 'ntp'
        }}

        describe 'with defaults' do
          it { should contain_service('ntp').with(
            :enable => true,
            :ensure => 'running',
            :name   => 'ntp'
          )}
        end

        describe 'service_ensure' do
          describe 'when overridden' do
            let(:params) {{ :service_name => 'ntp', :service_ensure => 'stopped' }}
            it { should contain_service('ntp').with_ensure('stopped') }
          end
        end

        describe 'service_manage' do
          let(:params) {{
            :service_manage => false,
            :service_enable => true,
            :service_ensure => 'running',
            :service_name   => 'ntpd',
          }}

          it 'when set to false' do
            should_not contain_service('ntp').with({
              'enable' => true,
              'ensure' => 'running',
              'name'   => 'ntpd'
            })
          end
        end
      end
    end

    context 'ntp::config' do
      describe "for operating system Gentoo (Facter < 1.7)" do
        let(:facts) {{ :operatingsystem => 'Gentoo',
                       :osfamily        => 'Linux' }}

        it 'uses the NTP pool servers by default' do
          should contain_file('/etc/ntp.conf').with({
            'content' => /server \d.gentoo.pool.ntp.org/,
          })
        end
      end

      describe "on osfamily Gentoo" do
        let(:facts) {{ :osfamily => 'Gentoo' }}

        it 'uses the NTP pool servers by default' do
          should contain_file('/etc/ntp.conf').with({
            'content' => /server \d.gentoo.pool.ntp.org/,
          })
        end
      end

      describe "on osfamily Debian" do
        let(:facts) {{ :osfamily => 'debian' }}

        it 'uses the debian ntp servers by default' do
          should contain_file('/etc/ntp.conf').with({
            'content' => /server \d.debian.pool.ntp.org iburst/,
          })
        end
      end

      describe "on osfamily RedHat" do
        let(:facts) {{ :osfamily => 'RedHat' }}

        it 'uses the redhat ntp servers by default' do
          should contain_file('/etc/ntp.conf').with({
            'content' => /server \d.centos.pool.ntp.org/,
          })
        end
      end

      describe "on osfamily SuSE" do
        let(:facts) {{ :osfamily => 'SuSE' }}

        it 'uses the opensuse ntp servers by default' do
          should contain_file('/etc/ntp.conf').with({
            'content' => /server \d.opensuse.pool.ntp.org/,
          })
        end
      end

      describe "on osfamily FreeBSD" do
        let(:facts) {{ :osfamily => 'FreeBSD' }}

        it 'uses the freebsd ntp servers by default' do
          should contain_file('/etc/ntp.conf').with({
            'content' => /server \d.freebsd.pool.ntp.org iburst maxpoll 9/,
          })
        end
      end

      describe "on osfamily ArchLinux" do
        let(:facts) {{ :osfamily => 'ArchLinux' }}

        it 'uses the NTP pool servers by default' do
          should contain_file('/etc/ntp.conf').with({
            'content' => /server \d.pool.ntp.org/,
          })
        end
      end

      describe "for operating system family unsupported" do
        let(:facts) {{
          :osfamily  => 'unsupported',
        }}

        it { expect{ subject }.to raise_error(
          /^The ntp module is not supported on an unsupported based system./
        )}
      end
    end

    describe 'for virtual machines' do
      let(:facts) {{ :osfamily        => 'Archlinux',
                     :is_virtual      => 'true' }}

      it 'should not use local clock as a time source' do
        should_not contain_file('/etc/ntp.conf').with({
          'content' => /server.*127.127.1.0.*fudge.*127.127.1.0 stratum 10/,
        })
      end

      it 'allows large clock skews' do
        should contain_file('/etc/ntp.conf').with({
          'content' => /tinker panic 0/,
        })
      end
    end

    describe 'for physical machines' do
      let(:facts) {{ :osfamily        => 'Archlinux',
                     :is_virtual      => 'false' }}

      it 'disallows large clock skews' do
        should_not contain_file('/etc/ntp.conf').with({
          'content' => /tinker panic 0/,
        })
      end
    end
  end

end
#my uber ntp config
#

server foobar
s
mtime
require 'puppetlabs_spec_helper/module_spec_helper'
require 'beaker-rspec'

UNSUPPORTED_PLATFORMS = [ 'windows', 'Solaris' ]

unless ENV['RS_PROVISION'] == 'no'
  hosts.each do |host|
    # Install Puppet
    if host.is_pe?
      install_pe
    else
      install_package host, 'rubygems'
      on host, 'gem install puppet --no-ri --no-rdoc'
      on host, "mkdir -p #{host['distmoduledir']}"
    end
  end
end

RSpec.configure do |c|
  # Project root
  proj_root = File.expand_path(File.join(File.dirname(__FILE__), '..'))

  # Readable test descriptions
  c.formatter = :documentation

  # Configure all nodes in nodeset
  c.before :suite do
    # Install module and dependencies
    puppet_module_install(:source => proj_root, :module_name => 'ntp')
    hosts.each do |host|
      shell("/bin/touch #{default['puppetpath']}/hiera.yaml")
      shell('puppet module install puppetlabs-stdlib', :acceptable_exit_codes => [0,1])
    end
  end
end
Provider Specs
==============

Define specs for your providers under this directory.
Resource Type Specs
===================

Define specs for your resource types in this directory.
# ntp.conf: Managed by puppet.
#
<% if @panic == false -%>
# Keep ntpd from panicking in the event of a large clock skew
# when a VM guest is suspended and resumed.
tinker panic 0
<% end -%>

<% if @restrict != [] -%>
# Permit time synchronization with our time source, but do not
# permit the source to query or modify the service on this system.
<% @restrict.flatten.each do |restrict| -%>
restrict <%= restrict %>
<% end %>
<% end -%>

<% [@servers].flatten.each do |server| -%>
server <%= server %><% if @preferred_servers.include?(server) -%> prefer<% end %>
<% end -%>

<% if scope.lookupvar('::is_virtual') == "false" or @udlc -%>
# Undisciplined Local Clock. This is a fake driver intended for backup
# and when no outside source of synchronized time is available. 
server	127.127.1.0 
fudge	127.127.1.0 stratum 10
restrict 127.127.1.0
<% end -%>

# Driftfile.
driftfile <%= @driftfile %>

<% if @keys_enable -%>
keys <%= @keys_file %>
<% unless @keys_trusted.empty? -%>
trustedkey <%= @keys_trusted.join(' ') %>
<% end -%>
<% if @keys_requestkey != '' -%>
requestkey <%= @keys_requestkey %>
<% end -%>
<% if @keys_controlkey != '' -%>
controlkey <%= @keys_controlkey %>
<% end -%>
<% end -%>
node default {

  notify { 'enduser-before': }
  notify { 'enduser-after': }

  class { 'ntp':
    require => Notify['enduser-before'],
    before  => Notify['enduser-after'],
  }

}
fixtures:
  repositories:
    "puppi": "git://github.com/example42/puppi.git"
    "monitor": "git://github.com/example42/puppet-monitor.git"
    "firewall": "git://github.com/example42/puppet-firewall.git"
    "iptables": "git://github.com/example42/puppet-iptables.git"
    "concat": "git://github.com/example42/puppet-concat.git"
  symlinks:
    "php": "#{source_dir}"

source :rubygems

puppetversion = ENV['PUPPET_VERSION']
gem 'puppet', puppetversion, :require => false
gem 'puppet-lint'
gem 'puppetlabs_spec_helper', '>= 0.1.0'
language: ruby
rvm:
  - 1.8.7
  - 1.9.3
script:
  - "rake spec SPEC_OPTS='--format documentation'"
env:
  - PUPPET_VERSION="~> 2.6.0"
  - PUPPET_VERSION="~> 2.7.0"
  - PUPPET_VERSION="~> 3.0.0"
  - PUPPET_VERSION="~> 3.1.0"
matrix:
  exclude:
    - rvm: 1.9.3
      env: PUPPET_VERSION="~> 2.6.0"
      gemfile: .gemfile

gemfile: .gemfile
notifications:
  email:
    - al@lab42.it
Copyright (C) 2013 Alessandro Franceschi / Lab42

for the relevant commits Copyright (C) by the respective authors.

Contact Lab42 at: info@lab42.it

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
name    'example42-php'
version '2.0.17'
author  'Alessandro Franceschi'
license 'Apache2'
project_page 'http://www.example42.com'
source  'https://github.com/example42/puppet-php'
summary 'Puppet module for php'
description 'This module installs and manages php. Check README.rdoc for details. Puppi is required for some common functions: you can install them without using the whole module. Monitor and firewall dependencies are needed only if the relevant features are enabled'
dependency 'example42/puppi', '>= 2.0.0'
# Puppet module: php

This is a Puppet module for php based on the second generation layout ("NextGen") of Example42 Puppet Modules.

Made by ALessandro Franceschi / Lab42

Official site: http://www.example42.com

Official git repository: http://github.com/example42/puppet-php

Released under the terms of Apache 2 License.

This module requires functions provided by the Example42 Puppi module (you need it even if you don't use and install Puppi)

For detailed info about the logic and usage patterns of Example42 modules check the DOCS directory on Example42 main modules set.

## USAGE - Basic management

* Install php with default settings

        class { 'php': }

* Install a specific version of php package

        class { 'php':
          version => '1.0.1',
        }

* Remove php package

        class { 'php':
          absent => true
        }

* Enable auditing without without making changes on existing php configuration files

        class { 'php':
          audit_only => true
        }

* Install php in an nginx environment

        class { 'php':
          service => 'nginx'
        }

## USAGE - Module installation

* Install a new module

        php::module { "imagick": }

* Install a specific version of a module:

        php::module { "imagick":
          version => '1.0.1';
        }

* Remove php module

        php::module { "imagick":
            absent => true,
        }

* By default module package name is php-$title for RedHat and php5-$title . You can override this prefix.

        php::module { "apc":
          module_prefix => "php-"
        }


## USAGE - Pear Management

* Install a pear package

        php::pear::module { "XML_Util": }

* Install a pear package from a remote repository

        php::pear::module { 'PHPUnit':
          repository  => 'pear.phpunit.de',
          use_package => 'no',
        }

* Install a pear package will all dependencies (--alldeps)

        php::pear::module { 'PHPUnit':
          repository  => 'pear.phpunit.de',
          alldeps => 'true',
        }

* Set a config option

        php::pear::config { http_proxy: value => "myproxy:8080" }


## USAGE - Pecl Management

* Install a pecl package

        php::pecl::module { "XML_Util": }

* Install a pecl package from source specifying the preferred state (note that you must have the package 'make' installed on your system)

        php::pecl::module { "xhprof":
          use_package     => 'false',
          preferred_state => 'beta',
        }

* Set a config option

        php::pecl::config { http_proxy: value => "myproxy:8080" }


## USAGE - Overrides and Customizations
* Use custom sources for main config file.

        class { 'php':
          source => [ "puppet:///modules/lab42/php/php.conf-${hostname}" , "puppet:///modules/lab42/php/php.conf" ],
        }

* Manage php.ini files on Debian and Suse derivatives. Here the main config file path (managed with the source/template params) defaults to /etc/php5/apache2/php.ini. To manage other files, either set a different path in config_file or use the php::conf define.

        class { 'php':
          config_file => '/etc/php5/apache2/php.ini',      # Default value on Ubuntu/Suse
          template    => 'example42/php/php.ini-apache2.erb',
        }

        php::conf { 'php.ini-cli':
          path     => '/etc/php5/cli/php.ini',
          template => 'example42/php/php.ini-cli.erb',
        }

* Use custom source directory for the whole configuration dir

        class { 'php':
          source_dir       => 'puppet:///modules/lab42/php/conf/',
          source_dir_purge => false, # Set to true to purge any existing file not present in $source_dir
        }

* Use custom template for main config file. Note that template and source arguments are alternative.

        class { 'php':
          template => 'example42/php/php.conf.erb',
        }

* Automatically include a custom subclass

        class { 'php':
          my_class => 'php::example42',
        }





[![Build Status](https://travis-ci.org/example42/puppet-php.png?branch=master)](https://travis-ci.org/example42/puppet-php)
require 'rubygems'
require 'puppetlabs_spec_helper/rake_tasks'
require 'puppet-lint'
PuppetLint.configuration.send("disable_80chars")
PuppetLint.configuration.send('disable_class_parameter_defaults')
Facter.add("php_fact_extension_dir") do
  setcode do
    Facter::Util::Resolution.exec('php-config --extension-dir')    || nil
  end
end
Facter.add("php_fact_version") do
  setcode do
    Facter::Util::Resolution.exec('php-config --version')    || nil
  end
end
# = Define: php::augeas
#
# Manage php.ini through augeas
#
# Here's an example how to find the augeas path to a variable:
#
#     # augtool --noload
#     augtool> rm /augeas/load
#     rm : /augeas/load 781
#     augtool> set /augeas/load/myfile/lens @PHP
#     augtool> set /augeas/load/myfile/incl /usr/local/etc/php5/cgi/php.ini
#     augtool> load
#     augtool> print
#     ...
#     /files/usr/local/etc/php5/cgi/php.ini/soap/soap.wsdl_cache_limit = "5"
#     /files/usr/local/etc/php5/cgi/php.ini/ldap/ldap.max_links = "-1"
#     ...
#     augtool> exit
#     #
#
# The part after 'php.ini/' is what you need to use as 'entry'.
#
# == Parameters
#
# [*entry*]
#   Augeas path to entry to be modified.
#
# [*ensure*]
#   Standard puppet ensure variable
#
# [*target*]
#   Which php.ini to manipulate. Default is $php::config_file
#
# [*value*]
#   Value to set
#
# == Examples
#
# php::augeas {
#   'php-memorylimit':
#     entry  => 'PHP/memory_limit',
#     value  => '128M';
#   'php-error_log':
#     entry  => 'PHP/error_log',
#     ensure => absent;
#   'php-sendmail_path':
#     entry  => 'mail function/sendmail_path',
#     value  => '/usr/sbin/sendmail -t -i -f info@example.com';
#   'php-date_timezone':
#     entry  => 'Date/date.timezone',
#     value  => 'Europe/Amsterdam';
# }
#
define php::augeas (
  $entry,
  $ensure = present,
  $target = $php::config_file,
  $value  = '',
  ) {

  include php

  $service = $php::service

  $changes = $ensure ? {
    present => [ "set '${entry}' '${value}'" ],
    absent  => [ "rm '${entry}'" ],
  }

  augeas { "php_ini-${name}":
    incl    => $target,
    lens    => 'Php.lns',
    changes => $changes,
  }

}
#
# = Define: php::conf
#
# With this define you can manage any php configuration file
# You have 3 parameters to provide it: source, template and content.
#
# == Parameters
#
# [*template*]
#   String. Optional. Default: undef. Alternative to: source, content.
#   Sets the module path of a custom template to use as content of
#   the config file
#   When defined, config file has: content => content($template),
#   Example: template => 'site/php/my.conf.erb',
#
# [*content*]
#   String. Optional. Default: undef. Alternative to: template, source.
#   Sets directly the value of the file's content parameter
#   When defined, config file has: content => $content,
#   Example: content => "# File Managed by Puppet \n",
#
# [*source*]
#   String. Optional. Default: undef. Alternative to: template, content.
#   Sets the value of the file's source parameter
#   When defined, config file has: source => $source,
#   Example: source => 'puppet:///site/php/my.conf',
#
# [*ensure*]
#   String. Default: present
#   Manages config file presence. Possible values:
#   * 'present' - Create and manages the file.
#   * 'absent' - Remove the file.
#
# [*path*]
#   String. Optional. Default: $config_dir/$title
#   The path of the created config file. If not defined a file
#   name like the  the name of the title a custom template to use as content of configfile
#   If defined, configfile file has: content => content("$template")
#
# [*mode*] [*owner*] [*group*] [*notify*] [*replace*]
#   String. Optional. Default: undef
#   All these parameters map directly to the created file attributes.
#   If not defined the module's defaults are used.
#   If defined, config file file has, for example: mode => $mode
#
# [*options_hash*]
#   Hash. Default undef. Needs: 'template'.
#   An hash of custom options to be used in templates to manage any key pairs of
#   arbitrary settings.
#
define php::conf (

  $source       = undef,
  $template     = undef,
  $content      = undef,

  $path         = undef,
  $mode         = undef,
  $owner        = undef,
  $group        = undef,
  $notify       = undef,
  $replace      = undef,

  $options_hash = undef,

  $ensure       = present ) {

  validate_re($ensure, ['present','absent'], 'Valid values are: present, absent. WARNING: If set to absent the conf file is removed.')

  include php

  $managed_path = $path ? {
    undef   => "${php::config_dir}/${name}",
    default => $path,
  }

  $managed_content = $content ? {
    undef   => $template ? {
      undef => undef,
      default => template($template),
    },
    default => $content,
  }

  $managed_mode = $mode ? {
    undef   => $php::config_file_mode,
    default => $mode,
  }

  $managed_owner = $owner ? {
    undef   => $php::config_file_owner,
    default => $owner,
  }

  $managed_group = $group ? {
    undef   => $php::config_file_group,
    default => $group,
  }

  file { "php_conf_${name}":
    ensure  => $ensure,
    source  => $source,
    content => $managed_content,
    path    => $managed_path,
    mode    => $managed_mode,
    owner   => $managed_owner,
    group   => $managed_group,
    notify  => $notify,
    replace => $replace,
  }

}
# Class php::devel
#
# Installs php devel package
#
class php::devel {

  if $php::package_devel != ''
  and ! defined(Package[$php::package_devel]) {
    package { $php::package_devel :
      ensure => $php::manage_package,
    }
  }
}
# = Define: php::ini
#
define php::ini (
    $value       = '',
    $template    = 'extra-ini.erb',
    $target      = 'extra.ini',
    $service     = $php::service,
    $config_dir  = $php::config_dir
) {

  include php

  file { "${config_dir}/conf.d/${target}":
    ensure  => 'present',
    content => template("php/${template}"),
    require => Package['php'],
    notify  => Service[$service],
  }

  file { "${config_dir}/cli/conf.d/${target}":
    ensure  => 'present',
    content => template("php/${template}"),
    require => Package['php'],
  }

}
# = Class: php
#
# This is the main php class
#
#
# == Parameters
#
# Module specific parameters
# [*package_devel*]
#   Name of the php-devel package
#
# [*package_pear*]
#   Name of the php-pear package
#
# Standard class parameters
# Define the general class behaviour and customizations
#
# [*my_class*]
#   Name of a custom class to autoload to manage module's customizations
#   If defined, php class will automatically "include $my_class"
#   Can be defined also by the (top scope) variable $php_myclass
#
# [*service*]
#   The service that runs the php interpreter. Defines what service gets
#   notified. Default: apache2|httpd.
#
# [*source*]
#   Sets the content of source parameter for main configuration file
#   If defined, php main config file will have the param: source => $source
#   Can be defined also by the (top scope) variable $php_source
#
# [*source_dir*]
#   If defined, the whole php configuration directory content is retrieved
#   recursively from the specified source
#   (source => $source_dir , recurse => true)
#   Can be defined also by the (top scope) variable $php_source_dir
#
# [*source_dir_purge*]
#   If set to true (default false) the existing configuration directory is
#   mirrored with the content retrieved from source_dir
#   (source => $source_dir , recurse => true , purge => true, force => true)
#   Can be defined also by the (top scope) variable $php_source_dir_purge
#
# [*template*]
#   Sets the path to the template to use as content for main configuration file
#   If defined, php main config file has: content => content("$template")
#   Note source and template parameters are mutually exclusive: don't use both
#   Can be defined also by the (top scope) variable $php_template
#
# [*augeas*]
#   If set to true (default false), the php.ini will be managed through
#   augeas. This will make php::pecl automatically add extensions to the
#   php.ini.
#   Can be defined also by the (top scope) variable $php_augeas
#
# [*options*]
#   An hash of custom options to be used in templates for arbitrary settings.
#   Can be defined also by the (top scope) variable $php_options
#
# [*version*]
#   The package version, used in the ensure parameter of package type.
#   Default: present. Can be 'latest' or a specific version number.
#   Note that if the argument absent (see below) is set to true, the
#   package is removed, whatever the value of version parameter.
#
# [*absent*]
#   Set to 'true' to remove package(s) installed by module
#   Can be defined also by the (top scope) variable $php_absent
#
# [*puppi*]
#   Set to 'true' to enable creation of module data files that are used by puppi
#   Can be defined also by the (top scope) variables $php_puppi and $puppi
#
# [*puppi_helper*]
#   Specify the helper to use for puppi commands. The default for this module
#   is specified in params.pp and is generally a good choice.
#   You can customize the output of puppi commands for this module using another
#   puppi helper. Use the define puppi::helper to create a new custom helper
#   Can be defined also by the (top scope) variables $php_puppi_helper
#   and $puppi_helper
#
# [*debug*]
#   Set to 'true' to enable modules debugging
#   Can be defined also by the (top scope) variables $php_debug and $debug
#
# [*audit_only*]
#   Set to 'true' if you don't intend to override existing configuration files
#   and want to audit the difference between existing files and the ones
#   managed by Puppet.
#   Can be defined also by the (top scope) variables $php_audit_only
#   and $audit_only
#
# Default class params - As defined in php::params.
# Note that these variables are mostly defined and used in the module itself,
# overriding the default values might not affected all the involved components.
# Set and override them only if you know what you're doing.
# Note also that you can't override/set them via top scope variables.
#
# [*package*]
#   The name of php package
#
# [*config_dir*]
#   Main configuration directory. Used by puppi
#
# [*config_file*]
#   Main configuration file path
#
# [*config_file_mode*]
#   Main configuration file path mode
#
# [*config_file_owner*]
#   Main configuration file path owner
#
# [*config_file_group*]
#   Main configuration file path group
#
# [*config_file_init*]
#   Path of configuration file sourced by init script
#
# [*pid_file*]
#   Path of pid file. Used by monitor
#
# [*data_dir*]
#   Path of application data directory. Used by puppi
#
# [*log_dir*]
#   Base logs directory. Used by puppi
#
# [*log_file*]
#   Log file(s). Used by puppi
#
# == Examples
#
# You can use this class in 2 ways:
# - Set variables (at top scope level on in a ENC) and "include php"
# - Call php as a parametrized class
#
# See README for details.
#
#
class php (
  $package_devel       = params_lookup( 'package_devel' ),
  $package_pear        = params_lookup( 'package_pear' ),
  $my_class            = params_lookup( 'my_class' ),
  $service             = params_lookup( 'service' ),
  $service_autorestart = params_lookup( 'service_autorestart' ),
  $source              = params_lookup( 'source' ),
  $source_dir          = params_lookup( 'source_dir' ),
  $source_dir_purge    = params_lookup( 'source_dir_purge' ),
  $template            = params_lookup( 'template' ),
  $augeas              = params_lookup( 'augeas' ),
  $options             = params_lookup( 'options' ),
  $version             = params_lookup( 'version' ),
  $absent              = params_lookup( 'absent' ),
  $monitor             = params_lookup( 'monitor' , 'global' ),
  $monitor_tool        = params_lookup( 'monitor_tool' , 'global' ),
  $monitor_target      = params_lookup( 'monitor_target' , 'global' ),
  $puppi               = params_lookup( 'puppi' , 'global' ),
  $puppi_helper        = params_lookup( 'puppi_helper' , 'global' ),
  $debug               = params_lookup( 'debug' , 'global' ),
  $audit_only          = params_lookup( 'audit_only' , 'global' ),
  $package             = params_lookup( 'package' ),
  $module_prefix       = params_lookup( 'module_prefix' ),
  $config_dir          = params_lookup( 'config_dir' ),
  $config_file         = params_lookup( 'config_file' ),
  $config_file_mode    = params_lookup( 'config_file_mode' ),
  $config_file_owner   = params_lookup( 'config_file_owner' ),
  $config_file_group   = params_lookup( 'config_file_group' ),
  $config_file_init    = params_lookup( 'config_file_init' ),
  $pid_file            = params_lookup( 'pid_file' ),
  $data_dir            = params_lookup( 'data_dir' ),
  $log_dir             = params_lookup( 'log_dir' ),
  $log_file            = params_lookup( 'log_file' ),
  $port                = params_lookup( 'port' ),
  $protocol            = params_lookup( 'protocol' )
  ) inherits php::params {

  $bool_service_autorestart=any2bool($service_autorestart)
  $bool_source_dir_purge=any2bool($source_dir_purge)
  $bool_augeas=any2bool($augeas)
  $bool_absent=any2bool($absent)
  $bool_monitor=any2bool($monitor)
  $bool_puppi=any2bool($puppi)
  $bool_debug=any2bool($debug)
  $bool_audit_only=any2bool($audit_only)

  ### Definition of some variables used in the module
  $manage_package = $php::bool_absent ? {
    true  => 'absent',
    false => $php::version,
  }

  $manage_file = $php::bool_absent ? {
    true    => 'absent',
    default => 'present',
  }

  if $php::bool_absent == true {
    $manage_monitor = false
  } else {
    $manage_monitor = true
  }

  $manage_audit = $php::bool_audit_only ? {
    true  => 'all',
    false => undef,
  }

  $manage_file_replace = $php::bool_audit_only ? {
    true  => false,
    false => true,
  }

  if ($php::source and $php::template) {
    fail ('PHP: cannot set both source and template')
  }
  if ($php::source and $php::bool_augeas) {
    fail ('PHP: cannot set both source and augeas')
  }
  if ($php::template and $php::bool_augeas) {
    fail ('PHP: cannot set both template and augeas')
  }

  $manage_file_source = $php::source ? {
    ''        => undef,
    default   => $php::source,
  }

  $manage_file_content = $php::template ? {
    ''        => undef,
    default   => template($php::template),
  }

  ### Managed resources
  package { 'php':
    ensure => $php::manage_package,
    name   => $php::package,
  }

  file { 'php.conf':
    ensure  => $php::manage_file,
    path    => $php::config_file,
    mode    => $php::config_file_mode,
    owner   => $php::config_file_owner,
    group   => $php::config_file_group,
    require => Package['php'],
    source  => $php::manage_file_source,
    content => $php::manage_file_content,
    replace => $php::manage_file_replace,
    audit   => $php::manage_audit,
  }

  # The whole php configuration directory can be recursively overriden
  if $php::source_dir {
    file { 'php.dir':
      ensure  => directory,
      path    => $php::config_dir,
      require => Package['php'],
      source  => $php::source_dir,
      recurse => true,
      purge   => $php::bool_source_dir_purge,
      force   => $php::bool_source_dir_purge,
      replace => $php::manage_file_replace,
      audit   => $php::manage_audit,
    }
  }


  ### Include custom class if $my_class is set
  if $php::my_class {
    include $php::my_class
  }


  ### Provide puppi data, if enabled ( puppi => true )
  if $php::bool_puppi == true {
    $classvars=get_class_args()
    puppi::ze { 'php':
      ensure    => $php::manage_file,
      variables => $classvars,
      helper    => $php::puppi_helper,
    }
  }


  ### Debugging, if enabled ( debug => true )
  if $php::bool_debug == true {
    file { 'debug_php':
      ensure  => $php::manage_file,
      path    => "${settings::vardir}/debug-php",
      mode    => '0640',
      owner   => 'root',
      group   => 'root',
      content => inline_template('<%= scope.to_hash.reject { |k,v| k.to_s =~ /(uptime.*|path|timestamp|free|.*password.*|.*psk.*|.*key)/ }.to_yaml %>'),
    }
  }

}
# = Define: php::module
#
# This define installs and configures php modules
# On Debian and derivatives it install module named php5-${name}
# On RedHat and derivatives it install module named php-${name}
# If you need a custom prefix you can overload default $module_prefix parameter
#
# == Parameters
#
# [*version*]
#   Version to install.
#
# [*absent*]
#   true to ensure package isn't installed.
#
# [*notify_service*]
#   If you want to restart a service automatically when
#   the module is applied. Default: true
#
# [*service_autorestart*]
#   whatever we want a module installation notify a service to restart.
#
# [*service*]
#   Service to restart.
#
# [*module_prefix*]
#   If package name prefix isn't standard.
#
# == Examples
# php::module { 'gd': }
#
# php::module { 'gd':
#   ensure => absent,
# }
#
# This will install php-apc on debian instead of php5-apc
#
# php::module { 'apc':
#   module_prefix => "php-",
# }
#
# Note that you may include or declare the php class when using
# the php::module define
#
define php::module (
  $version             = 'present',
  $service_autorestart = '',
  $module_prefix       = '',
  $absent              = ''
  ) {

  include php

  if $absent {
    $real_version = 'absent'
  } else {
    $real_version = $version
  }

  $real_service_autorestart = $service_autorestart ? {
    true    => "Service[${php::service}]",
    false   => undef,
    ''      => $php::service_autorestart ? {
      true    => "Service[${php::service}]",
      false   => undef,
    }
  }

  $real_module_prefix = $module_prefix ? {
    ''      => $php::module_prefix,
    default => $module_prefix,
  }

  $real_install_package = "${real_module_prefix}${name}"

  if defined(Package[$real_install_package]) == false {
    package { "PhpModule_${name}":
      ensure  => $real_version,
      name    => $real_install_package,
      notify  => $real_service_autorestart,
      require => Package['php'],
    }
  }

}
# Class: php::params
#
# This class defines default parameters used by the main module class php
# Operating Systems differences in names and paths are addressed here
#
# == Variables
#
# Refer to php class for the variables defined here.
#
# == Usage
#
# This class is not intended to be used directly.
# It may be imported or inherited by other classes
#
class php::params {

  $package_devel = $::operatingsystem ? {
    /(?i:Ubuntu|Debian|Mint)/ => 'php5-dev',
    /(?i:SLES|OpenSuSe)/      => 'php5-devel',
    default                   => 'php-devel',
  }

  $package_pear = $::operatingsystem ? {
    /(?i:Ubuntu|Debian|Mint)/ => 'php-pear',
    /(?i:SLES|OpenSuSe)/      => 'php5-pear',
    default                   => 'php-pear',
  }

  ### Application related parameters
  $module_prefix = $::operatingsystem ? {
    /(?i:Ubuntu|Debian|Mint|SLES|OpenSuSE)/ => 'php5-',
    default                                 => 'php-',
  }

  $pear_module_prefix = $::operatingsystem ? {
    /(?i:Ubuntu|Debian|Mint)/             => 'php-',
    /(?i:SLES|OpenSuSe)/                  => 'php5-pear-',
    /(?i:CentOS|RedHat|Scientific|Linux)/ => 'php-pear-',
    default                               => 'pear-',
  }

  $package = $::operatingsystem ? {
    /(?i:Ubuntu|Debian|Mint)/ => 'php5',
    /(?i:SLES|OpenSuSE)/      => [ 'php5','apache2-mod_php5'],
    default                   => 'php',
  }

  # Here it's not the php service script name but
  # web service name like apache2, nginx, etc.
  $service = $::operatingsystem ? {
    /(?i:Ubuntu|Debian|Mint|SLES|OpenSuSE)/ => 'apache2',
    default                                 => 'httpd',
  }

  $config_dir = $::operatingsystem ? {
    /(?i:Ubuntu|Debian|Mint|SLES|OpenSuSE)/ => '/etc/php5',
    default                                   => '/etc/php.d',
  }

  $config_file = $::operatingsystem ? {
    /(?i:Ubuntu|Debian|Mint)/ => '/etc/php5/php.ini',
    /(?i:SLES|OpenSuSE)/      => '/etc/php5/apache2/php.ini',
    default                   => '/etc/php.ini',
  }

  $config_file_mode = $::operatingsystem ? {
    default => '0644',
  }

  $config_file_owner = $::operatingsystem ? {
    default => 'root',
  }

  $config_file_group = $::operatingsystem ? {
    default => 'root',
  }

  $data_dir = $::operatingsystem ? {
    default => '',
  }

  $log_dir = $::operatingsystem ? {
    default => '',
  }

  $log_file = $::operatingsystem ? {
    default => '',
  }

  # General Settings
  $my_class = ''
  $source = ''
  $source_dir = ''
  $source_dir_purge = false
  $augeas = false
  $template = ''
  $options = ''
  $version = 'present'
  $service_autorestart = true
  $absent = false

  ### General module variables that can have a site or per module default
  $puppi = false
  $puppi_helper = 'standard'
  $debug = false
  $audit_only = false

}
# Class: php::pear
#
# Installs Pear for PHP module
#
# Usage:
# include php::pear
#
# == Parameters
#
# Standard class parameters
# Define the general class behaviour and customizations
#
# [*package*]
#   Name of the package to install. Defaults to 'php-pear'
#
# [*version*]
#   Version to install. Defaults to 'present'
#
# [*install_package*]
#   Boolean. Determines if any package should be installed to support the PEAR functionality.
#   Can be false if PEAR was already provided by another package or module.
#   Default: true
#
class php::pear (
  $package         = $php::package_pear,
  $install_package = true,
  $version         = 'present',
  $path            = '/usr/bin:/usr/sbin:/bin:/sbin'
  ) inherits php {

  if ( $install_package ) {
    package { 'php-pear':
      ensure => $version,
      name   => $package,
    }
  }

}
# Define: php::pear::config
#
# Configures pear
#
# Usage:
# php::pear::config { http_proxy: value => "myproxy:8080" }
#
define php::pear::config ($value) {

  include php::pear

  exec { "pear-config-set-${name}":
    command => "pear config-set ${name} ${value}",
    path    => $php::pear::path,
    unless  => "pear config-get ${name} | grep ${value}",
    require => Package['php-pear'],
  }

}
# Define: php::pear::module
#
# Installs the defined php pear component
#
# Variables:
# [*use_package*]
#   (default=true) - Tries to install pear module with the relevant OS package
#   If set to "no" it installs the module via pear command
#
# [*preferred_state*]
#   (default="stable") - Define which preferred state to use when installing
#   Pear modules via pear via command line (when use_package=false)
#
# [*alldeps*]
#   (default="false") - Define if all the available (optional) modules should
#   be installed. (when use_package=false)
#
# Usage:
# php::pear::module { packagename: }
# Example:
# php::pear::module { Crypt-CHAP: }
#
define php::pear::module (
  $service             = '',
  $use_package         = true,
  $preferred_state     = 'stable',
  $alldeps             = false,
  $version             = 'present',
  $repository          = 'pear.php.net',
  $service_autorestart = '',
  $module_prefix       = '',
  $path                = '/usr/bin:/usr/sbin:/bin:/sbin',
  $ensure              = 'present',
  $timeout             = 300
  ) {

  include php::pear

  $bool_use_package = any2bool($use_package)
  $bool_alldeps = any2bool($alldeps)
  $manage_alldeps = $bool_alldeps ? {
    true  => '--alldeps',
    false => '',
  }

  $pear_source = $version ? {
    'present' => "${repository}/${name}",
    default   => "${repository}/${name}-${version}",
  }

  $pear_exec_command = $ensure ? {
    present => "pear -d preferred_state=${preferred_state} install ${manage_alldeps} ${pear_source}",
    absent  => "pear uninstall -n ${pear_source}",
  }

  $pear_exec_require = $repository ? {
    'pear.php.net' => Package['php-pear'],
    default        => [ Package['php-pear'],Php::Pear::Config['auto_discover'] ],
  }

  $pear_exec_unless = $ensure ? {
    present => "pear info ${pear_source}",
    absent  => undef
  }

  $pear_exec_onlyif = $ensure ? {
    present => undef,
    absent  => "pear info ${pear_source}",
  }

  $real_service = $service ? {
    ''      => $php::service,
    default => $service,
  }

  $real_service_autorestart = $service_autorestart ? {
    true    => "Service[${real_service}]",
    false   => undef,
    ''      => $php::service_autorestart ? {
      true    => "Service[${real_service}]",
      false   => undef,
    }
  }

  $real_module_prefix = $module_prefix ? {
    ''      => $php::pear_module_prefix,
    default => $module_prefix,
  }
  $package_name = "${real_module_prefix}${name}"


  case $bool_use_package {
    true: {
      package { "pear-${name}":
        ensure  => $ensure,
        name    => $package_name,
        notify  => $real_service_autorestart,
      }
    }
    default: {
      if $repository != 'pear.php.net' {
        if !defined (Php::Pear::Config['auto_discover']) {
          php::pear::config { 'auto_discover':
            value => '1',
          }
        }
      }
      exec { "pear-${name}":
        command => $pear_exec_command,
        path    => $path,
        unless  => $pear_exec_unless,
        onlyif  => $pear_exec_onlyif,
        require => $pear_exec_require,
        timeout => $timeout,
      }
    }
  } # End Case

}
# Define: php::pecl::config
#
# Configures pecl
#
# Usage:
# php::pecl::config { http_proxy: value => "myproxy:8080" }
#
define php::pecl::config (
  $value,
  $layer = 'user',
  $path  = '/usr/bin:/bin:/usr/sbin:/sbin'
  ) {

  include php::pear

  exec { "pecl-config-set-${name}":
    command => "pecl config-set ${name} ${value} ${layer}",
    path    => $path,
    unless  => "pecl config-get ${name} | grep ${value}",
    require => Package['php-pear'],
  }

}
# Define: php::pecl::module
#
# Installs the defined php pecl component
#
# == Parameters
#
# [*service_autorestart*]
#   wathever we want a module installation notify a service to restart.
#
# [*service*]
#   Service to restart.
#
# [*use_package*]
#   Tries to install pecl module with the relevant package.
#   If set to "no" it installs the module via pecl command. Default: true
#
# [*preferred_state*]
#   Define which preferred state to use when installing Pear modules via pecl
#   command line (when use_package=no). Default: true
#
# [*auto_answer*]
#   The answer(s) to give to pecl prompts for unattended install
#
# [*verbose*]
#   (Optional) - If you want to see verbose pecl output during installation.
#   This can help to debug installation problems (missing packages) during
#   installation process. Default: false
#
# == Examples
# php::pecl::module { 'intl': }
#
# This will install xdebug from pecl source instead of using the package
#
# php::pecl::module { 'xdebug':.
#   use_package => "no",
# }
#
define php::pecl::module (
  $service_autorestart = $php::bool_service_autorestart,
  $service             = $php::service,
  $use_package         = 'yes',
  $preferred_state     = 'stable',
  $auto_answer         = '\\n',
  $ensure              = present,
  $path                = '/usr/bin:/usr/sbin:/bin:/sbin',
  $verbose             = false,
  $version             = '',
  $config_file         = $php::config_file) {

  include php
  include php::pear
  include php::devel

  $manage_service_autorestart = $service_autorestart ? {
    true    => $service ? {
      ''      => undef,
      default => "Service[${service}]",
    },
    false   => undef,
    undef   => undef,
  }

  $real_package_name = $::operatingsystem ? {
    ubuntu  => "php5-${name}",
    debian  => "php5-${name}",
    default => "php-${name}",
  }

  case $use_package {
    yes: {
      package { "php-${name}":
        ensure => $ensure,
        name   => $real_package_name,
        notify => $manage_service_autorestart,
      }
    }
    default: {

      $bool_verbose = any2bool($verbose)

      $pecl_exec_logoutput = $bool_verbose ? {
        true  => true,
        false => undef,
      }

      if $version != '' {
        $new_version = "-${version}"
      } else {
        $new_version = ''
      }

      $pecl_exec_command = $ensure ? {
        present => "printf \"${auto_answer}\" | pecl -d preferred_state=${preferred_state} install ${name}${new_version}",
        absent  => "pecl uninstall -n ${name}",
      }

      $pecl_exec_unless = $ensure ? {
        present => "pecl info ${name}",
        absent  => undef
      }

      $pecl_exec_onlyif = $ensure ? {
        present => undef,
        absent  => "pecl info ${name}",
      }

      exec { "pecl-${name}":
        command   => $pecl_exec_command,
        unless    => $pecl_exec_unless,
        onlyif    => $pecl_exec_onlyif,
        logoutput => $pecl_exec_logoutput,
        path      => $path,
        require   => [ Class['php::pear'], Class['php::devel']],
      }
      if $php::bool_augeas == true {
        php::augeas { "augeas-${name}":
          ensure => $ensure,
          entry  => "PHP/extension[. = \"${name}.so\"]",
          value  => "${name}.so",
          notify => $manage_service_autorestart,
          target => $config_file,
        }
      }
    }
  } # End Case
}
# Class: php::spec
#
# This class is used only for rpsec-puppet tests
# Can be taken as an example on how to do custom classes but should not
# be modified.
#
# == Usage
#
# This class is not intended to be used directly.
# Use it as reference
#
class php::spec inherits php {

  # This just a test to override the arguments of an existing resource
  # Note that you can achieve this same result with just:
  # class { "php": template => "php/spec.erb" }

  File['php.conf'] {
    content => template('php/spec.erb'),
  }

}
require "#{File.join(File.dirname(__FILE__),'..','spec_helper.rb')}"

describe 'php' do

  let(:title) { 'php' }
  let(:node) { 'rspec.example42.com' }
  let(:facts) { { :ipaddress => '10.42.42.42' } }

  describe 'Test standard installation' do
    it { should contain_package('php').with_ensure('present') }
    it { should contain_file('php.conf').with_ensure('present') }
  end

  describe 'Test installation of a specific version' do
    let(:params) { {:version => '1.0.42' } }
    it { should contain_package('php').with_ensure('1.0.42') }
  end

  describe 'Test decommissioning - absent' do
    let(:params) { {:absent => true, :monitor => true } }

    it 'should remove Package[php]' do should contain_package('php').with_ensure('absent') end 
    it 'should remove php configuration file' do should contain_file('php.conf').with_ensure('absent') end
  end

  describe 'Test customizations - template' do
    let(:params) { {:template => "php/spec.erb" , :options => { 'opt_a' => 'value_a' } } }

    it 'should generate a valid template' do
      content = catalogue.resource('file', 'php.conf').send(:parameters)[:content]
      content.should match "fqdn: rspec.example42.com"
    end
    it 'should generate a template that uses custom options' do
      content = catalogue.resource('file', 'php.conf').send(:parameters)[:content]
      content.should match "value_a"
    end

  end

  describe 'Test customizations - source' do
    let(:params) { {:source => "puppet://modules/php/spec" , :source_dir => "puppet://modules/php/dir/spec" , :source_dir_purge => true } }

    it 'should request a valid source ' do
      content = catalogue.resource('file', 'php.conf').send(:parameters)[:source]
      content.should == "puppet://modules/php/spec"
    end
    it 'should request a valid source dir' do
      content = catalogue.resource('file', 'php.dir').send(:parameters)[:source]
      content.should == "puppet://modules/php/dir/spec"
    end
    it 'should purge source dir if source_dir_purge is true' do
      content = catalogue.resource('file', 'php.dir').send(:parameters)[:purge]
      content.should == true
    end
  end

  describe 'Test customizations - custom class' do
    let(:params) { {:my_class => "php::spec" } }
    it 'should automatically include a custom class' do
      content = catalogue.resource('file', 'php.conf').send(:parameters)[:content]
      content.should match "fqdn: rspec.example42.com"
    end
  end

  describe 'Test Puppi Integration' do
    let(:params) { {:puppi => true, :puppi_helper => "myhelper"} }

    it 'should generate a puppi::ze define' do
      content = catalogue.resource('puppi::ze', 'php').send(:parameters)[:helper]
      content.should == "myhelper"
    end
  end


end

require "#{File.join(File.dirname(__FILE__),'..','spec_helper.rb')}"

describe 'php::module' do

  let(:title) { 'php::module' }
  let(:node) { 'rspec.example42.com' }
  let(:facts) { { 'operatingsystem' => 'Ubuntu' } }

  describe 'Test standard installation' do
    let(:params) { { 'name' =>  'ps', } }
    it 'should create a package with the default OS prefix' do
      should contain_package('PhpModule_ps').with_name('php5-ps')
    end
    it 'should notify the default service' do
      should contain_package('PhpModule_ps').with_notify('Service[apache2]')
    end
  end

  describe 'Test custom params' do
    let(:params) { { 'name' =>  'ps', 'module_prefix' => 'my-' , 'service_autorestart' => false } }
    it 'should create a package with custom prefix' do
      should contain_package('PhpModule_ps').with(
        'ensure' => 'present',
        'name'   => 'my-ps'
      )
      should contain_package('PhpModule_ps').without('notify')
    end
  end

  describe 'Test uninstallation' do
    let(:params) { { 'name' =>  'ps', 'absent' => 'true' } }
    it 'should remove the package' do
      should contain_package('PhpModule_ps').with_ensure('absent')
    end
  end

end

require "#{File.join(File.dirname(__FILE__),'..','spec_helper.rb')}"

describe 'php::pear::module' do

  let(:title) { 'php::pear::module' }
  let(:node) { 'rspec.example42.com' }
  let(:facts) { { 'operatingsystem' => 'Ubuntu' } }

  describe 'Test standard installation' do
    let(:params) { { 'name' =>  'Crypt-CHAP', } }
    it 'should install pear module with default OS package' do
      should contain_package('pear-Crypt-CHAP').with_name('php-Crypt-CHAP')
    end
    it 'should notify the default service' do
      should contain_package('pear-Crypt-CHAP').with_notify('Service[apache2]')
    end
  end

  describe 'Test custom params' do
    let(:params) { { 'name' =>  'Crypt-CHAP', 'module_prefix' => 'my-' , 'service_autorestart' => false } }
    it 'should create a package with custom prefix' do
      should contain_package('pear-Crypt-CHAP').with(
        'ensure' => 'present',
        'name'   => 'my-Crypt-CHAP'
      )
      should contain_package('pear-Crypt-CHAP').without('notify')
    end
  end

  describe 'Test uninstallation' do
    let(:params) { { 'name' =>  'Crypt-CHAP', 'ensure' => 'absent' } }
    it 'should remove the package' do
      should contain_package('pear-Crypt-CHAP').with_ensure('absent')
    end
  end

  describe 'Test installation via exec' do
    let(:params) { { 'name' =>  'Crypt-CHAP', 'use_package' => 'false' } }
    it 'should install pear module with exec commands' do
      should contain_exec('pear-Crypt-CHAP').with(
        'command' => 'pear -d preferred_state=stable install  pear.php.net/Crypt-CHAP',
        'unless'  => 'pear info pear.php.net/Crypt-CHAP'
      )
    end
  end


end

require 'puppetlabs_spec_helper/module_spec_helper'
; File Managed by Puppet

<% if @value != "" -%>
<% if @value.is_a? Array -%>
<% @value.each do |name| -%>
<%= name %>
<% end %>
<% else -%>
<%= value %>
<% end -%>
<% end -%>
# This is a template used only for rspec tests

# Yaml of the whole scope
<%= scope.to_hash.reject { |k,v| !( k.is_a?(String) && v.is_a?(String) ) }.to_yaml %>

# Custom Options
<%= options['opt_a'] %>
<%= options['opt_b'] %>
fixtures:
  repositories:
    apt: "https://github.com/puppetlabs/puppetlabs-apt.git"
    stdlib: "https://github.com/puppetlabs/puppetlabs-stdlib.git"
    firewall: "https://github.com/puppetlabs/puppetlabs-firewall.git"
    concat: "https://github.com/puppetlabs/puppetlabs-concat.git"
  symlinks:
    postgresql: "#{source_dir}"
default_set: 'centos-64-x64'
sets:
  'centos-59-x64':
    nodes:
      "main.foo.vm":
        prefab: 'centos-59-x64'
  'centos-64-x64':
    nodes:
      "main.foo.vm":
        prefab: 'centos-64-x64'
  'fedora-18-x64':
    nodes:
      "main.foo.vm":
        prefab: 'fedora-18-x64'
  'debian-607-x64':
    nodes:
      "main.foo.vm":
        prefab: 'debian-607-x64'
  'debian-70rc1-x64':
    nodes:
      "main.foo.vm":
        prefab: 'debian-70rc1-x64'
  'ubuntu-server-10044-x64':
    nodes:
      "main.foo.vm":
        prefab: 'ubuntu-server-10044-x64'
  'ubuntu-server-12042-x64':
    nodes:
      "main.foo.vm":
        prefab: 'ubuntu-server-12042-x64'
language: ruby
bundler_args: --without development
script: bundle exec rake spec SPEC_OPTS='--format documentation'
after_success:
  - git clone -q git://github.com/puppetlabs/ghpublisher.git .forge-release
  - .forge-release/publish
rvm:
- 1.8.7
- 1.9.3
- 2.0.0
env:
  matrix:
  - PUPPET_GEM_VERSION="~> 2.7.0"
  - PUPPET_GEM_VERSION="~> 3.2.0"
  - PUPPET_GEM_VERSION="~> 3.4.0"
  global:
    - PUBLISHER_LOGIN=puppetlabs
    - secure: jY81Y/csdcDjjXRzX9VA3fbb5db+/KraLRPErHjYANO15DZjh3b9tBwo/ybLCLCGJE8ej1yXzTxs1dJhokySQL12m1VW1i8dM26kMc4x+wOnIFKny7VB78Tcbp8RV1iV1kWN3UcuAbQ5hvMrI3rzoWkD22zF0k3nFEcv1kpix1w=
matrix:
  fast_finish: true
  exclude:
  - rvm: 1.9.3
    env: PUPPET_GEM_VERSION="~> 2.7.0"
  - rvm: 2.0.0
    env: PUPPET_GEM_VERSION="~> 2.7.0"
notifications:
  email: false
##2014-03-04 - Supported Release 3.3.3
###Summary

This is a supported release.  This release removes a testing symlink that can
cause trouble on systems where /var is on a seperate filesystem from the
modulepath.

####Features
####Bugfixes
####Known Bugs
* SLES is not supported.

##2014-03-04 - Supported Release 3.3.2
###Summary
This is a supported release. It fixes a problem with updating passwords on postgresql.org distributed versions of PostgreSQL.

####Bugfixes
- Correct psql path when setting password on custom versions.
- Documentation updates
- Test updates

####Known Bugs
* SLES is not supported.


##2014-02-12 - Version 3.3.1
####Bugfix:
- Allow dynamic rubygems host


##2014-01-28 - Version 3.3.0

###Summary

This release rolls up a bunch of bugfixes our users have found and fixed for
us over the last few months.  This improves things for 9.1 users, and makes
this module usable on FreeBSD.

This release is dedicated to 'bma', who's suffering with Puppet 3.4.1 issues
thanks to Puppet::Util::SUIDManager.run_and_capture.

####Features
 - Add lc_ config entry settings
 - Can pass template at database creation.
 - Add FreeBSD support.
 - Add support for customer `xlogdir` parameter.
 - Switch tests from rspec-system to beaker.  (This isn't really a feature)

####Bugfixes
 - Properly fix the deprecated Puppet::Util::SUIDManager.run_and_capture errors.
 - Fix NOREPLICATION option for Postgres 9.1
 - Wrong parameter name: manage_pg_conf -> manage_pg_hba_conf
 - Add $postgresql::server::client_package_name, referred to by install.pp
 - Add missing service_provider/service_name descriptions in ::globals.
 - Fix several smaller typos/issues throughout.
 - Exec['postgresql_initdb'] needs to be done after $datadir exists
 - Prevent defined resources from floating in the catalog.
 - Fix granting all privileges on a table.
 - Add some missing privileges.
 - Remove deprecated and unused concat::fragment parameters.


##2013-11-05 - Version 3.2.0

###Summary

Add's support for Ubuntu 13.10 (and 14.04) as well as x, y, z.

####Features
- Add versions for Ubuntu 13.10 and 14.04.
- Use default_database in validate_db_connection instead of a hardcoded
'postgres'
- Add globals/params layering for default_database.
- Allow specification of default database name.

####Bugs
- Fixes to the README.


##2013-10-25 - Version 3.1.0

###Summary

This is a minor feature and bug fix release.

Firstly, the postgresql_psql type now includes a new parameter `search_path` which is equivalent to using `set search_path` which allows you to change the default schema search path.

The default version of Fedora 17 has now been added, so that Fedora 17 users can enjoy the module.

And finally we've extended the capabilities of the defined type postgresql::validate_db_connection so that now it can handle retrying and sleeping between retries. This feature has been monopolized to fix a bug we were seeing with startup race conditions, but it can also be used by remote systems to 'wait' for PostgreSQL to start before their Puppet run continues.

####Features
- Defined $default_version for Fedora 17 (Bret Comnes)
- add search_path attribute to postgresql_psql resource (Jeremy Kitchen)
- (GH-198) Add wait and retry capability to validate_db_connection (Ken Barber)

####Bugs
- enabling defined postgres user password without resetting on every puppet run (jonoterc)
- periods are valid in configuration variables also (Jeremy Kitchen)
- Add zero length string to join() function (Jarl Stefansson)
- add require of install to reload class (cdenneen)
- (GH-198) Fix race condition on postgresql startup (Ken Barber)
- Remove concat::setup for include in preparation for the next concat release (Ken Barber)


##2013-10-14 - Version 3.0.0

Final release of 3.0, enjoy!


##2013-10-14 - Version 3.0.0-rc3

###Summary

Add a parameter to unmanage pg_hba.conf to fix a regression from 2.5, as well
as allowing owner to be passed into x.

####Features
- `manage_pg_hba_conf` parameter added to control pg_hba.conf management.
- `owner` parameter added to server::db.


##2013-10-09 - Version 3.0.0-rc2

###Summary

A few bugfixes have been found since -rc1.

####Fixes
- Special case for $datadir on Amazon
- Fix documentation about username/password for the postgresql_hash function


##2013-10-01 - Version 3.0.0-rc1

###Summary

Version 3 was a major rewrite to fix some internal dependency issues, and to
make the new Public API more clear. As a consequence a lot of things have
changed for version 3 and older revisions that we will try to outline here.

(NOTE:  The format of this CHANGELOG differs to normal in an attempt to
explain the scope of changes)

* Server specific objects now moved under `postgresql::server::` namespace:

To restructure server specific elements under the `postgresql::server::`
namespaces the following objects were renamed as such:

`postgresql::database`       -> `postgresql::server::database`
`postgresql::database_grant` -> `postgresql::server::database_grant`
`postgresql::db`             -> `postgresql::server::db`
`postgresql::grant`          -> `postgresql::server::grant`
`postgresql::pg_hba_rule`    -> `postgresql::server::pg_hba_rule`
`postgresql::plperl`         -> `postgresql::server::plperl`
`postgresql::contrib`        -> `postgresql::server::contrib`
`postgresql::role`           -> `postgresql::server::role`
`postgresql::table_grant`    -> `postgresql::server::table_grant`
`postgresql::tablespace`     -> `postgresql::server::tablespace`

* New `postgresql::server::config_entry` resource for managing configuration:

Previously we used the `file_line` resource to modify `postgresql.conf`. This
new revision now adds a new resource named `postgresql::server::config_entry`
for managing this file. For example:

```puppet
    postgresql::server::config_entry { 'check_function_bodies':
      value => 'off',
    }
```

If you were using `file_line` for this purpose, you should change to this new
methodology.

* `postgresql_puppet_extras.conf` has been removed:

Now that we have a methodology for managing `postgresql.conf`, and due to
concerns over the file management methodology using an `exec { 'touch ...': }`
as a way to create an empty file the existing postgresql\_puppet\_extras.conf
file is no longer managed by this module.

If you wish to recreate this methodology yourself, use this pattern:

```puppet
    class { 'postgresql::server': }

    $extras = "/tmp/include.conf"

    file { $extras:
      content => 'max_connections = 123',
      notify  => Class['postgresql::server::service'],
    }->
    postgresql::server::config_entry { 'include':
      value   => $extras,
    }
```

* All uses of the parameter `charset` changed to `encoding`:

Since PostgreSQL uses the terminology `encoding` not `charset` the parameter
has been made consisent across all classes and resources.

* The `postgresql` base class is no longer how you set globals:

The old global override pattern was less then optimal so it has been fixed,
however we decided to demark this properly by specifying these overrides in
the class `postgresql::global`. Consult the documentation for this class now
to see what options are available.

Also, some parameter elements have been moved between this and the
`postgresql::server` class where it made sense.

* `config_hash` parameter collapsed for the `postgresql::server` class:

Because the `config_hash` was really passing data through to what was in
effect an internal class (`postgresql::config`). And since we don't want this
kind of internal exposure the parameters were collapsed up into the
`postgresql::server` class directly.

* Lots of changes to 'private' or 'undocumented' classes:

If you were using these before, these have changed names. You should only use
what is documented in this README.md, and if you don't have what you need you
should raise a patch to add that feature to a public API. All internal classes
now have a comment at the top indicating them as private to make sure the
message is clear that they are not supported as Public API.

* `pg_hba_conf_defaults` parameter included to turn off default pg\_hba rules:

The defaults should be good enough for most cases (if not raise a bug) but if
you simply need an escape hatch, this setting will turn off the defaults. If
you want to do this, it may affect the rest of the module so make sure you
replace the rules with something that continues operation.

* `postgresql::database_user` has now been removed:

Use `postgresql::server::role` instead.

* `postgresql::psql` resource has now been removed:

Use `postgresql_psql` instead. In the future we may recreate this as a wrapper
to add extra capability, but it will not match the old behaviour.

* `postgresql_default_version` fact has now been removed:

It didn't make sense to have this logic in a fact any more, the logic has been
moved into `postgresql::params`.

* `ripienaar/concat` is no longer used, instead we use `puppetlabs/concat`:

The older concat module is now deprecated and moved into the
`puppetlabs/concat` namespace. Functionality is more or less identical, but
you may need to intervene during the installing of this package - as both use
the same `concat` namespace.

##2013-09-09 Release 2.5.0

###Summary

The focus of this release is primarily to capture the fixes done to the
types and providers to make sure refreshonly works properly and to set
the stage for the large scale refactoring work of 3.0.0.

####Features


####Bugfixes 
- Use boolean for refreshonly.
- Fix postgresql::plperl documentation.
- Add two missing parameters to config::beforeservice
- Style fixes


##2013-08-01 Release 2.4.1

###Summary

This minor bugfix release solves an idempotency issue when using plain text
passwords for the password_hash parameter for the postgresql::role defined
type. Without this, users would continually see resource changes everytime
your run Puppet.

####Bugfixes
- Alter role call not idempotent with cleartext passwords (Ken Barber)


##2013-07-19 Release 2.4.0

###Summary

This updates adds the ability to change permissions on tables, create template
databases from normal databases, manage PL-Perl's postgres package, and
disable the management of `pg_hba.conf`.

####Features
- Add `postgresql::table_grant` defined resource
- Add `postgresql::plperl` class
- Add `manage_pg_hba_conf` parameter to the `postgresql::config` class
- Add `istemplate` parameter to the `postgresql::database` define

####Bugfixes
- Update `postgresql::role` class to be able to update roles when modified
instead of only on creation.
- Update tests
- Fix documentation of `postgresql::database_grant`


##2.3.0

This feature release includes the following changes:

* Add a new parameter `owner` to the `database` type.  This can be used to
  grant ownership of a new database to a specific user.  (Bruno Harbulot)
* Add support for operating systems other than Debian/RedHat, as long as the
  user supplies custom values for all of the required paths, package names, etc.
  (Chris Price)
* Improved integration testing (Ken Barber)


##2.2.1

This release fixes a bug whereby one of our shell commands (psql) were not ran from a globally accessible directory. This was causing permission denied errors when the command attempted to change user without changing directory.

Users of previous versions might have seen this error:

    Error: Error executing SQL; psql returned 256: 'could not change directory to "/root"

This patch should correct that.

#### Detail Changes

* Set /tmp as default CWD for postgresql_psql


##2.2.0

This feature release introduces a number of new features and bug fixes.

First of all it includes a new class named `postgresql::python` which provides you with a convenient way of install the python Postgresql client libraries.

    class { 'postgresql::python':
    }

You are now able to use `postgresql::database_user` without having to specify a password_hash, useful for different authentication mechanisms that do not need passwords (ie. cert, local etc.).

We've also provided a lot more advanced custom parameters now for greater control of your Postgresql installation. Consult the class documentation for PuppetDB in the README.

This release in particular has largely been contributed by the community members below, a big thanks to one and all.

#### Detailed Changes

* Add support for psycopg installation (Flaper Fesp and Dan Prince)
* Added default PostgreSQL version for Ubuntu 13.04 (Kamil Szymanski)
* Add ability to create users without a password (Bruno Harbulot)
* Three Puppet 2.6 fixes (Dominic Cleal)
* Add explicit call to concat::setup when creating concat file (Dominic Cleal)
* Fix readme typo (Jordi Boggiano)
* Update postgres_default_version for Ubuntu (Kamil Szymanski)
* Allow to set connection for noew role (Kamil Szymanski)
* Fix pg_hba_rule for postgres local access (Kamil Szymanski)
* Fix versions for travis-ci (Ken Barber)
* Add replication support (Jordi Boggiano)
* Cleaned up and added unit tests (Ken Barber)
* Generalization to provide more flexability in postgresql configuration (Karel Brezina)
* Create dependent directory for sudoers so tests work on Centos 5 (Ken Barber)
* Allow SQL commands to be run against a specific DB (Carlos Villela)
* Drop trailing comma to support Puppet 2.6 (Michael Arnold)


##2.1.1


This release provides a bug fix for RHEL 5 and Centos 5 systems, or specifically systems using PostgreSQL 8.1 or older. On those systems one would have received the error:

    Error: Could not start Service[postgresqld]: Execution of ‘/sbin/service postgresql start’ returned 1:

And the postgresql log entry:

    FATAL: unrecognized configuration parameter "include"

This bug is due to a new feature we had added in 2.1.0, whereby the `include` directive in `postgresql.conf` was not compatible. As a work-around we have added checks in our code to make sure systems running PostgreSQL 8.1 or older do not have this directive added.

#### Detailed Changes

2013-01-21 - Ken Barber <ken@bob.sh>
* Only install `include` directive and included file on PostgreSQL >= 8.2
* Add system tests for Centos 5


##2.1.0

This release is primarily a feature release, introducing some new helpful constructs to the module.

For starters, we've added the line `include 'postgresql_conf_extras.conf'` by default so extra parameters not managed by the module can be added by other tooling or by Puppet itself. This provides a useful escape-hatch for managing settings that are not currently managed by the module today.

We've added a new defined resource for managing your tablespace, so you can now create new tablespaces using the syntax:

    postgresql::tablespace { 'dbspace':
      location => '/srv/dbspace',
    }

We've added a locale parameter to the `postgresql` class, to provide a default. Also the parameter has been added to the `postgresql::database` and `postgresql::db` defined resources for changing the locale per database:

    postgresql::db { 'mydatabase':
      user     => 'myuser',
      password => 'mypassword',
      encoding => 'UTF8',
      locale   => 'en_NG',
    }

There is a new class for installing the necessary packages to provide the PostgreSQL JDBC client jars:

    class { 'postgresql::java': }

And we have a brand new defined resource for managing fine-grained rule sets within your pg_hba.conf access lists:

    postgresql::pg_hba { 'Open up postgresql for access from 200.1.2.0/24':
      type => 'host',
      database => 'app',
      user => 'app',
      address => '200.1.2.0/24',
      auth_method => 'md5',
    }

Finally, we've also added Travis-CI support and unit tests to help us iterate faster with tests to reduce regression. The current URL for these tests is here: https://travis-ci.org/puppetlabs/puppet-postgresql. Instructions on how to run the unit tests available are provided in the README for the module.

A big thanks to all those listed below who made this feature release possible :-).

#### Detailed Changes

2013-01-18 - Simão Fontes <simaofontes@gmail.com> & Flaper Fesp <flaper87@gmail.com>
* Remove trailing commas from params.pp property definition for Puppet 2.6.0 compatibility

2013-01-18 - Lauren Rother <lauren.rother@puppetlabs.com>
* Updated README.md to conform with best practices template

2013-01-09 - Adrien Thebo <git@somethingsinistral.net>
* Update postgresql_default_version to 9.1 for Debian 7.0

2013-01-28 - Karel Brezina <karel.brezina@gmail.com>
* Add support for tablespaces

2013-01-16 - Chris Price <chris@puppetlabs.com> & Karel Brezina <karel.brezina@gmail.com>
* Provide support for an 'include' config file 'postgresql_conf_extras.conf' that users can modify manually or outside of the module.

2013-01-31 - jv <jeff@jeffvier.com>
* Fix typo in README.pp for postgresql::db example

2013-02-03 - Ken Barber <ken@bob.sh>
* Add unit tests and travis-ci support

2013-02-02 - Ken Barber <ken@bob.sh>
* Add locale parameter support to the 'postgresql' class

2013-01-21 - Michael Arnold <github@razorsedge.org>
* Add a class for install the packages containing the PostgreSQL JDBC jar

2013-02-06 - fhrbek <filip.hbrek@gmail.com>
* Coding style fixes to reduce warnings in puppet-lint and Geppetto

2013-02-10 - Ken Barber <ken@bob.sh>
* Provide new defined resource for managing pg_hba.conf

2013-02-11 - Ken Barber <ken@bob.sh>
* Fix bug with reload of Postgresql on Redhat/Centos

2013-02-15 - Erik Dalén <dalen@spotify.com>
* Fix more style issues to reduce warnings in puppet-lint and Geppetto

2013-02-15 - Erik Dalén <dalen@spotify.com>
* Fix case whereby we were modifying a hash after creation


##2.0.1

Minor bugfix release.

2013-01-16 - Chris Price <chris@puppetlabs.com>
 * Fix revoke command in database.pp to support postgres 8.1 (43ded42)

2013-01-15 - Jordi Boggiano <j.boggiano@seld.be>
 * Add support for ubuntu 12.10 status (3504405)

##2.0.0

Many thanks to the following people who contributed patches to this
release:

* Adrien Thebo
* Albert Koch
* Andreas Ntaflos
* Brett Porter
* Chris Price
* dharwood
* Etienne Pelletier
* Florin Broasca
* Henrik
* Hunter Haugen
* Jari Bakken
* Jordi Boggiano
* Ken Barber
* nzakaria
* Richard Arends
* Spenser Gilliland
* stormcrow
* William Van Hevelingen

Notable features:

   * Add support for versions of postgres other than the system default version
     (which varies depending on OS distro).  This includes optional support for
     automatically managing the package repo for the "official" postgres yum/apt
     repos.  (Major thanks to Etienne Pelletier <epelletier@maestrodev.com> and
     Ken Barber <ken@bob.sh> for their tireless efforts and patience on this
     feature set!)  For example usage see `tests/official-postgresql-repos.pp`.

   * Add some support for Debian Wheezy and Ubuntu Quantal

   * Add new `postgres_psql` type with a Ruby provider, to replace the old
     exec-based `psql` type.  This gives us much more flexibility around
     executing SQL statements and controlling their logging / reports output.

   * Major refactor of the "spec" tests--which are actually more like
     acceptance tests.  We now support testing against multiple OS distros
     via vagrant, and the framework is in place to allow us to very easily add
     more distros.  Currently testing against Cent6 and Ubuntu 10.04.

   * Fixed a bug that was preventing multiple databases from being owned by the
     same user
     (9adcd182f820101f5e4891b9f2ff6278dfad495c - Etienne Pelletier <epelletier@maestrodev.com>)

   * Add support for ACLs for finer-grained control of user/interface access
     (b8389d19ad78b4fb66024897097b4ed7db241930 - dharwood <harwoodd@cat.pdx.edu>)

   * Many other bug fixes and improvements!

##1.0.0

2012-09-17 - Version 0.3.0 released

2012-09-14 - Chris Price <chris@puppetlabs.com>
 * Add a type for validating a postgres connection (ce4a049)

2012-08-25 - Jari Bakken <jari.bakken@gmail.com>
 * Remove trailing commas. (e6af5e5)

2012-08-16 - Version 0.2.0 released
source ENV['GEM_SOURCE'] || "https://rubygems.org"

group :development, :test do
  gem 'rake'
  gem 'pry',                    :require => false
  gem 'puppetlabs_spec_helper', :require => false
  gem 'rspec-puppet', '< 1.0'
  gem 'puppet-lint', '~> 0.3.2'
  gem 'beaker',                 :require => false
  gem 'beaker-rspec',           :require => false
  gem 'serverspec',             :require => false
end

if puppetversion = ENV['PUPPET_GEM_VERSION']
  gem 'puppet', puppetversion, :require => false
else
  gem 'puppet', :require => false
end

# vim:ft=ruby

                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright 2013 Puppet Labs

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
name 'puppetlabs-postgresql'
version '3.3.3'
source 'git://github.com/puppetlabs/puppet-postgresql.git'
author 'Inkling/Puppet Labs'
description 'PostgreSQL defined resource types'
summary 'PostgreSQL defined resource types'
license 'ASL 2.0'
project_page 'https://github.com/puppetlabs/puppet-postgresql'

dependency 'puppetlabs/stdlib', '>=3.2.0 <5.0.0'
dependency 'puppetlabs/firewall', '>= 0.0.4'
dependency 'puppetlabs/apt', '>=1.1.0 <2.0.0'
dependency 'puppetlabs/concat', '>= 1.0.0 <2.0.0'
Puppetlabs postgresql module

Copyright 2012 Inkling Systems Inc
Copyright 2012-2013 Puppet Labs Inc
Copyright 2012-2013 Camptocamp SA.

This product includes software developed by:
  The Puppet Labs Inc (http://www.puppetlabs.com/).

This product includes also software developed by:
  Camptocamp SA (http://www.camptocamp.com/)

This product includes also software developed by:
  Inkling Systems Inc (https://www.inkling.com/)
postgresql
==========

Table of Contents

1. [Overview - What is the PostgreSQL module?](#overview)
2. [Module Description - What does the module do?](#module-description)
3. [Setup - The basics of getting started with PostgreSQL module](#setup)
    * [PE 3.2 supported module](#pe-3.2-supported-module)
    * [Configuring the server](#configuring-the-server) 
4. [Usage - How to use the module for various tasks](#usage)
5. [Upgrading - Guide for upgrading from older revisions of this module](#upgrading)
6. [Reference - The classes, defines,functions and facts available in this module](#reference)
7. [Limitations - OS compatibility, etc.](#limitations)
8. [Development - Guide for contributing to the module](#development)
9. [Disclaimer - Licensing information](#disclaimer)
10. [Transfer Notice - Notice of authorship change](#transfer-notice)
11. [Contributors - List of module contributors](#contributors)

Overview

The PostgreSQL module allows you to easily manage postgres databases with Puppet.

Module Description

PostgreSQL is a high-performance, free, open-source relational database server. The postgresql module allows you to manage PostgreSQL packages and services on several operating systems, while also supporting basic management of PostgreSQL databases and users. The module offers support for managing firewall for postgres ports on RedHat-based distros, as well as support for basic management of common security settings.

Setup

**What puppetlabs-PostgreSQL affects:**

* package/service/configuration files for PostgreSQL
* listened-to ports
* system firewall (optional)
* IP and mask (optional)

**Introductory Questions**

The postgresql module offers many security configuration settings. Before getting started, you will want to consider:

* Do you want/need to allow remote connections?
    * If yes, what about TCP connections?
* Would you prefer to work around your current firewall settings or overwrite some of them?
* How restrictive do you want the database superuser's permissions to be?

Your answers to these questions will determine which of the module's parameters you'll want to specify values for.

###PE 3.2 supported module

PE 3.2 introduces Puppet Labs supported modules. The version of the postgresql module that ships within PE 3.2 is supported via normal [Puppet Enterprise support](http://puppetlabs.com/services/customer-support) channels. If you would like to access the [supported module](http://forge.puppetlabs.com/supported) version, you will need to uninstall the shipped module and install the supported version from the Puppet Forge. You can do this by first running

    # puppet module uninstall puppetlabs-postgresql
and then running

    # puppet module install puppetlabs/postgresql

###Configuring the server

The main configuration you'll need to do will be around the `postgresql::server` class. The default parameters are reasonable, but fairly restrictive regarding permissions for who can connect and from where. To manage a PostgreSQL server with sane defaults:

    class { 'postgresql::server': }

For a more customized configuration:

    class { 'postgresql::server':
      ip_mask_deny_postgres_user => '0.0.0.0/32',
      ip_mask_allow_all_users    => '0.0.0.0/0',
      listen_addresses           => '*',
      ipv4acls                   => ['hostssl all johndoe 192.168.0.0/24 cert'],
      manage_firewall            => true,
      postgres_password          => 'TPSrep0rt!',
    }

Once you've completed your configuration of `postgresql::server`, you can test out your settings from the command line:

    $ psql -h localhost -U postgres
    $ psql -h my.postgres.server -U

If you get an error message from these commands, it means that your permissions are set in a way that restricts access from where you're trying to connect. That might be a good thing or a bad thing, depending on your goals.

For more details about server configuration parameters consult the [PostgreSQL Runtime Configuration docs](http://www.postgresql.org/docs/9.2/static/runtime-config.html).

Usage

###Creating a database

There are many ways to set up a postgres database using the `postgresql::server::db` class. For instance, to set up a database for PuppetDB:

    class { 'postgresql::server': }

    postgresql::server::db { 'mydatabasename':
      user     => 'mydatabaseuser',
      password => postgresql_password('mydatabaseuser', 'mypassword'),
    }

###Managing users, roles and permissions

To manage users, roles and permissions:

    class { 'postgresql::server': }

    postgresql::server::role { 'marmot':
      password_hash => postgresql_password('marmot', 'mypasswd'),
    }

    postgresql::server::database_grant { 'test1':
      privilege => 'ALL',
      db        => 'test1',
      role      => 'marmot',
    }

    postgresql::server::table_grant { 'my_table of test2':
      privilege => 'ALL',
      table     => 'my_table',
      db        => 'test2',
      role      => 'marmot',
    }

In this example, you would grant ALL privileges on the test1 database and on the `my_table` table of the test2 database to the user or group specified by dan.

At this point, you would just need to plunk these database name/username/password values into your PuppetDB config files, and you are good to go.

Upgrading

###Upgrading from 2.x to version 3

*Note:* if you are upgrading for 2.x, you *must* read this, as just about everything has changed.

Version 3 was a major rewrite to fix some internal dependency issues, and to make the new Public API more clear. As a consequence a lot of things have changed for version 3 and older revisions that we will try to outline here.

####Server specific objects now moved under `postgresql::server::` namespace

To restructure server specific elements under the `postgresql::server::` namespaces the following objects were renamed as such:

* `postgresql::database`       -> `postgresql::server::database`
* `postgresql::database_grant` -> `postgresql::server::database_grant`
* `postgresql::db`             -> `postgresql::server::db`
* `postgresql::grant`          -> `postgresql::server::grant`
* `postgresql::pg_hba_rule`    -> `postgresql::server::pg_hba_rule`
* `postgresql::plperl`         -> `postgresql::server::plperl`
* `postgresql::contrib`        -> `postgresql::server::contrib`
* `postgresql::role`           -> `postgresql::server::role`
* `postgresql::table_grant`    -> `postgresql::server::table_grant`
* `postgresql::tablespace`     -> `postgresql::server::tablespace`

####New `postgresql::server::config_entry` resource for managing configuration

Previously we used the `file_line` resource to modify `postgresql.conf`. This new revision now adds a new resource named `postgresql::server::config_entry` for managing this file. For example:

    postgresql::server::config_entry { 'check_function_bodies':
      value => 'off',
    }

If you were using `file_line` for this purpose, you should change to this new methodology.

####`postgresql_puppet_extras.conf` has been removed

Now that we have a methodology for managing `postgresql.conf`, and due to concerns over the file management methodology using an `exec { 'touch ...': }` as a way to create an empty file the existing postgresql\_puppet\_extras.conf file is no longer managed by this module.

If you wish to recreate this methodology yourself, use this pattern:

    class { 'postgresql::server': }

    $extras = "/tmp/include.conf"

    file { $extras:
      content => 'max_connections = 123',
      notify  => Class['postgresql::server::service'],
    }->
    postgresql::server::config_entry { 'include':
      value   => $extras,
    }

####All uses of the parameter `charset` changed to `encoding`

Since PostgreSQL uses the terminology `encoding` not `charset` the parameter has been made consisent across all classes and resources.

####The `postgresql` base class is no longer how you set globals

The old global override pattern was less then optimal so it has been fixed, however we decided to demark this properly by specifying these overrides in the class `postgresql::globals`. Consult the documentation for this class now to see what options are available.

Also, some parameter elements have been moved between this and the `postgresql::server` class where it made sense.

####`config_hash` parameter collapsed for the `postgresql::server` class

Because the `config_hash` was really passing data through to what was in effect an internal class (`postgresql::config`). And since we don't want this kind of internal exposure the parameters were collapsed up into the `postgresql::server` class directly.

####Lots of changes to 'private' or 'undocumented' classes

If you were using these before, these have changed names. You should only use what is documented in this README.md, and if you don't have what you need you should raise a patch to add that feature to a public API. All internal classes now have a comment at the top indicating them as private to make sure the message is clear that they are not supported as Public API.

####`pg_hba_conf_defaults` parameter included to turn off default pg\_hba rules

The defaults should be good enough for most cases (if not raise a bug) but if you simply need an escape hatch, this setting will turn off the defaults. If you want to do this, it may affect the rest of the module so make sure you replace the rules with something that continues operation.

####`postgresql::database_user` has now been removed

Use `postgresql::server::role` instead.

####`postgresql::psql` resource has now been removed

Use `postgresql_psql` instead. In the future we may recreate this as a wrapper to add extra capability, but it will not match the old behaviour.

####`postgresql_default_version` fact has now been removed

It didn't make sense to have this logic in a fact any more, the logic has been moved into `postgresql::params`.

####`ripienaar/concat` is no longer used, instead we use `puppetlabs/concat`

The older concat module is now deprecated and moved into the `puppetlabs/concat` namespace. Functionality is more or less identical, but you may need to intervene during the installing of this package - as both use the same `concat` namespace.

Reference

The postgresql module comes with many options for configuring the server. While you are unlikely to use all of the below settings, they allow you a decent amount of control over your security settings.

Classes:

* [postgresql::client](#class-postgresqlclient)
* [postgresql::globals](#class-postgresqlglobals)
* [postgresql::lib::devel](#class-postgresqllibdevel)
* [postgresql::lib::java](#class-postgresqllibjava)
* [postgresql::lib::python](#class-postgresqllibpython)
* [postgresql::server](#class-postgresqlserver)
* [postgresql::server::plperl](#class-postgresqlserverplperl)
* [postgresql::server::contrib](#class-postgresqlservercontrib)

Resources:

* [postgresql::server::config_entry](#resource-postgresqlserverconfigentry)
* [postgresql::server::db](#resource-postgresqlserverdb)
* [postgresql::server::database](#resource-postgresqlserverdatabase)
* [postgresql::server::database_grant](#resource-postgresqlserverdatabasegrant)
* [postgresql::server::pg_hba_rule](#resource-postgresqlserverpghbarule)
* [postgresql::server::role](#resource-postgresqlserverrole)
* [postgresql::server::table_grant](#resource-postgresqlservertablegrant)
* [postgresql::server::tablespace](#resource-postgresqlservertablespace)
* [postgresql::validate_db_connection](#resource-postgresqlvalidatedbconnection)

Functions:

* [postgresql\_password](#function-postgresqlpassword)
* [postgresql\_acls\_to\_resources\_hash](#function-postgresqlaclstoresourceshashaclarray-id-orderoffset)


###Class: postgresql::globals
*Note:* most server specific defaults should be overriden in the `postgresql::server` class. This class should only be used if you are using a non-standard OS or if you are changing elements such as `version` or `manage_package_repo` that can only be changed here.

This class allows you to configure the main settings for this module in a global way, to be used by the other classes and defined resources. On its own it does nothing.

For example, if you wanted to overwrite the default `locale` and `encoding` for all classes you could use the following combination:

    class { 'postgresql::globals':
      encoding => 'UTF8',
      locale   => 'en_NG',
    }->
    class { 'postgresql::server':
    }

That would make the `encoding` and `locale` the default for all classes and defined resources in this module.

If you want to use the upstream PostgreSQL packaging, and be specific about the version you wish to download, you could use something like this:

    class { 'postgresql::globals':
      manage_package_repo => true,
      version             => '9.2',
    }->
    class { 'postgresql::server': }

####`client_package_name`
This setting can be used to override the default postgresql client package name. If not specified, the module will use whatever package name is the default for your OS distro.

####`server_package_name`
This setting can be used to override the default postgresql server package name. If not specified, the module will use whatever package name is the default for your OS distro.

####`contrib_package_name`
This setting can be used to override the default postgresql contrib package name. If not specified, the module will use whatever package name is the default for your OS distro.

####`devel_package_name`
This setting can be used to override the default postgresql devel package name. If not specified, the module will use whatever package name is the default for your OS distro.

####`java_package_name`
This setting can be used to override the default postgresql java package name. If not specified, the module will use whatever package name is the default for your OS distro.

####`plperl_package_name`
This setting can be used to override the default postgresql PL/perl package name. If not specified, the module will use whatever package name is the default for your OS distro.

####`python_package_name`
This setting can be used to override the default postgresql Python package name. If not specified, the module will use whatever package name is the default for your OS distro.

####`service_name`
This setting can be used to override the default postgresql service name. If not specified, the module will use whatever service name is the default for your OS distro.

####`service_provider`
This setting can be used to override the default postgresql service provider. If not specified, the module will use whatever service provider is the default for your OS distro.

####`service_status`
This setting can be used to override the default status check command for your PostgreSQL service. If not specified, the module will use whatever service status is the default for your OS distro.

####`default_database`
This setting is used to specify the name of the default database to connect with. On most systems this will be "postgres".

####`initdb_path`
Path to the `initdb` command.

####`createdb_path`
Path to the `createdb` command.

####`psql_path`
Path to the `psql` command.

####`pg_hba_conf_path`
Path to your `pg\_hba.conf` file.

####`postgresql_conf_path`
Path to your `postgresql.conf` file.

####`pg_hba_conf_defaults`
If false, disables the defaults supplied with the module for `pg\_hba.conf`. This is useful if you disagree with the defaults and wish to override them yourself. Be sure that your changes of course align with the rest of the module, as some access is required to perform basic `psql` operations for example.

####`datadir`
This setting can be used to override the default postgresql data directory for the target platform. If not specified, the module will use whatever directory is the default for your OS distro.

####`confdir`
This setting can be used to override the default postgresql configuration directory for the target platform. If not specified, the module will use whatever directory is the default for your OS distro.

####`bindir`
This setting can be used to override the default postgresql binaries directory for the target platform. If not specified, the module will use whatever directory is the default for your OS distro.

####`xlogdir`
This setting can be used to override the default postgresql xlog directory. If not specified the module will use initdb's default path.

####`user`
This setting can be used to override the default postgresql super user and owner of postgresql related files in the file system. If not specified, the module will use the user name 'postgres'.

####`group`
This setting can be used to override the default postgresql user group to be used for related files in the file system. If not specified, the module will use the group name 'postgres'.

####`version`
The version of PostgreSQL to install/manage. This is a simple way of providing a specific version such as '9.2' or '8.4' for example.

Defaults to your operating system default.

####`needs_initdb`
This setting can be used to explicitly call the initdb operation after server package is installed and before the postgresql service is started. If not specified, the module will decide whether to call initdb or not depending on your OS distro.

####`encoding`
This will set the default encoding encoding for all databases created with this module. On certain operating systems this will be used during the `template1` initialization as well so it becomes a default outside of the module as well. Defaults to the operating system default.

####`locale`
This will set the default database locale for all databases created with this module. On certain operating systems this will be used during the `template1` initialization as well so it becomes a default outside of the module as well. Defaults to `undef` which is effectively `C`.

#####Debian

On Debian you'll need to ensure that the 'locales-all' package is installed for full functionality of Postgres.

####`firewall_supported`
This allows you to override the automated detection to see if your OS supports the `firewall` module.

####`manage_package_repo`
If `true` this will setup the official PostgreSQL repositories on your host. Defaults to `false`.

###Class: postgresql::server
The following list are options that you can set in the `config_hash` parameter of `postgresql::server`.

####`ensure`
This value default to `present`. When set to `absent` it will remove all packages, configuration and data so use this with extreme caution.

####`version`
This will set the version of the PostgreSQL software to install. Defaults to your operating systems default.

####`postgres_password`
This value defaults to `undef`, meaning the super user account in the postgres database is a user called `postgres` and this account does not have a password. If you provide this setting, the module will set the password for the `postgres` user to your specified value.

####`package_name`
The name of the package to use for installing the server software. Defaults to the default for your OS distro.

####`package_ensure`
Value to pass through to the `package` resource when creating the server instance. Defaults to `undef`.

####`plperl_package_name`
This sets the default package name for the PL/Perl extension. Defaults to utilising the operating system default.

####`service_name`
This setting can be used to override the default postgresql service name. If not specified, the module will use whatever service name is the default for your OS distro.

####`service_name`
This setting can be used to override the default postgresql service provider. If not specified, the module will use whatever service name is the default for your OS distro.

####`service_status`
This setting can be used to override the default status check command for your PostgreSQL service. If not specified, the module will use whatever service name is the default for your OS distro.

####`default_database`
This setting is used to specify the name of the default database to connect with. On most systems this will be "postgres".

####`listen_addresses`
This value defaults to `localhost`, meaning the postgres server will only accept connections from localhost. If you'd like to be able to connect to postgres from remote machines, you can override this setting. A value of `*` will tell postgres to accept connections from any remote machine. Alternately, you can specify a comma-separated list of hostnames or IP addresses. (For more info, have a look at the `postgresql.conf` file from your system's postgres package).

####`ip_mask_deny_postgres_user`
This value defaults to `0.0.0.0/0`. Sometimes it can be useful to block the superuser account from remote connections if you are allowing other database users to connect remotely. Set this to an IP and mask for which you want to deny connections by the postgres superuser account. So, e.g., the default value of `0.0.0.0/0` will match any remote IP and deny access, so the postgres user won't be able to connect remotely at all. Conversely, a value of `0.0.0.0/32` would not match any remote IP, and thus the deny rule will not be applied and the postgres user will be allowed to connect.

####`ip_mask_allow_all_users`
This value defaults to `127.0.0.1/32`. By default, Postgres does not allow any database user accounts to connect via TCP from remote machines. If you'd like to allow them to, you can override this setting. You might set it to `0.0.0.0/0` to allow database users to connect from any remote machine, or `192.168.0.0/16` to allow connections from any machine on your local 192.168 subnet.

####`ipv4acls`
List of strings for access control for connection method, users, databases, IPv4 addresses; see [postgresql documentation](http://www.postgresql.org/docs/9.2/static/auth-pg-hba-conf.html) about `pg_hba.conf` for information (please note that the link will take you to documentation for the most recent version of Postgres, however links for earlier versions can be found on that page).

####`ipv6acls`
List of strings for access control for connection method, users, databases, IPv6 addresses; see [postgresql documentation](http://www.postgresql.org/docs/9.2/static/auth-pg-hba-conf.html) about `pg_hba.conf` for information (please note that the link will take you to documentation for the most recent version of Postgres, however links for earlier versions can be found on that page).

####`initdb_path`
Path to the `initdb` command.

####`createdb_path`
Path to the `createdb` command.

####`psql_path`
Path to the `psql` command.

####`pg_hba_conf_path`
Path to your `pg\_hba.conf` file.

####`postgresql_conf_path`
Path to your `postgresql.conf` file.

####`pg_hba_conf_defaults`
If false, disables the defaults supplied with the module for `pg\_hba.conf`. This is useful if you di
sagree with the defaults and wish to override them yourself. Be sure that your changes of course alig
n with the rest of the module, as some access is required to perform basic `psql` operations for exam
ple.

####`user`
This setting can be used to override the default postgresql super user and owner of postgresql related files in the file system. If not specified, the module will use the user name 'postgres'.

####`group`
This setting can be used to override the default postgresql user group to be used for related files in the file system. If not specified, the module will use the group name 'postgres'.

####`needs_initdb`
This setting can be used to explicitly call the initdb operation after server package is installed and before the postgresql service is started. If not specified, the module will decide whether to call initdb or not depending on your OS distro.

####`encoding`
This will set the default encoding encoding for all databases created with this module. On certain operating systems this will be used during the `template1` initialization as well so it becomes a default outside of the module as well. Defaults to the operating system default.

####`locale`
This will set the default database locale for all databases created with this module. On certain operating systems this will be used during the `template1` initialization as well so it becomes a default outside of the module as well. Defaults to `undef` which is effectively `C`.

#####Debian

On Debian you'll need to ensure that the 'locales-all' package is installed for full functionality of Postgres.

####`manage_firewall`
This value defaults to `false`. Many distros ship with a fairly restrictive firewall configuration which will block the port that postgres tries to listen on. If you'd like for the puppet module to open this port for you (using the [puppetlabs-firewall](http://forge.puppetlabs.com/puppetlabs/firewall) module), change this value to true. Check the documentation for `puppetlabs/firewall` to ensure the rest of the global setup is applied, to ensure things like persistence and global rules are set correctly.

####`manage_pg_hba_conf`
This value defaults to `true`. Whether or not manage the pg_hba.conf. If set to `true`, puppet will overwrite this file. If set to `false`, puppet will not modify the file.


###Class: postgresql::client

This class installs postgresql client software. Alter the following parameters if you have a custom version you would like to install (Note: don't forget to make sure to add any necessary yum or apt repositories if specifying a custom version):

####`package_name`
The name of the postgresql client package.

####`package_ensure`
The ensure parameter passed on to postgresql client package resource.


###Class: postgresql::server::contrib
Installs the postgresql contrib package.

####`package_name`
The name of the postgresql contrib package.

####`package_ensure`
The ensure parameter passed on to postgresql contrib package resource.


###Class: postgresql::lib::devel
Installs the packages containing the development libraries for PostgreSQL.

####`package_ensure`
Override for the `ensure` parameter during package installation. Defaults to `present`.

####`package_name`
Overrides the default package name for the distribution you are installing to. Defaults to `postgresql-devel` or `postgresql<version>-devel` depending on your distro.


###Class: postgresql::lib::java
This class installs postgresql bindings for Java (JDBC). Alter the following parameters if you have a custom version you would like to install (Note: don't forget to make sure to add any necessary yum or apt repositories if specifying a custom version):

####`package_name`
The name of the postgresql java package.

####`package_ensure`
The ensure parameter passed on to postgresql java package resource.


###Class: postgresql::lib::python
This class installs the postgresql Python libraries. For customer requirements you can customise the following parameters:

####`package_name`
The name of the postgresql python package.

####`package_ensure`
The ensure parameter passed on to postgresql python package resource.


###Class: postgresql::server::plperl
This class installs the PL/Perl procedural language for postgresql.

####`package_name`
The name of the postgresql PL/Perl package.

####`package_ensure`
The ensure parameter passed on to postgresql PL/Perl package resource.


###Resource: postgresql::server::config\_entry
This resource can be used to modify your `postgresql.conf` configuration file.

Each resource maps to a line inside your `postgresql.conf` file, for example:

    postgresql::server::config_entry { 'check_function_bodies':
      value => 'off',
    }

####`namevar`
Name of the setting to change.

####`ensure`
Set to `absent` to remove an entry.

####`value`
Value for the setting.


###Resource: postgresql::server::db
This is a convenience resource that creates a database, user and assigns necessary permissions in one go.

For example, to create a database called `test1` with a corresponding user of the same name, you can use:

    postgresql::server::db { 'test1':
      user     => 'test1',
      password => 'test1',
    }

####`namevar`
The namevar for the resource designates the name of the database.

####`user`
User to create and assign access to the database upon creation. Mandatory.

####`password`
Password for the created user. Mandatory.

####`encoding`
Override the character set during creation of the database. Defaults to the default defined during installation.

####`locale`
Override the locale during creation of the database. Defaults to the default defined during installation.

####`grant`
Grant permissions during creation. Defaults to `ALL`.

####`tablespace`
The name of the tablespace to allocate this database to. If not specifies, it defaults to the PostgreSQL default.

####`istemplate`
Define database as a template. Defaults to `false`.


###Resource: postgresql::server::database
This defined type can be used to create a database with no users and no permissions, which is a rare use case.

####`namevar`
The name of the database to create.

####`dbname`
The name of the database, defaults to the namevar.

####`owner`
Name of the database user who should be set as the owner of the database. Defaults to the $user variable set in `postgresql::server` or `postgresql::globals`.

####`tablespace`
Tablespace for where to create this database. Defaults to the defaults defined during PostgreSQL installation.

####`encoding`
Override the character set during creation of the database. Defaults to the default defined during installation.

####`locale`
Override the locale during creation of the database. Defaults to the default defined during installation.

####`istemplate`
Define database as a template. Defaults to `false`.


###Resource: postgresql::server::database\_grant
This defined type manages grant based access privileges for users, wrapping the `postgresql::server::database_grant` for database specific permissions. Consult the PostgreSQL documentation for `grant` for more information.

####`namevar`
Used to uniquely identify this resource, but functionality not used during grant.

####`privilege`
Can be one of `SELECT`, `TEMPORARY`, `TEMP`, `CONNECT`. `ALL` is used as a synonym for `CREATE`. If you need to add multiple privileges, a space delimited string can be used.

####`db`
Database to grant access to.

####`role`
Role or user whom you are granting access for.

####`psql_db`
Database to execute the grant against. This should not ordinarily be changed from the default, which is `postgres`.

####`psql_user`
OS user for running `psql`. Defaults to the default user for the module, usually `postgres`.


###Resource: postgresql::server::pg\_hba\_rule
This defined type allows you to create an access rule for `pg_hba.conf`. For more details see the [PostgreSQL documentation](http://www.postgresql.org/docs/8.2/static/auth-pg-hba-conf.html).

For example:

    postgresql::server::pg_hba_rule { 'allow application network to access app database':
      description => "Open up postgresql for access from 200.1.2.0/24",
      type => 'host',
      database => 'app',
      user => 'app',
      address => '200.1.2.0/24',
      auth_method => 'md5',
    }

This would create a ruleset in `pg_hba.conf` similar to:

    # Rule Name: allow application network to access app database
    # Description: Open up postgresql for access from 200.1.2.0/24
    # Order: 150
    host  app  app  200.1.2.0/24  md5

####`namevar`
A unique identifier or short description for this rule. The namevar doesn't provide any functional usage, but it is stored in the comments of the produced `pg_hba.conf` so the originating resource can be identified.

####`description`
A longer description for this rule if required. Defaults to `none`. This description is placed in the comments above the rule in `pg_hba.conf`.

####`type`
The type of rule, this is usually one of: `local`, `host`, `hostssl` or `hostnossl`.

####`database`
A comma separated list of databases that this rule matches.

####`user`
A comma separated list of database users that this rule matches.

####`address`
If the type is not 'local' you can provide a CIDR based address here for rule matching.

####`auth_method`
The `auth_method` is described further in the `pg_hba.conf` documentation, but it provides the method that is used for authentication for the connection that this rule matches.

####`auth_option`
For certain `auth_method` settings there are extra options that can be passed. Consult the PostgreSQL `pg_hba.conf` documentation for further details.

####`order`
An order for placing the rule in `pg_hba.conf`. Defaults to `150`.

####`target`
This provides the target for the rule, and is generally an internal only property. Use with caution.


###Resource: postgresql::server::role
This resource creates a role or user in PostgreSQL.

####`namevar`
The role name to create.

####`password_hash`
The hash to use during password creation. If the password is not already pre-encrypted in a format that PostgreSQL supports, use the `postgresql_password` function to provide an MD5 hash here, for example:

    postgresql::role { "myusername":
      password_hash => postgresql_password('myusername', 'mypassword'),
    }

####`createdb`
Whether to grant the ability to create new databases with this role. Defaults to `false`.

####`createrole`
Whether to grant the ability to create new roles with this role. Defaults to `false`.

####`login`
Whether to grant login capability for the new role. Defaults to `false`.

####`superuser`
Whether to grant super user capability for the new role. Defaults to `false`.

####`replication`
If `true` provides replication capabilities for this role. Defaults to `false`.

####`connection_limit`
Specifies how many concurrent connections the role can make. Defaults to `-1` meaning no limit.

####`username`
The username of the role to create, defaults to `namevar`.


###Resource: postgresql::server::table\_grant
This defined type manages grant based access privileges for users. Consult the PostgreSQL documentation for `grant` for more information.

####`namevar`
Used to uniquely identify this resource, but functionality not used during grant.

####`privilege`
Can be one of `SELECT`, `INSERT`, `UPDATE`, `REFERENCES`. `ALL` is used as a synonym for `CREATE`. If you need to add multiple privileges, a space delimited string can be used.

####`table`
Table to grant access on.

####`db`
Database of table.

####`role`
Role or user whom you are granting access for.

####`psql_db`
Database to execute the grant against. This should not ordinarily be changed from the default, which is `postgres`.

####`psql_user`
OS user for running `psql`. Defaults to the default user for the module, usually `postgres`.


###Resource: postgresql::server::tablespace
This defined type can be used to create a tablespace. For example:

    postgresql::tablespace { 'tablespace1':
      location => '/srv/space1',
    }

It will create the location if necessary, assigning it the same permissions as your
PostgreSQL server.

####`namevar`
The tablespace name to create.

####`location`
The path to locate this tablespace.

####`owner`
The default owner of the tablespace.

####`spcname`
Name of the tablespace. Defaults to `namevar`.


###Resource: postgresql::validate\_db\_connection
This resource can be utilised inside composite manifests to validate that a client has a valid connection with a remote PostgreSQL database. It can be ran from any node where the PostgreSQL client software is installed to validate connectivity before commencing other dependent tasks in your Puppet manifests, so it is often used when chained to other tasks such as: starting an application server, performing a database migration.

Example usage:

    postgresql::validate_db_connection { 'validate my postgres connection':
      database_host           => 'my.postgres.host',
      database_username       => 'mydbuser',
      database_password       => 'mydbpassword',
      database_name           => 'mydbname',
    }->
    exec { 'rake db:migrate':
      cwd => '/opt/myrubyapp',
    }

####`namevar`
Uniquely identify this resource, but functionally does nothing.

####`database_host`
The hostname of the database you wish to test. Defaults to 'undef' which generally uses the designated local unix socket.

####`database_port`
Port to use when connecting. Default to 'undef' which generally defaults to 5432 depending on your PostgreSQL packaging.

####`database_name`
The name of the database you wish to test. Defaults to 'postgres'.

####`database_username`
Username to connect with. Defaults to 'undef', which when using a unix socket and ident auth will be the user you are running as. If the host is remote you must provide a username.

####`database_password`
Password to connect with. Can be left blank, but that is not recommended.

####`run_as`
The user to run the `psql` command with for authenticiation. This is important when trying to connect to a database locally using Unix sockets and `ident` authentication. It is not needed for remote testing.

####`sleep`
Upon failure, sets the number of seconds to sleep for before trying again.

####`tries`
Upon failure, sets the number of attempts before giving up and failing the resource.

####`create_db_first`
This will ensure the database is created before running the test. This only really works if your test is local. Defaults to `true`.


###Function: postgresql\_password
If you need to generate a postgres encrypted password, use `postgresql_password`. You can call it from your production manifests if you don't mind them containing the clear text versions of your passwords, or you can call it from the command line and then copy and paste the encrypted password into your manifest:

    $ puppet apply --execute 'notify { "test": message => postgresql_password("username", "password") }'

###Function: postgresql\_acls\_to\_resources\_hash(acl\_array, id, order\_offset)
This internal function converts a list of `pg_hba.conf` based acls (passed in as an array of strings) to a format compatible with the `postgresql::pg_hba_rule` resource.

**This function should only be used internally by the module**.

Limitations

Works with versions of PostgreSQL from 8.1 through 9.2.

Current it is only actively tested with the following operating systems:

* Debian 6.x and 7.x
* Centos 5.x and 6.x
* Ubuntu 10.04 and 12.04

Although patches are welcome for making it work with other OS distros, it is considered best effort.

Development

Puppet Labs modules on the Puppet Forge are open projects, and community contributions are essential for keeping them great. We can't access the huge number of platforms and myriad of hardware, software, and deployment configurations that Puppet is intended to serve.

We want to keep it as easy as possible to contribute changes so that our modules work in your environment. There are a few guidelines that we need contributors to follow so that we can have a chance of keeping on top of things.

You can read the complete module contribution guide [on the Puppet Labs wiki.](http://projects.puppetlabs.com/projects/module-site/wiki/Module_contributing)

### Tests

There are two types of tests distributed with the module. Unit tests with rspec-puppet and system tests using rspec-system.

For unit testing, make sure you have:

* rake
* bundler

Install the necessary gems:

    bundle install --path=vendor

And then run the unit tests:

    bundle exec rake spec

The unit tests are ran in Travis-CI as well, if you want to see the results of your own tests regsiter the service hook through Travis-CI via the accounts section for your Github clone of this project.

If you want to run the system tests, make sure you also have:

* vagrant > 1.2.x
* Virtualbox > 4.2.10

Then run the tests using:

    bundle exec rake spec:system

To run the tests on different operating systems, see the sets available in .nodeset.yml and run the specific set with the following syntax:

    RSPEC_SET=debian-607-x64 bundle exec rake spec:system

Transfer Notice

This Puppet module was originally authored by Inkling Systems. The maintainer preferred that Puppet Labs take ownership of the module for future improvement and maintenance as Puppet Labs is using it in the PuppetDB module.  Existing pull requests and issues were transferred over, please fork and continue to contribute here instead of Inkling.

Previously: [https://github.com/inkling/puppet-postgresql](https://github.com/inkling/puppet-postgresql)

Contributors

 * Andrew Moon
 * [Kenn Knowles](https://github.com/kennknowles) ([@kennknowles](https://twitter.com/KennKnowles))
 * Adrien Thebo
 * Albert Koch
 * Andreas Ntaflos
 * Bret Comnes
 * Brett Porter
 * Chris Price
 * dharwood
 * Etienne Pelletier
 * Florin Broasca
 * Henrik
 * Hunter Haugen
 * Jari Bakken
 * Jordi Boggiano
 * Ken Barber
 * nzakaria
 * Richard Arends
 * Spenser Gilliland
 * stormcrow
 * William Van Hevelingen
require 'rubygems'
require 'bundler/setup'

Bundler.require :default

require 'puppetlabs_spec_helper/rake_tasks'
require 'puppet-lint/tasks/puppet-lint'

task :default do
  sh %{rake -T}
end
Version: GnuPG v1.4.7 (GNU/Linux)

mQGiBEeD8koRBACC1VBRsUwGr9gxFFRho9kZpdRUjBJoPhkeOTvp9LzkdAQMFngr
BFi6N0ov1kCX7LLwBmDG+JPR7N+XcH9YR1coSHpLVg+JNy2kFDd4zAyWxJafjZ3a
9zFg9Yx+0va1BJ2t4zVcmKS4aOfbgQ5KwIOWUujalQW5Y+Fw39Gn86qjbwCg5dIo
tkM0l19h2sx50D027pV5aPsD/2c9pfcFTbMhB0CcKS836GH1qY+NCAdUwPs646ee
Ex/k9Uy4qMwhl3HuCGGGa+N6Plyon7V0TzZuRGp/1742dE8IO+I/KLy2L1d1Fxrn
XOTBZd8qe6nBwh12OMcKrsPBVBxn+iSkaG3ULsgOtx+HHLfa1/p22L5+GzGdxizr
peBuA/90cCp+lYcEwdYaRoFVR501yDOTmmzBc1DrsyWP79QMEGzMqa393G0VnqXt
L4pGmunq66Agw2EhPcIt3pDYiCmEt/obdVtSJH6BtmSDB/zYhbE8u3vLP3jfFDa9
KXxgtYj0NvuUVoRmxSKm8jtfmj1L7zoKNz3jl+Ba3L0WxIv4+bRBUG9zdGdyZVNR
TCBSUE0gQnVpbGRpbmcgUHJvamVjdCA8cGdzcWxycG1zLWhhY2tlcnNAcGdmb3Vu
ZHJ5Lm9yZz6IYAQTEQIAIAUCR4PySgIbIwYLCQgHAwIEFQIIAwQWAgMBAh4BAheA
AAoJEB8W0uFELfD4jnkAoMqd6ZwwsgYHZ3hP9vt+DJt1uDW7AKDbRwP8ESKFhwdJ
8m91RPBeJW/tMLkCDQRHg/JKEAgA64+ZXgcERPYfZYo4p+yMTJAAa9aqnE3U4Ni6
ZMB57GPuEy8NfbNya+HiftO8hoozmJdcI6XFyRBCDUVCdZ8SE+PJdOx2FFqZVIu6
dKnr8ykhgLpNNEFDG3boK9UfLj/5lYQ3Y550Iym1QKOgyrJYeAp6sZ+Nx2PavsP3
nMFCSD67BqAbcLCVQN7a2dAUXfEbfXJjPHXTbo1/kxtzE+KCRTLdXEbSEe3nHO04
K/EgTBjeBUOxnciH5RylJ2oGy/v4xr9ed7R1jJtshsDKMdWApwoLlCBJ63jg/4T/
z/OtXmu4AvmWaJxaTl7fPf2GqSqqb6jLCrQAH7AIhXr9V0zPZwADBQgAlpptNQHl
u7euIdIujFwwcxyQGfee6BG+3zaNSEHMVQMuc6bxuvYmgM9r7aki/b0YMfjJBk8v
OJ3Eh1vDH/woJi2iJ13vQ21ot+1JP3fMd6NPR8/qEeDnmVXu7QAtlkmSKI9Rdnjz
FFSUJrQPHnKsH4V4uvAM+njwYD+VFiwlBPTKNeL8cdBb4tPN2cdVJzoAp57wkZAN
VA2tKxNsTJKBi8wukaLWX8+yPHiWCNWItvyB4WCEp/rZKG4A868NM5sZQMAabpLd
l4fTiGu68OYgK9qUPZvhEAL2C1jPDVHPkLm+ZsD+90Pe66w9vB00cxXuHLzm8Pad
GaCXCY8h3xi6VIhJBBgRAgAJBQJHg/JKAhsMAAoJEB8W0uFELfD4K4cAoJ4yug8y
1U0cZEiF5W25HDzMTtaDAKCaM1m3Cbd+AZ0NGWNg/VvIX9MsPA==
=au6K
#!/usr/bin/env bash

# usage is: validate_db_connection 2 50 psql

SLEEP=$1
TRIES=$2
PSQL=$3

STATE=1

for (( c=1; c<=$TRIES; c++ ))
do
  echo $c
  if [ $c -gt 1 ]
  then
    echo 'sleeping'
    sleep $SLEEP
  fi

  /bin/echo "SELECT 1" | $PSQL
  STATE=$?

  if [ $STATE -eq 0 ]
  then
    exit 0
  fi
done

echo 'Unable to connect to postgresql'

exit 1
module Puppet::Parser::Functions
  newfunction(:postgresql_acls_to_resources_hash, :type => :rvalue, :doc => <<-EOS
    This internal function translates the ipv(4|6)acls format into a resource
    suitable for create_resources. It is not intended to be used outside of the
    postgresql internal classes/defined resources.

    This function accepts an array of strings that are pg_hba.conf rules. It
    will return a hash that can be fed into create_resources to create multiple
    individual pg_hba_rule resources.

    The second parameter is an identifier that will be included in the namevar
    to provide uniqueness. It must be a string.

    The third parameter is an order offset, so you can start the order at an
    arbitrary starting point.
    EOS
  ) do |args|
    func_name = "postgresql_acls_to_resources_hash()"

    raise(Puppet::ParseError, "#{func_name}: Wrong number of arguments " +
      "given (#{args.size} for 3)") if args.size != 3

    acls = args[0]
    raise(Puppet::ParseError, "#{func_name}: first argument must be an array") \
      unless acls.instance_of? Array

    id = args[1]
    raise(Puppet::ParseError, "#{func_name}: second argument must be a string") \
      unless id.instance_of? String

    offset = args[2].to_i
    raise(Puppet::ParseError, "#{func_name}: third argument must be a number") \
      unless offset.instance_of? Fixnum

    resources = {}
    acls.each do |acl|
      index = acls.index(acl)

      parts = acl.split

      raise(Puppet::ParseError, "#{func_name}: acl line #{index} does not " +
        "have enough parts") unless parts.length >= 4

      resource = {
        'type' => parts[0],
        'database' => parts[1],
        'user' => parts[2],
        'order' => format('%03d', offset + index),
      }
      if parts[0] == 'local' then
        resource['auth_method'] = parts[3]
        if parts.length > 4 then
          resource['auth_option'] = parts.last(parts.length - 4).join(" ")
        end
      else
        if parts[4] =~ /^\d/
          resource['address'] = parts[3] + ' ' + parts[4]
          resource['auth_method'] = parts[5]

          if parts.length > 6 then
            resource['auth_option'] = parts.last(parts.length - 6).join(" ")
          end
        else
          resource['address'] = parts[3]
          resource['auth_method'] = parts[4]

          if parts.length > 5 then
            resource['auth_option'] = parts.last(parts.length - 5).join(" ")
          end
        end
      end
      resources["postgresql class generated rule #{id} #{index}"] = resource
    end
    resources
  end
end
require 'digest/md5'

module Puppet::Parser::Functions
  newfunction(:postgresql_escape, :type => :rvalue, :doc => <<-EOS
    Safely escapes a string using $$ using a random tag which should be consistent
    EOS
  ) do |args|

    raise(Puppet::ParseError, "postgresql_escape(): Wrong number of arguments " +
      "given (#{args.size} for 1)") if args.size != 1

    password = args[0]

    if password !~ /\$\$/ 
      retval = "$$#{password}$$"
    else
      escape = Digest::MD5.hexdigest(password)[0..5].gsub(/\d/,'')
      until password !~ /#{escape}/
        escape = Digest::MD5.hexdigest(escape)[0..5].gsub(/\d/,'')
      end
      retval = "$#{escape}$#{password}$#{escape}$"
    end
    retval 
  end
end
# hash a string as mysql's "PASSWORD()" function would do it
require 'digest/md5'

module Puppet::Parser::Functions
  newfunction(:postgresql_password, :type => :rvalue, :doc => <<-EOS
    Returns the postgresql password hash from the clear text username / password.
    EOS
  ) do |args|

    raise(Puppet::ParseError, "postgresql_password(): Wrong number of arguments " +
      "given (#{args.size} for 2)") if args.size != 2

    username = args[0]
    password = args[1]

    'md5' + Digest::MD5.hexdigest(password + username)
  end
end
require 'puppet/provider/parsedfile'

Puppet::Type.type(:postgresql_conf).provide(
  :parsed,
  :parent => Puppet::Provider::ParsedFile,
  :default_target => '/etc/postgresql.conf',
  :filetype => :flat
) do
  desc "Set key/values in postgresql.conf."

  text_line :comment, :match => /^\s*#/
  text_line :blank, :match => /^\s*$/

  record_line :parsed,
    :fields   => %w{name value comment},
    :optional => %w{comment},
    :match    => /^\s*([\w\.]+)\s*=?\s*(.*?)(?:\s*#\s*(.*))?\s*$/,
    :to_line  => proc { |h|

      # simple string and numeric values don't need to be enclosed in quotes
      dontneedquote = h[:value].match(/^(\w+|[0-9.-]+)$/)
      dontneedequal = h[:name].match(/^(include|include_if_exists)$/i)

      str =  h[:name].downcase # normalize case
      str += dontneedequal ? ' ' : ' = '
      str += "'" unless dontneedquote && !dontneedequal
      str += h[:value]
      str += "'" unless dontneedquote && !dontneedequal
      str += " # #{h[:comment]}" unless (h[:comment].nil? or h[:comment] == :absent)
      str
    },
    :post_parse => proc { |h|
      h[:name].downcase! # normalize case
      h[:value].gsub!(/(^'|'$)/, '') # strip out quotes
    }

end
Puppet::Type.type(:postgresql_psql).provide(:ruby) do

  def command()
    if ((! resource[:unless]) or (resource[:unless].empty?))
      if (resource.refreshonly?)
        # So, if there's no 'unless', and we're in "refreshonly" mode,
        # we need to return the target command here.  If we don't,
        # then Puppet will generate an event indicating that this
        # property has changed.
        return resource[:command]
      end

      # if we're not in refreshonly mode, then we return nil,
      # which will cause Puppet to sync this property.  This
      # is what we want if there is no 'unless' value specified.
      return nil
    end

    if Puppet::PUPPETVERSION.to_f < 4
      output, status = run_unless_sql_command(resource[:unless])
    else
      output = run_unless_sql_command(resource[:unless])
      status = output.exitcode
    end

    if status != 0
      puts status
      self.fail("Error evaluating 'unless' clause: '#{output}'")
    end
    result_count = output.strip.to_i
    if result_count > 0
      # If the 'unless' query returned rows, then we don't want to execute
      # the 'command'.  Returning the target 'command' here will cause
      # Puppet to treat this property as already being 'insync?', so it
      # won't call the setter to run the 'command' later.
      return resource[:command]
    end

    # Returning 'nil' here will cause Puppet to see this property
    # as out-of-sync, so it will call the setter later.
    nil
  end

  def command=(val)
    output, status = run_sql_command(val)

    if status != 0
      self.fail("Error executing SQL; psql returned #{status}: '#{output}'")
    end
  end


  def run_unless_sql_command(sql)
    # for the 'unless' queries, we wrap the user's query in a 'SELECT COUNT',
    # which makes it easier to parse and process the output.
    run_sql_command('SELECT COUNT(*) FROM (' <<  sql << ') count')
  end

  def run_sql_command(sql)
    if resource[:search_path]
      sql = "set search_path to #{Array(resource[:search_path]).join(',')}; #{sql}"
    end

    command = [resource[:psql_path]]
    command.push("-d", resource[:db]) if resource[:db]
    command.push("-t", "-c", sql)

    if resource[:cwd]
      Dir.chdir resource[:cwd] do
        run_command(command, resource[:psql_user], resource[:psql_group])
      end
    else
      run_command(command, resource[:psql_user], resource[:psql_group])
    end
  end

  def run_command(command, user, group)
    if Puppet::PUPPETVERSION.to_f < 3.4
      Puppet::Util::SUIDManager.run_and_capture(command, user, group)
    else
      output = Puppet::Util::Execution.execute(command, {
        :uid                => user,
        :gid                => group,
        :failonfail         => false,
        :combine            => true,
        :override_locale    => true,
        :custom_environment => {}
      })
      [output, $CHILD_STATUS.dup]
    end
  end

end
module Puppet
  newtype(:postgresql_conf) do

    @doc = "This type allows puppet to manage postgresql.conf parameters."

    ensurable

    newparam(:name) do
      desc "The postgresql parameter name to manage."
      isnamevar

      newvalues(/^[\w\.]+$/)
    end

    newproperty(:value) do
      desc "The value to set for this parameter."
    end

    newproperty(:target) do
      desc "The path to postgresql.conf"
      defaultto {
        if @resource.class.defaultprovider.ancestors.include?(Puppet::Provider::ParsedFile)
          @resource.class.defaultprovider.default_target
        else
          nil
        end
      }
    end

  end
end
Puppet::Type.newtype(:postgresql_psql) do

  newparam(:name) do
    desc "An arbitrary tag for your own reference; the name of the message."
    isnamevar
  end

  newproperty(:command) do
    desc 'The SQL command to execute via psql.'

    defaultto { @resource[:name] }

    def sync(refreshing = false)
      # We're overriding 'sync' here in order to do some magic
      # in support of providing a 'refreshonly' parameter.  This
      # is kind of hacky because the logic for 'refreshonly' is
      # spread between the type and the provider, but this is
      # the least horrible way that I could determine to accomplish
      # it.
      #
      # Note that our overridden version of 'sync' takes a parameter,
      # 'refreshing', which the parent version doesn't take.  This
      # allows us to call the sync method directly from the 'refresh'
      # method, and then inside of the body of 'sync' we can tell
      # whether or not we're refreshing.

      if (!@resource.refreshonly? || refreshing)
        # If we're not in 'refreshonly' mode, or we're not currently
        # refreshing, then we just call the parent method.
        super()
      else
        # If we get here, it means we're in 'refreshonly' mode and
        # we're not being called by the 'refresh' method, so we
        # just no-op.  We'll be called again by the 'refresh'
        # method momentarily.
        nil
      end
    end
  end

  newparam(:unless) do
    desc "An optional SQL command to execute prior to the main :command; " +
        "this is generally intended to be used for idempotency, to check " +
        "for the existence of an object in the database to determine whether " +
        "or not the main SQL command needs to be executed at all."
  end

  newparam(:db) do
    desc "The name of the database to execute the SQL command against."
  end

  newparam(:search_path) do
    desc "The schema search path to use when executing the SQL command"
  end

  newparam(:psql_path) do
    desc "The path to psql executable."
    defaultto("psql")
  end

  newparam(:psql_user) do
    desc "The system user account under which the psql command should be executed."
    defaultto("postgres")
  end

  newparam(:psql_group) do
    desc "The system user group account under which the psql command should be executed."
    defaultto("postgres")
  end

  newparam(:cwd, :parent => Puppet::Parameter::Path) do
    desc "The working directory under which the psql command should be executed."
    defaultto("/tmp")
  end

  newparam(:refreshonly, :boolean => true) do
    desc "If 'true', then the SQL will only be executed via a notify/subscribe event."

    defaultto(:false)
    newvalues(:true, :false)
  end

  def refresh()
    # All of the magic for this type is attached to the ':command' property, so
    # we just need to sync it to accomplish a 'refresh'.
    self.property(:command).sync(true)
  end

end
# Install client cli tool. See README.md for more details.
class postgresql::client (
  $package_name   = $postgresql::params::client_package_name,
  $package_ensure = 'present'
) inherits postgresql::params {
  validate_string($package_name)

  package { 'postgresql-client':
    ensure  => $package_ensure,
    name    => $package_name,
    tag     => 'postgresql',
  }

  $file_ensure = $package_ensure ? {
    'present' => 'file',
    true      => 'file',
    'absent'  => 'absent',
    false     => 'absent',
    default   => 'file',
  }
  file { "/usr/local/bin/validate_postgresql_connection.sh":
    ensure => $file_ensure,
    source => "puppet:///modules/postgresql/validate_postgresql_connection.sh",
    owner  => 0,
    group  => 0,
    mode   => 0755,
  }

}
# Class for setting cross-class global overrides. See README.md for more
# details.
class postgresql::globals (
  $ensure               = undef,

  $client_package_name  = undef,
  $server_package_name  = undef,
  $contrib_package_name = undef,
  $devel_package_name   = undef,
  $java_package_name    = undef,
  $plperl_package_name  = undef,
  $python_package_name  = undef,

  $service_name         = undef,
  $service_provider     = undef,
  $service_status       = undef,
  $default_database     = undef,

  $initdb_path          = undef,
  $createdb_path        = undef,
  $psql_path            = undef,
  $pg_hba_conf_path     = undef,
  $postgresql_conf_path = undef,

  $pg_hba_conf_defaults = undef,

  $datadir              = undef,
  $confdir              = undef,
  $bindir               = undef,
  $xlogdir              = undef,

  $user                 = undef,
  $group                = undef,

  $version              = undef,

  $needs_initdb         = undef,

  $encoding             = undef,
  $locale               = undef,

  $manage_firewall      = undef,
  $manage_pg_hba_conf   = undef,
  $firewall_supported   = undef,

  $manage_package_repo  = undef
) {
  # We are determining this here, because it is needed by the package repo
  # class.
  $default_version = $::osfamily ? {
    /^(RedHat|Linux)/ => $::operatingsystem ? {
      'Fedora' => $::operatingsystemrelease ? {
        /^(18|19|20)$/ => '9.2',
        /^(17)$/ => '9.1',
        default => undef,
      },
      'Amazon' => '9.2',
      default => $::operatingsystemrelease ? {
        /^6\./ => '8.4',
        /^5\./ => '8.1',
        default => undef,
      },
    },
    'Debian' => $::operatingsystem ? {
      'Debian' => $::operatingsystemrelease ? {
        /^6\./ => '8.4',
        /^(wheezy|7\.)/ => '9.1',
        default => undef,
      },
      'Ubuntu' => $::operatingsystemrelease ? {
        /^(14.04)$/ => '9.3',
        /^(11.10|12.04|12.10|13.04|13.10)$/ => '9.1',
        /^(10.04|10.10|11.04)$/ => '8.4',
        default => undef,
      },
      default => undef,
    },
    'Archlinux' => $::operatingsystem ? {
      /Archlinux/ => '9.2',
      default => '9.2',
    },
    'FreeBSD' => '93',
    default => undef,
  }
  $globals_version = pick($version, $default_version, 'unknown')

  # Setup of the repo only makes sense globally, so we are doing this here.
  if($manage_package_repo) {
    class { 'postgresql::repo':
      ensure  => $ensure,
      version => $globals_version
    }
  }
}
# This class installs postgresql development libraries. See README.md for more
# details.
class postgresql::lib::devel(
  $package_name   = $postgresql::params::devel_package_name,
  $package_ensure = 'present'
) inherits postgresql::params {

  validate_string($package_name)

  package { 'postgresql-devel':
    ensure => $package_ensure,
    name   => $package_name,
    tag    => 'postgresql',
  }
}
# This class installs the postgresql jdbc connector. See README.md for more
# details.
class postgresql::lib::java (
  $package_name   = $postgresql::params::java_package_name,
  $package_ensure = 'present'
) inherits postgresql::params {

  validate_string($package_name)

  package { 'postgresql-jdbc':
    ensure => $package_ensure,
    name   => $package_name,
  }

}
# This class installs the python libs for postgresql. See README.md for more
# details.
class postgresql::lib::python(
  $package_name   = $postgresql::params::python_package_name,
  $package_ensure = 'present'
) inherits postgresql::params {

  package { 'python-psycopg2':
    ensure => $package_ensure,
    name   => $package_name,
  }

}
# PRIVATE CLASS: do not use directly
class postgresql::params inherits postgresql::globals {
  $ensure                     = true
  $version                    = $globals_version
  $listen_addresses           = 'localhost'
  $ip_mask_deny_postgres_user = '0.0.0.0/0'
  $ip_mask_allow_all_users    = '127.0.0.1/32'
  $ipv4acls                   = []
  $ipv6acls                   = []
  $user                       = pick($user, 'postgres')
  $group                      = pick($group, 'postgres')
  $encoding                   = $encoding
  $locale                     = $locale
  $service_provider           = $service_provider
  $manage_firewall            = $manage_firewall
  $manage_pg_hba_conf         = pick($manage_pg_hba_conf, true)

  # Amazon Linux's OS Family is 'Linux', operating system 'Amazon'.
  case $::osfamily {
    'RedHat', 'Linux': {
      $needs_initdb       = pick($needs_initdb, true)
      $firewall_supported = pick($firewall_supported, true)

      if $version == $default_version {
        $client_package_name  = pick($client_package_name, 'postgresql')
        $server_package_name  = pick($server_package_name, 'postgresql-server')
        $contrib_package_name = pick($contrib_package_name,'postgresql-contrib')
        $devel_package_name   = pick($devel_package_name, 'postgresql-devel')
        $java_package_name    = pick($java_package_name, 'postgresql-jdbc')
        $plperl_package_name  = pick($plperl_package_name, 'postgresql-plperl')
        $service_name         = pick($service_name, 'postgresql')
        $bindir               = pick($bindir, '/usr/bin')
        $datadir              = $::operatingsystem ? {
          'Amazon' => pick($datadir, '/var/lib/pgsql9/data'),
          default  => pick($datadir, '/var/lib/pgsql/data'),
        }
        $confdir              = pick($confdir, $datadir)
      } else {
        $version_parts        = split($version, '[.]')
        $package_version      = "${version_parts[0]}${version_parts[1]}"
        $client_package_name  = pick($client_package_name, "postgresql${package_version}")
        $server_package_name  = pick($server_package_name, "postgresql${package_version}-server")
        $contrib_package_name = pick($contrib_package_name,"postgresql${package_version}-contrib")
        $devel_package_name   = pick($devel_package_name, "postgresql${package_version}-devel")
        $java_package_name    = pick($java_package_name, "postgresql${package_version}-jdbc")
        $plperl_package_name  = pick($plperl_package_name, "postgresql${package_version}-plperl")
        $service_name         = pick($service_name, "postgresql-${version}")
        $bindir               = pick($bindir, "/usr/pgsql-${version}/bin")
        $datadir              = $::operatingsystem ? {
          'Amazon' => pick($datadir, "/var/lib/pgsql9/${version}/data"),
          default  => pick($datadir, "/var/lib/pgsql/${version}/data"),
        }
        $confdir              = pick($confdir, $datadir)
      }
      $psql_path            = pick($psql_path, "${bindir}/psql")

      $service_status      = $service_status
      $python_package_name = pick($python_package_name, 'python-psycopg2')
    }

    'Archlinux': {
      # Based on the existing version of the firewall module, this is normally
      # true for Archlinux, but archlinux users want more control.
      # so they can set it themself
      $firewall_supported = pick($firewall_supported, true)
      $needs_initdb       = pick($needs_initdb, true)

      # Archlinux doesn't have a client-package but has a libs package which
      # pulls in postgresql server
      $client_package_name  = pick($client_package_name, 'postgresql')
      $server_package_name  = pick($server_package_name, 'postgresql-libs')
      $java_package_name    = pick($java_package_name, 'postgresql-jdbc')
      # Archlinux doesn't have develop packages
      $devel_package_name   = pick($devel_package_name, 'postgresql-devel')
      # Archlinux does have postgresql-contrib but it isn't maintained
      $contrib_package_name = pick($contrib_package_name,'undef')
      # Archlinux postgresql package provides plperl
      $plperl_package_name  = pick($plperl_package_name, 'undef')
      $service_name         = pick($service_name, 'postgresql')
      $bindir               = pick($bindir, '/usr/bin')
      $datadir              = pick($datadir, '/var/lib/postgres/data')
      $confdir              = pick($confdir, $datadir)
      $psql_path            = pick($psql_path, "${bindir}/psql")

      $service_status      = $service_status
      $python_package_name = pick($python_package_name, 'python-psycopg2')
    }

    'Debian': {

      if $manage_package_repo == true {
        $needs_initdb = pick($needs_initdb, true)
        $service_name = pick($service_name, 'postgresql')
      } else {
        $needs_initdb = pick($needs_initdb, false)
        $service_name = $::operatingsystem ? {
          'Debian' => pick($service_name, 'postgresql'),
          'Ubuntu' => $::lsbmajdistrelease ? {
            '10' => pick($service_name, "postgresql-${version}"),
            default => pick($service_name, 'postgresql'),
          },
          default => undef
        }
      }

      $client_package_name  = pick($client_package_name, "postgresql-client-${version}")
      $server_package_name  = pick($server_package_name, "postgresql-${version}")
      $contrib_package_name = pick($contrib_package_name, "postgresql-contrib-${version}")
      $devel_package_name   = pick($devel_package_name, 'libpq-dev')
      $java_package_name    = pick($java_package_name, 'libpostgresql-jdbc-java')
      $plperl_package_name  = pick($plperl_package_name, "postgresql-plperl-${version}")
      $python_package_name  = pick($python_package_name, 'python-psycopg2')

      $bindir               = pick($bindir, "/usr/lib/postgresql/${version}/bin")
      $datadir              = pick($datadir, "/var/lib/postgresql/${version}/main")
      $confdir              = pick($confdir, "/etc/postgresql/${version}/main")
      $service_status       = pick($service_status, "/etc/init.d/${service_name} status | /bin/egrep -q 'Running clusters: .+|online'")
      $psql_path            = pick($psql_path, "/usr/bin/psql")

      $firewall_supported   = pick($firewall_supported, true)
    }

    'FreeBSD': {

      $client_package_name  = pick($client_package_name, "databases/postgresql${version}-client")
      $server_package_name  = pick($server_package_name, "databases/postgresql${version}-server")
      $contrib_package_name = pick($contrib_package_name, "databases/postgresql${version}-contrib")
      $devel_package_name   = pick($devel_package_name, 'databases/postgresql-libpqxx3')
      $java_package_name    = pick($java_package_name, 'databases/postgresql-jdbc')
      $plperl_package_name  = pick($plperl_package_name, "databases/postgresql${version}-plperl")
      $python_package_name  = pick($python_package_name, 'databases/py-psycopg2')

      $service_name         = pick($service_name, 'postgresql')
      $bindir               = pick($bindir, '/usr/local/bin')
      $datadir              = pick($datadir, '/usr/local/pgsql/data')
      $confdir              = pick($confdir, '/usr/local/share/postgresql')
      $service_status       = pick($service_status, "/usr/local/etc/rc.d/${service_name} status")
      $psql_path            = pick($psql_path, "${bindir}/psql")

      $firewall_supported   = pick($firewall_supported, false)
      $needs_initdb         = pick($needs_initdb, true)
    }

    default: {
      # Based on the existing version of the firewall module, this is normally
      # false for other OS, but this allows an escape hatch to override it.
      $firewall_supported = pick($firewall_supported, false)

      $psql_path            = pick($psql_path, "${bindir}/psql")

      # Since we can't determine defaults on our own, we rely on users setting
      # parameters with the postgresql::globals class. Here we are checking
      # that the mandatory minimum is set for the module to operate.
      $err_prefix = "Module ${module_name} does not provide defaults for osfamily: ${::osfamily} operatingsystem: ${::operatingsystem}; please specify a value for ${module_name}::globals::"
      if ($needs_initdb == undef) { fail("${err_prefix}needs_initdb") }
      if ($service_name == undef) { fail("${err_prefix}service_name") }
      if ($client_package_name == undef) { fail("${err_prefix}client_package_name") }
      if ($server_package_name == undef) { fail("${err_prefix}server_package_name") }
      if ($bindir == undef) { fail("${err_prefix}bindir") }
      if ($datadir == undef) { fail("${err_prefix}datadir") }
      if ($confdir == undef) { fail("${err_prefix}confdir") }
    }
  }

  $initdb_path          = pick($initdb_path, "${bindir}/initdb")
  $createdb_path        = pick($createdb_path, "${bindir}/createdb")
  $pg_hba_conf_path     = pick($pg_hba_conf_path, "${confdir}/pg_hba.conf")
  $pg_hba_conf_defaults = pick($pg_hba_conf_defaults, true)
  $postgresql_conf_path = pick($postgresql_conf_path, "${confdir}/postgresql.conf")
  $default_database     = pick($default_database, 'postgres')

  if($version == 'unknown') {
    fail('No preferred version defined or automatically detected.')
  }
}
# PRIVATE CLASS: do not use directly
class postgresql::repo (
  $ensure  = $postgresql::params::ensure,
  $version = undef
) inherits postgresql::params {
  case $::osfamily {
    'RedHat', 'Linux': {
      if $version == undef {
        fail("The parameter 'version' for 'postgresql::repo' is undefined. You must always define it when osfamily == Redhat or Linux")
      }
      class { 'postgresql::repo::yum_postgresql_org': }
    }

    'Debian': {
      class { 'postgresql::repo::apt_postgresql_org': }
    }

    default: {
      fail("Unsupported managed repository for osfamily: ${::osfamily}, operatingsystem: ${::operatingsystem}, module ${module_name} currently only supports managing repos for osfamily RedHat and Debian")
    }
  }
}
# PRIVATE CLASS: do not use directly
class postgresql::repo::apt_postgresql_org inherits postgresql::repo {
  if($ensure == 'present' or $ensure == true) {
    # Here we have tried to replicate the instructions on the PostgreSQL site:
    #
    # http://www.postgresql.org/download/linux/debian/
    #
    apt::pin { 'apt.postgresql.org':
      originator => 'apt.postgresql.org',
      priority   => 500,
    }->
    apt::source { 'apt.postgresql.org':
      location          => 'http://apt.postgresql.org/pub/repos/apt/',
      release           => "${::lsbdistcodename}-pgdg",
      repos             => "main ${version}",
      key               => 'ACCC4CF8',
      key_source        => 'http://apt.postgresql.org/pub/repos/apt/ACCC4CF8.asc',
      include_src       => false,
    }

    Apt::Source['apt.postgresql.org']->Package<|tag == 'postgresql'|>
  } else {
    apt::source { 'apt.postgresql.org':
      ensure => absent,
    }
    apt::pin { 'apt.postgresql.org':
      ensure => absent,
    }
  }
}
# PRIVATE CLASS: do not use directly
class postgresql::repo::yum_postgresql_org inherits postgresql::repo {
  $version_parts   = split($version, '[.]')
  $package_version = "${version_parts[0]}${version_parts[1]}"
  $gpg_key_path    = "/etc/pki/rpm-gpg/RPM-GPG-KEY-PGDG-${package_version}"

  if ($ensure == 'present' or $ensure == true) {
    file { $gpg_key_path:
      source => 'puppet:///modules/postgresql/RPM-GPG-KEY-PGDG',
      before => Yumrepo['yum.postgresql.org']
    }

    if($::operatingsystem == 'Fedora') {
      $label1 = 'fedora'
      $label2 = $label1
    } else {
      $label1 = 'redhat'
      $label2 = 'rhel'
    }

    yumrepo { 'yum.postgresql.org':
      descr    => "PostgreSQL ${version} \$releasever - \$basearch",
      baseurl  => "http://yum.postgresql.org/${version}/${label1}/${label2}-\$releasever-\$basearch",
      enabled  => 1,
      gpgcheck => 1,
      gpgkey   => "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-PGDG-${package_version}",
    }

    Yumrepo['yum.postgresql.org'] -> Package<|tag == 'postgresql'|>
  } else {
    yumrepo { 'yum.postgresql.org':
      enabled => absent,
    }->
    file { $gpg_key_path:
      ensure => absent,
    }
  }
}
# This installs a PostgreSQL server. See README.md for more details.
class postgresql::server (
  $ensure                     = $postgresql::params::ensure,

  $version                    = $postgresql::params::version,

  $postgres_password          = undef,

  $package_name               = $postgresql::params::server_package_name,
  $client_package_name        = $postgresql::params::client_package_name,
  $package_ensure             = $ensure,

  $plperl_package_name        = $postgresql::params::plperl_package_name,

  $service_name               = $postgresql::params::service_name,
  $service_provider           = $postgresql::params::service_provider,
  $service_status             = $postgresql::params::service_status,
  $default_database           = $postgresql::params::default_database,

  $listen_addresses           = $postgresql::params::listen_addresses,
  $ip_mask_deny_postgres_user = $postgresql::params::ip_mask_deny_postgres_user,
  $ip_mask_allow_all_users    = $postgresql::params::ip_mask_allow_all_users,
  $ipv4acls                   = $postgresql::params::ipv4acls,
  $ipv6acls                   = $postgresql::params::ipv6acls,

  $initdb_path                = $postgresql::params::initdb_path,
  $createdb_path              = $postgresql::params::createdb_path,
  $psql_path                  = $postgresql::params::psql_path,
  $pg_hba_conf_path           = $postgresql::params::pg_hba_conf_path,
  $postgresql_conf_path       = $postgresql::params::postgresql_conf_path,

  $datadir                    = $postgresql::params::datadir,
  $xlogdir                    = $postgresql::params::xlogdir,

  $pg_hba_conf_defaults       = $postgresql::params::pg_hba_conf_defaults,

  $user                       = $postgresql::params::user,
  $group                      = $postgresql::params::group,

  $needs_initdb               = $postgresql::params::needs_initdb,

  $encoding                   = $postgresql::params::encoding,
  $locale                     = $postgresql::params::locale,

  $manage_firewall            = $postgresql::params::manage_firewall,
  $manage_pg_hba_conf         = $postgresql::params::manage_pg_hba_conf,
  $firewall_supported         = $postgresql::params::firewall_supported
) inherits postgresql::params {
  $pg = 'postgresql::server'

  if ($ensure == 'present' or $ensure == true) {
    # Reload has its own ordering, specified by other defines
    class { "${pg}::reload": require => Class["${pg}::install"] }

    anchor { "${pg}::start": }->
    class { "${pg}::install": }->
    class { "${pg}::initdb": }->
    class { "${pg}::config": }->
    class { "${pg}::service": }->
    class { "${pg}::passwd": }->
    class { "${pg}::firewall": }->
    anchor { "${pg}::end": }
  } else {
    anchor { "${pg}::start": }->
    class { "${pg}::firewall": }->
    class { "${pg}::passwd": }->
    class { "${pg}::service": }->
    class { "${pg}::install": }->
    class { "${pg}::initdb": }->
    class { "${pg}::config": }->
    anchor { "${pg}::end": }
  }
}
# PRIVATE CLASS: do not call directly
class postgresql::server::config {
  $ensure                     = $postgresql::server::ensure
  $ip_mask_deny_postgres_user = $postgresql::server::ip_mask_deny_postgres_user
  $ip_mask_allow_all_users    = $postgresql::server::ip_mask_allow_all_users
  $listen_addresses           = $postgresql::server::listen_addresses
  $ipv4acls                   = $postgresql::server::ipv4acls
  $ipv6acls                   = $postgresql::server::ipv6acls
  $pg_hba_conf_path           = $postgresql::server::pg_hba_conf_path
  $postgresql_conf_path       = $postgresql::server::postgresql_conf_path
  $pg_hba_conf_defaults       = $postgresql::server::pg_hba_conf_defaults
  $user                       = $postgresql::server::user
  $group                      = $postgresql::server::group
  $version                    = $postgresql::server::version
  $manage_pg_hba_conf         = $postgresql::server::manage_pg_hba_conf

  if ($ensure == 'present' or $ensure == true) {

    if ($manage_pg_hba_conf == true) {
      # Prepare the main pg_hba file
      concat { $pg_hba_conf_path:
        owner  => 0,
        group  => $group,
        mode   => '0640',
        warn   => true,
        notify => Class['postgresql::server::reload'],
      }

      if $pg_hba_conf_defaults {
        Postgresql::Server::Pg_hba_rule {
          database => 'all',
          user => 'all',
        }

        # Lets setup the base rules
        $local_auth_option = $version ? {
          '8.1'   => 'sameuser',
          default => undef,
        }
        postgresql::server::pg_hba_rule { 'local access as postgres user':
          type        => 'local',
          user        => $user,
          auth_method => 'ident',
          auth_option => $local_auth_option,
          order       => '001',
        }
        postgresql::server::pg_hba_rule { 'local access to database with same name':
          type        => 'local',
          auth_method => 'ident',
          auth_option => $local_auth_option,
          order       => '002',
        }
        postgresql::server::pg_hba_rule { 'allow localhost TCP access to postgresql user':
          type        => 'host',
          user        => $user,
          address     => '127.0.0.1/32',
          auth_method => 'md5',
          order       => '003',
        }
        postgresql::server::pg_hba_rule { 'deny access to postgresql user':
          type        => 'host',
          user        => $user,
          address     => $ip_mask_deny_postgres_user,
          auth_method => 'reject',
          order       => '004',
        }

        # ipv4acls are passed as an array of rule strings, here we transform
        # them into a resources hash, and pass the result to create_resources
        $ipv4acl_resources = postgresql_acls_to_resources_hash($ipv4acls,
        'ipv4acls', 10)
        create_resources('postgresql::server::pg_hba_rule', $ipv4acl_resources)

        postgresql::server::pg_hba_rule { 'allow access to all users':
          type        => 'host',
          address     => $ip_mask_allow_all_users,
          auth_method => 'md5',
          order       => '100',
        }
        postgresql::server::pg_hba_rule { 'allow access to ipv6 localhost':
          type        => 'host',
          address     => '::1/128',
          auth_method => 'md5',
          order       => '101',
        }

        # ipv6acls are passed as an array of rule strings, here we transform
        # them into a resources hash, and pass the result to create_resources
        $ipv6acl_resources = postgresql_acls_to_resources_hash($ipv6acls,
        'ipv6acls', 102)
        create_resources('postgresql::server::pg_hba_rule', $ipv6acl_resources)
      }
    }

    # We must set a "listen_addresses" line in the postgresql.conf if we
    # want to allow any connections from remote hosts.
    postgresql::server::config_entry { 'listen_addresses':
      value => $listen_addresses,
    }
  } else {
    file { $pg_hba_conf_path:
      ensure => absent,
    }
    file { $postgresql_conf_path:
      ensure => absent,
    }
  }
}
# Manage a postgresql.conf entry. See README.md for more details.
define postgresql::server::config_entry (
  $ensure = 'present',
  $value  = undef,
  $path   = false
) {
  $postgresql_conf_path = $postgresql::server::postgresql_conf_path

  $target = $path ? {
    false   => $postgresql_conf_path,
    default => $path,
  }

  case $name {
    /data_directory|hba_file|ident_file|include|listen_addresses|port|max_connections|superuser_reserved_connections|unix_socket_directory|unix_socket_group|unix_socket_permissions|bonjour|bonjour_name|ssl|ssl_ciphers|shared_buffers|max_prepared_transactions|max_files_per_process|shared_preload_libraries|wal_level|wal_buffers|archive_mode|max_wal_senders|hot_standby|logging_collector|silent_mode|track_activity_query_size|autovacuum_max_workers|autovacuum_freeze_max_age|max_locks_per_transaction|max_pred_locks_per_transaction|restart_after_crash|lc_messages|lc_monetary|lc_numeric|lc_time/: {
      Postgresql_conf {
        notify => Class['postgresql::server::service'],
        before => Class['postgresql::server::reload'],
      }
    }

    default: {
      Postgresql_conf {
        notify => Class['postgresql::server::reload'],
      }
    }
  }

  case $ensure {
    /present|absent/: {
      postgresql_conf { $name:
        ensure  => $ensure,
        target  => $target,
        value   => $value,
        require => Class['postgresql::server::initdb'],
      }
    }

    default: {
      fail("Unknown value for ensure '${ensure}'.")
    }
  }
}
# Install the contrib postgresql packaging. See README.md for more details.
class postgresql::server::contrib (
  $package_name   = $postgresql::params::contrib_package_name,
  $package_ensure = 'present'
) inherits postgresql::params {
  validate_string($package_name)

  package { 'postgresql-contrib':
    ensure => $package_ensure,
    name   => $package_name,
    tag    => 'postgresql',
  }

  if($package_ensure == 'present' or $package_ensure == true) {
    anchor { 'postgresql::server::contrib::start': }->
    Class['postgresql::server::install']->
    Package['postgresql-contrib']->
    Class['postgresql::server::service']->
    anchor { 'postgresql::server::contrib::end': }
  } else {
    anchor { 'postgresql::server::contrib::start': }->
    Class['postgresql::server::service']->
    Package['postgresql-contrib']->
    Class['postgresql::server::install']->
    anchor { 'postgresql::server::contrib::end': }
  }
}
# Define for creating a database. See README.md for more details.
define postgresql::server::database(
  $dbname     = $title,
  $owner      = $postgresql::server::user,
  $tablespace = undef,
  $template   = 'template0',
  $encoding   = $postgresql::server::encoding,
  $locale     = $postgresql::server::locale,
  $istemplate = false
) {
  $createdb_path = $postgresql::server::createdb_path
  $user          = $postgresql::server::user
  $group         = $postgresql::server::group
  $psql_path     = $postgresql::server::psql_path
  $version       = $postgresql::server::version

  # Set the defaults for the postgresql_psql resource
  Postgresql_psql {
    psql_user  => $user,
    psql_group => $group,
    psql_path  => $psql_path,
  }

  # Optionally set the locale switch. Older versions of createdb may not accept
  # --locale, so if the parameter is undefined its safer not to pass it.
  if ($version != '8.1') {
    $locale_option = $locale ? {
      undef   => '',
      default => "--locale=${locale} ",
    }
    $public_revoke_privilege = 'CONNECT'
  } else {
    $locale_option = ''
    $public_revoke_privilege = 'ALL'
  }

  $encoding_option = $encoding ? {
    undef   => '',
    default => "--encoding '${encoding}' ",
  }

  $tablespace_option = $tablespace ? {
    undef   => '',
    default => "--tablespace='${tablespace}' ",
  }

  $createdb_command = "${createdb_path} --owner='${owner}' --template=${template} ${encoding_option}${locale_option}${tablespace_option} '${dbname}'"

  postgresql_psql { "Check for existence of db '${dbname}'":
    command => 'SELECT 1',
    unless  => "SELECT datname FROM pg_database WHERE datname='${dbname}'",
    require => Class['postgresql::server::service']
  }~>
  exec { $createdb_command :
    refreshonly => true,
    user        => $user,
    logoutput   => on_failure,
  }~>

  # This will prevent users from connecting to the database unless they've been
  #  granted privileges.
  postgresql_psql {"REVOKE ${public_revoke_privilege} ON DATABASE \"${dbname}\" FROM public":
    db          => $user,
    refreshonly => true,
  }

  Exec [ $createdb_command ]->
  postgresql_psql {"UPDATE pg_database SET datistemplate = ${istemplate} WHERE datname = '${dbname}'":
    unless => "SELECT datname FROM pg_database WHERE datname = '${dbname}' AND datistemplate = ${istemplate}",
  }

  # Build up dependencies on tablespace
  if($tablespace != undef and defined(Postgresql::Server::Tablespace[$tablespace])) {
    Postgresql::Server::Tablespace[$tablespace]->Exec[$createdb_command]
  }
}
# Manage a database grant. See README.md for more details.
define postgresql::server::database_grant(
  $privilege,
  $db,
  $role,
  $psql_db   = undef,
  $psql_user = undef
) {
  postgresql::server::grant { "database:${name}":
    role        => $role,
    db          => $db,
    privilege   => $privilege,
    object_type => 'DATABASE',
    object_name => $db,
    psql_db     => $psql_db,
    psql_user   => $psql_user,
  }
}
# Define for conveniently creating a role, database and assigning the correct
# permissions. See README.md for more details.
define postgresql::server::db (
  $user,
  $password,
  $encoding   = $postgresql::server::encoding,
  $locale     = $postgresql::server::locale,
  $grant      = 'ALL',
  $tablespace = undef,
  $template   = 'template0',
  $istemplate = false,
  $owner      = undef
) {
  postgresql::server::database { $name:
    encoding   => $encoding,
    tablespace => $tablespace,
    template   => $template,
    locale     => $locale,
    istemplate => $istemplate,
    owner      => $owner,
  }

  if ! defined(Postgresql::Server::Role[$user]) {
    postgresql::server::role { $user:
      password_hash => $password,
    }
  }

  postgresql::server::database_grant { "GRANT ${user} - ${grant} - ${name}":
    privilege => $grant,
    db        => $name,
    role      => $user,
  }

  if($tablespace != undef and defined(Postgresql::Server::Tablespace[$tablespace])) {
    Postgresql::Server::Tablespace[$tablespace]->Postgresql::Server::Database[$name]
  }
}
# PRIVATE CLASS: do not use directly
class postgresql::server::firewall {
  $ensure             = $postgresql::server::ensure
  $manage_firewall    = $postgresql::server::manage_firewall
  $firewall_supported = $postgresql::server::firewall_supported

  if ($manage_firewall and $firewall_supported) {
    if ($ensure == 'present' or $ensure == true) {
      # TODO: get rid of hard-coded port
      firewall { '5432 accept - postgres':
        port   => '5432',
        proto  => 'tcp',
        action => 'accept',
      }
    } else {
      firewall { '5432 accept - postgres':
        ensure => absent,
      }
    }
  }
}
# Define for granting permissions to roles. See README.md for more details.
define postgresql::server::grant (
  $role,
  $db,
  $privilege   = undef,
  $object_type = 'database',
  $object_name = $db,
  $psql_db     = $postgresql::server::user,
  $psql_user   = $postgresql::server::user
) {
  $group     = $postgresql::server::group
  $psql_path = $postgresql::server::psql_path

  ## Munge the input values
  $_object_type = upcase($object_type)
  $_privilege   = upcase($privilege)

  ## Validate that the object type is known
  validate_string($_object_type,
    #'COLUMN',
    'DATABASE',
    #'FOREIGN SERVER',
    #'FOREIGN DATA WRAPPER',
    #'FUNCTION',
    #'PROCEDURAL LANGUAGE',
    #'SCHEMA',
    #'SEQUENCE',
    'TABLE',
    #'TABLESPACE',
    #'VIEW',
  )

  ## Validate that the object type's privilege is acceptable
  # TODO: this is a terrible hack; if they pass "ALL" as the desired privilege,
  #  we need a way to test for it--and has_database_privilege does not
  #  recognize 'ALL' as a valid privilege name. So we probably need to
  #  hard-code a mapping between 'ALL' and the list of actual privileges that
  #  it entails, and loop over them to check them.  That sort of thing will
  #  probably need to wait until we port this over to ruby, so, for now, we're
  #  just going to assume that if they have "CREATE" privileges on a database,
  #  then they have "ALL".  (I told you that it was terrible!)
  case $_object_type {
    'DATABASE': {
      $unless_privilege = $_privilege ? {
        'ALL'   => 'CREATE',
        default => $_privilege,
      }
      validate_string($unless_privilege,'CREATE','CONNECT','TEMPORARY','TEMP',
        'ALL','ALL PRIVILEGES')
      $unless_function = 'has_database_privilege'
      $on_db = $psql_db
    }
    'TABLE': {
      $unless_privilege = $_privilege ? {
        'ALL'   => 'INSERT',
        default => $_privilege,
      }
      validate_string($unless_privilege,'SELECT','INSERT','UPDATE','DELETE',
        'TRUNCATE','REFERENCES','TRIGGER','ALL','ALL PRIVILEGES')
      $unless_function = 'has_table_privilege'
      $on_db = $db
    }
    default: {
      fail("Missing privilege validation for object type ${_object_type}")
    }
  }

  $grant_cmd = "GRANT ${_privilege} ON ${_object_type} \"${object_name}\" TO \"${role}\""
  postgresql_psql { $grant_cmd:
    db         => $on_db,
    psql_user  => $psql_user,
    psql_group => $group,
    psql_path  => $psql_path,
    unless     => "SELECT 1 WHERE ${unless_function}('${role}', '${object_name}', '${unless_privilege}')",
    require    => Class['postgresql::server']
  }

  if($role != undef and defined(Postgresql::Server::Role[$role])) {
    Postgresql::Server::Role[$role]->Postgresql_psql[$grant_cmd]
  }

  if($db != undef and defined(Postgresql::Server::Database[$db])) {
    Postgresql::Server::Database[$db]->Postgresql_psql[$grant_cmd]
  }
}
# PRIVATE CLASS: do not call directly
class postgresql::server::initdb {
  $ensure       = $postgresql::server::ensure
  $needs_initdb = $postgresql::server::needs_initdb
  $initdb_path  = $postgresql::server::initdb_path
  $datadir      = $postgresql::server::datadir
  $xlogdir      = $postgresql::server::xlogdir
  $encoding     = $postgresql::server::encoding
  $locale       = $postgresql::server::locale
  $group        = $postgresql::server::group
  $user         = $postgresql::server::user

  if($ensure == 'present' or $ensure == true) {
    # Make sure the data directory exists, and has the correct permissions.
    file { $datadir:
      ensure => directory,
      owner  => $user,
      group  => $group,
      mode   => '0700',
    }

    if($xlogdir) {
      # Make sure the xlog directory exists, and has the correct permissions.
      file { $xlogdir:
        ensure => directory,
        owner  => $user,
        group  => $group,
        mode   => '0700',
      }
    }

    if($needs_initdb) {
      # Build up the initdb command.
      #
      # We optionally add the locale switch if specified. Older versions of the
      # initdb command don't accept this switch. So if the user didn't pass the
      # parameter, lets not pass the switch at all.
      $ic_base = "${initdb_path} --encoding '${encoding}' --pgdata '${datadir}'"
      $ic_xlog = $xlogdir ? {
        undef   => $ic_base,
        default => "${ic_base} --xlogdir '${xlogdir}'"
      }
      $initdb_command = $locale ? {
        undef   => $ic_xlog,
        default => "${ic_xlog} --locale '${locale}'"
      }

      # This runs the initdb command, we use the existance of the PG_VERSION
      # file to ensure we don't keep running this command.
      exec { 'postgresql_initdb':
        command   => $initdb_command,
        creates   => "${datadir}/PG_VERSION",
        user      => $user,
        group     => $group,
        logoutput => on_failure,
        require   => File[$datadir],
      }
    }
  } else {
    # Purge data directory if ensure => absent
    file { $datadir:
      ensure  => absent,
      recurse => true,
      force   => true,
    }

    if($xlogdir) {
      # Make sure the xlog directory exists, and has the correct permissions.
      file { $xlogdir:
        ensure  => absent,
        recurse => true,
        force   => true,
      }
    }
  }
}
# PRIVATE CLASS: do not call directly
class postgresql::server::install {
  $package_ensure      = $postgresql::server::package_ensure
  $package_name        = $postgresql::server::package_name
  $client_package_name = $postgresql::server::client_package_name

  # This is necessary to ensure that the extra client package that was
  # installed automatically by the server package is removed and all
  # of its dependencies are removed also. Without this later installation
  # of the native Ubuntu packages will fail.
  if($::operatingsystem == 'Ubuntu' and $package_ensure == 'absent') {
    # This is an exec, because we want to invoke autoremove.
    #
    # An alternative would be to have a full list of packages, but that seemed
    # more problematic to maintain, not to mention the conflict with the
    # client class will create duplicate resources.
    exec { 'apt-get-autoremove-postgresql-client-XX':
      command   => "apt-get autoremove --purge --yes ${client_package_name}",
      onlyif    => "dpkg -l ${client_package_name} | grep -e '^ii'",
      logoutput => on_failure,
      path      => '/usr/bin:/bin:/usr/sbin/:/sbin',
    }

    # This will clean up anything we miss
    exec { 'apt-get-autoremove-postgresql-client-brute':
      command   => "dpkg -P postgresql*",
      onlyif    => "dpkg -l postgresql* | grep -e '^ii'",
      logoutput => on_failure,
      path      => '/usr/bin:/bin:/usr/sbin/:/sbin',
    }
  }

  $_package_ensure = $package_ensure ? {
    true     => 'present',
    false    => 'purged',
    'absent' => 'purged',
    default => $package_ensure,
  }

  package { 'postgresql-server':
    ensure => $_package_ensure,
    name   => $package_name,

    # This is searched for to create relationships with the package repos, be
    # careful about its removal
    tag    => 'postgresql',
  }

}
# PRIVATE CLASS: do not call directly
class postgresql::server::passwd {
  $ensure            = $postgresql::server::ensure
  $postgres_password = $postgresql::server::postgres_password
  $user              = $postgresql::server::user
  $group             = $postgresql::server::group
  $psql_path         = $postgresql::server::psql_path

  if($ensure == 'present' or $ensure == true) {
    if ($postgres_password != undef) {
      # NOTE: this password-setting logic relies on the pg_hba.conf being
      #  configured to allow the postgres system user to connect via psql
      #  without specifying a password ('ident' or 'trust' security). This is
      #  the default for pg_hba.conf.
      $escaped = postgresql_escape($postgres_password)
      $env = "env PGPASSWORD='${postgres_password}'"
      exec { 'set_postgres_postgrespw':
        # This command works w/no password because we run it as postgres system
        # user
        command     => "${psql_path} -c 'ALTER ROLE \"${user}\" PASSWORD ${escaped}'",
        user        => $user,
        group       => $group,
        logoutput   => true,
        cwd         => '/tmp',
        # With this command we're passing -h to force TCP authentication, which
        # does require a password.  We specify the password via the PGPASSWORD
        # environment variable. If the password is correct (current), this
        # command will exit with an exit code of 0, which will prevent the main
        # command from running.
        unless      => "${env} ${psql_path} -h localhost -c 'select 1' > /dev/null",
        path        => '/usr/bin:/usr/local/bin:/bin',
      }
    }
  }
}
# This resource manages an individual rule that applies to the file defined in
# $target. See README.md for more details.
define postgresql::server::pg_hba_rule(
  $type,
  $database,
  $user,
  $auth_method,
  $address     = undef,
  $description = 'none',
  $auth_option = undef,
  $order       = '150',

  # Needed for testing primarily, support for multiple files is not really
  # working.
  $target      = $postgresql::server::pg_hba_conf_path
) {

  if $postgresql::server::manage_pg_hba_conf == false {
      fail('postgresql::server::manage_pg_hba_conf has been disabled, so this resource is now unused and redundant, either enable that option or remove this resource from your manifests')
  } else {
    validate_re($type, '^(local|host|hostssl|hostnossl)$',
    "The type you specified [${type}] must be one of: local, host, hostssl, hostnosssl")

    if($type =~ /^host/ and $address == undef) {
      fail('You must specify an address property when type is host based')
    }

    $allowed_auth_methods = $postgresql::server::version ? {
      '9.3' => ['trust', 'reject', 'md5', 'sha1', 'password', 'gss', 'sspi', 'krb5', 'ident', 'peer', 'ldap', 'radius', 'cert', 'pam'],
      '9.2' => ['trust', 'reject', 'md5', 'sha1', 'password', 'gss', 'sspi', 'krb5', 'ident', 'peer', 'ldap', 'radius', 'cert', 'pam'],
      '9.1' => ['trust', 'reject', 'md5', 'sha1', 'password', 'gss', 'sspi', 'krb5', 'ident', 'peer', 'ldap', 'radius', 'cert', 'pam'],
      '9.0' => ['trust', 'reject', 'md5', 'sha1', 'password', 'gss', 'sspi', 'krb5', 'ident', 'ldap', 'radius', 'cert', 'pam'],
      '8.4' => ['trust', 'reject', 'md5', 'sha1', 'password', 'gss', 'sspi', 'krb5', 'ident', 'ldap', 'cert', 'pam'],
      '8.3' => ['trust', 'reject', 'md5', 'sha1', 'crypt', 'password', 'gss', 'sspi', 'krb5', 'ident', 'ldap', 'pam'],
      '8.2' => ['trust', 'reject', 'md5', 'crypt', 'password', 'krb5', 'ident', 'ldap', 'pam'],
      '8.1' => ['trust', 'reject', 'md5', 'crypt', 'password', 'krb5', 'ident', 'pam'],
      default => ['trust', 'reject', 'md5', 'password', 'gss', 'sspi', 'krb5', 'ident', 'peer', 'ldap', 'radius', 'cert', 'pam', 'crypt']
    }

    $auth_method_regex = join(['^(', join($allowed_auth_methods, '|'), ')$'],'')
    validate_re($auth_method, $auth_method_regex,
    join(["The auth_method you specified [${auth_method}] must be one of: ", join($allowed_auth_methods, ', ')],''))

    # Create a rule fragment
    $fragname = "pg_hba_rule_${name}"
    concat::fragment { $fragname:
      target  => $target,
      content => template('postgresql/pg_hba_rule.conf'),
      order   => $order,
    }
  }
}
# This class installs the PL/Perl procedural language for postgresql. See
# README.md for more details.
class postgresql::server::plperl(
  $package_ensure = 'present',
  $package_name   = $postgresql::server::plperl_package_name
) {
  package { 'postgresql-plperl':
    ensure => $package_ensure,
    name   => $package_name,
    tag    => 'postgresql',
  }

  if($package_ensure == 'present' or $package_ensure == true) {
    anchor { 'postgresql::server::plperl::start': }->
    Class['postgresql::server::install']->
    Package['postgresql-plperl']->
    Class['postgresql::server::service']->
    anchor { 'postgresql::server::plperl::end': }
  } else {
    anchor { 'postgresql::server::plperl::start': }->
    Class['postgresql::server::service']->
    Package['postgresql-plperl']->
    Class['postgresql::server::install']->
    anchor { 'postgresql::server::plperl::end': }
  }

}
# PRIVATE CLASS: do not use directly
class postgresql::server::reload {
  $ensure         = $postgresql::server::ensure
  $service_name   = $postgresql::server::service_name
  $service_status = $postgresql::server::service_status

  if($ensure == 'present' or $ensure == true) {
    exec { 'postgresql_reload':
      path        => '/usr/bin:/usr/sbin:/bin:/sbin',
      command     => "service ${service_name} reload",
      onlyif      => $service_status,
      refreshonly => true,
    }
  }
}
# Define for creating a database role. See README.md for more information
define postgresql::server::role(
  $password_hash    = false,
  $createdb         = false,
  $createrole       = false,
  $db               = $postgresql::server::user,
  $login            = true,
  $superuser        = false,
  $replication      = false,
  $connection_limit = '-1',
  $username         = $title
) {
  $psql_user  = $postgresql::server::user
  $psql_group = $postgresql::server::group
  $psql_path  = $postgresql::server::psql_path
  $version    = $postgresql::server::version

  $login_sql       = $login       ? { true => 'LOGIN',       default => 'NOLOGIN' }
  $createrole_sql  = $createrole  ? { true => 'CREATEROLE',  default => 'NOCREATEROLE' }
  $createdb_sql    = $createdb    ? { true => 'CREATEDB',    default => 'NOCREATEDB' }
  $superuser_sql   = $superuser   ? { true => 'SUPERUSER',   default => 'NOSUPERUSER' }
  $replication_sql = $replication ? { true => 'REPLICATION', default => '' }
  if ($password_hash != false) {
    $password_sql = "ENCRYPTED PASSWORD '${password_hash}'"
  } else {
    $password_sql = ''
  }

  Postgresql_psql {
    db         => $db,
    psql_user  => $psql_user,
    psql_group => $psql_group,
    psql_path  => $psql_path,
    require    => [ Postgresql_psql["CREATE ROLE \"${username}\" ${password_sql} ${login_sql} ${createrole_sql} ${createdb_sql} ${superuser_sql} ${replication_sql} CONNECTION LIMIT ${connection_limit}"], Class['postgresql::server'] ],
  }

  postgresql_psql {"CREATE ROLE \"${username}\" ${password_sql} ${login_sql} ${createrole_sql} ${createdb_sql} ${superuser_sql} ${replication_sql} CONNECTION LIMIT ${connection_limit}":
    unless  => "SELECT rolname FROM pg_roles WHERE rolname='${username}'",
    require => Class['Postgresql::Server'],
  }

  postgresql_psql {"ALTER ROLE \"${username}\" ${superuser_sql}":
    unless => "SELECT rolname FROM pg_roles WHERE rolname='${username}' and rolsuper=${superuser}",
  }

  postgresql_psql {"ALTER ROLE \"${username}\" ${createdb_sql}":
    unless => "SELECT rolname FROM pg_roles WHERE rolname='${username}' and rolcreatedb=${createdb}",
  }

  postgresql_psql {"ALTER ROLE \"${username}\" ${createrole_sql}":
    unless => "SELECT rolname FROM pg_roles WHERE rolname='${username}' and rolcreaterole=${createrole}",
  }

  postgresql_psql {"ALTER ROLE \"${username}\" ${login_sql}":
    unless => "SELECT rolname FROM pg_roles WHERE rolname='${username}' and rolcanlogin=${login}",
  }

  if(versioncmp($version, '9.1') >= 0) {
    if $replication_sql == '' {
      postgresql_psql {"ALTER ROLE \"${username}\" NOREPLICATION":
        unless => "SELECT rolname FROM pg_roles WHERE rolname='${username}' and rolreplication=${replication}",
      }
    } else {
      postgresql_psql {"ALTER ROLE \"${username}\" ${replication_sql}":
        unless => "SELECT rolname FROM pg_roles WHERE rolname='${username}' and rolreplication=${replication}",
      }
    }
  }

  postgresql_psql {"ALTER ROLE \"${username}\" CONNECTION LIMIT ${connection_limit}":
    unless => "SELECT rolname FROM pg_roles WHERE rolname='${username}' and rolconnlimit=${connection_limit}",
  }

  if $password_hash {
    if($password_hash =~ /^md5.+/) {
      $pwd_hash_sql = $password_hash
    } else {
      $pwd_md5 = md5("${password_hash}${username}")
      $pwd_hash_sql = "md5${pwd_md5}"
    }
    postgresql_psql {"ALTER ROLE \"${username}\" ${password_sql}":
      unless => "SELECT usename FROM pg_shadow WHERE usename='${username}' and passwd='${pwd_hash_sql}'",
    }
  }
}
# PRIVATE CLASS: do not call directly
class postgresql::server::service {
  $ensure           = $postgresql::server::ensure
  $service_name     = $postgresql::server::service_name
  $service_provider = $postgresql::server::service_provider
  $service_status   = $postgresql::server::service_status
  $user             = $postgresql::server::user
  $default_database = $postgresql::server::default_database

  $service_ensure = $ensure ? {
    present => true,
    absent  => false,
    default => $ensure
  }

  anchor { 'postgresql::server::service::begin': }

  service { 'postgresqld':
    ensure    => $service_ensure,
    name      => $service_name,
    enable    => $service_ensure,
    provider  => $service_provider,
    hasstatus => true,
    status    => $service_status,
  }

  if($service_ensure) {
    # This blocks the class before continuing if chained correctly, making
    # sure the service really is 'up' before continuing.
    #
    # Without it, we may continue doing more work before the database is
    # prepared leading to a nasty race condition.
    postgresql::validate_db_connection { 'validate_service_is_running':
      run_as          => $user,
      database_name   => $default_database,
      sleep           => 1,
      tries           => 60,
      create_db_first => false,
      require         => Service['postgresqld'],
      before          => Anchor['postgresql::server::service::end']
    }
  }

  anchor { 'postgresql::server::service::end': }
}
# This resource wraps the grant resource to manage table grants specifically.
# See README.md for more details.
define postgresql::server::table_grant(
  $privilege,
  $table,
  $db,
  $role,
  $psql_db   = undef,
  $psql_user = undef
) {
  postgresql::server::grant { "table:${name}":
    role        => $role,
    db          => $db,
    privilege   => $privilege,
    object_type => 'TABLE',
    object_name => $table,
    psql_db     => $psql_db,
    psql_user   => $psql_user,
  }
}
# This module creates tablespace. See README.md for more details.
define postgresql::server::tablespace(
  $location,
  $owner   = undef,
  $spcname = $title
) {
  $user      = $postgresql::server::user
  $group     = $postgresql::server::group
  $psql_path = $postgresql::server::psql_path

  Postgresql_psql {
    psql_user  => $user,
    psql_group => $group,
    psql_path  => $psql_path,
  }

  if ($owner == undef) {
    $owner_section = ''
  } else {
    $owner_section = "OWNER \"${owner}\""
  }

  $create_tablespace_command = "CREATE TABLESPACE \"${spcname}\" ${owner_section} LOCATION '${location}'"

  file { $location:
    ensure => directory,
    owner  => $user,
    group  => $group,
    mode   => '0700',
  }

  $create_ts = "Create tablespace '${spcname}'"
  postgresql_psql { "Create tablespace '${spcname}'":
    command => $create_tablespace_command,
    unless  => "SELECT spcname FROM pg_tablespace WHERE spcname='${spcname}'",
    require => [Class['postgresql::server'], File[$location]],
  }

  if($owner != undef and defined(Postgresql::Server::Role[$owner])) {
    Postgresql::Server::Role[$owner]->Postgresql_psql[$create_ts]
  }
}
# This type validates that a successful postgres connection can be established
# between the node on which this resource is run and a specified postgres
# instance (host/port/user/password/database name).
#
# See README.md for more details.
define postgresql::validate_db_connection(
  $database_host     = undef,
  $database_name     = undef,
  $database_password = undef,
  $database_username = undef,
  $database_port     = undef,
  $run_as            = undef,
  $sleep             = 2,
  $tries             = 10,
  $create_db_first   = true
) {
  require postgresql::client
  include postgresql::params

  $psql_path = $postgresql::params::psql_path

  $cmd_init = "${psql_path} --tuples-only --quiet "
  $cmd_host = $database_host ? {
    default => "-h ${database_host} ",
    undef   => "",
  }
  $cmd_user = $database_username ? {
    default => "-U ${database_username} ",
    undef   => "",
  }
  $cmd_port = $database_port ? {
    default => "-p ${database_port} ",
    undef   => "",
  }
  $cmd_dbname = $database_name ? {
    default => "--dbname ${database_name} ",
    undef   => "--dbname ${postgresql::params::default_database} ",
  }
  $env = $database_password ? {
    default => "PGPASSWORD=${database_password}",
    undef   => undef,
  }
  $cmd = join([$cmd_init, $cmd_host, $cmd_user, $cmd_port, $cmd_dbname])
  $validate_cmd = "/usr/local/bin/validate_postgresql_connection.sh ${sleep} ${tries} '${cmd}'"

  # This is more of a safety valve, we add a little extra to compensate for the
  # time it takes to run each psql command.
  $timeout = (($sleep + 2) * $tries)

  $exec_name = "validate postgres connection for ${database_host}/${database_name}"
  exec { $exec_name:
    command     => "echo 'Unable to connect to defined database using: ${cmd}' && false",
    unless      => $validate_cmd,
    cwd         => '/tmp',
    environment => $env,
    logoutput   => 'on_failure',
    user        => $run_as,
    path        => '/bin',
    timeout     => $timeout,
    require     => Package['postgresql-client'],
  }

  # This is a little bit of puppet magic.  What we want to do here is make
  # sure that if the validation and the database instance creation are being
  # applied on the same machine, then the database resource is applied *before*
  # the validation resource.  Otherwise, the validation is guaranteed to fail
  # on the first run.
  #
  # We accomplish this by using Puppet's resource collection syntax to search
  # for the Database resource in our current catalog; if it exists, the
  # appropriate relationship is created here.
  if($create_db_first) {
    Postgresql::Server::Database<|title == $database_name|> -> Exec[$exec_name]
  }
}
{
  "operatingsystem_support": [
    {
      "operatingsystem": "RedHat",
      "operatingsystemrelease": [
        "5",
        "6"
      ]
    },
    {
      "operatingsystem": "CentOS",
      "operatingsystemrelease": [
        "5",
        "6"
      ]
    },
    {
      "operatingsystem": "OracleLinux",
      "operatingsystemrelease": [
        "5",
        "6"
      ]
    },
    {
      "operatingsystem": "Scientific",
      "operatingsystemrelease": [
        "5",
        "6"
      ]
    },
    {
      "operatingsystem": "Debian",
      "operatingsystemrelease": [
        "6",
        "7"
      ]
    },
    {
      "operatingsystem": "Ubuntu",
      "operatingsystemrelease": [
        "10.04",
        "12.04"
      ]
    }
  ],
  "requirements": [
    {
      "name": "pe",
      "version_requirement": "3.2.x"
    },
    {
      "name": "puppet",
      "version_requirement": "3.x"
    }
  ],
  "name": "puppetlabs-postgresql",
  "version": "3.3.3",
  "source": "git://github.com/puppetlabs/puppet-postgresql.git",
  "author": "Inkling/Puppet Labs",
  "license": "ASL 2.0",
  "summary": "PostgreSQL defined resource types",
  "description": "PostgreSQL defined resource types",
  "project_page": "https://github.com/puppetlabs/puppet-postgresql",
  "dependencies": [
    {
      "name": "puppetlabs/stdlib",
      "version_requirement": ">=3.2.0 <5.0.0"
    },
    {
      "name": "puppetlabs/firewall",
      "version_requirement": ">= 0.0.4"
    },
    {
      "name": "puppetlabs/apt",
      "version_requirement": ">=1.1.0 <2.0.0"
    },
    {
      "name": "puppetlabs/concat",
      "version_requirement": ">= 1.0.0 <2.0.0"
    }
  ]
}
require 'spec_helper_acceptance'

describe 'postgresql::client:', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
  after :all do
    # Cleanup after tests have ran
    apply_manifest("class { 'postgresql::client': package_ensure => purged }",
                   :catch_failures => true)
  end

  it 'test loading class with no parameters' do
    pp = <<-EOS.unindent
      class { 'postgresql::client': }
    EOS

    apply_manifest(pp, :catch_failures => true)
    apply_manifest(pp, :catch_changes => true)
  end
end
require 'spec_helper_acceptance'

describe 'common patterns:', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
  describe 'postgresql.conf include pattern' do
    after :all do
      pp = <<-EOS.unindent
        class { 'postgresql::server': ensure => absent }

        file { '/tmp/include.conf':
          ensure => absent
        }
      EOS
      apply_manifest(pp, :catch_failures => true)
    end

    it "should support an 'include' directive at the end of postgresql.conf" do
      pending('no support for include directive with centos 5/postgresql 8.1',
        :if => (fact('osfamily') == 'RedHat' and fact('lsbmajdistrelease') == '5'))

      pp = <<-EOS.unindent
        class { 'postgresql::server': }

        $extras = "/etc/postgresql-include.conf"

        file { $extras:
          content => 'max_connections = 123',
          seltype => 'postgresql_db_t',
          seluser => 'system_u',
          notify  => Class['postgresql::server::service'],
        }

        postgresql::server::config_entry { 'include':
          value   => $extras,
          require => File[$extras],
        }
      EOS

      apply_manifest(pp, :catch_failures => true)
      apply_manifest(pp, :catch_changes => true)

      psql('--command="show max_connections" -t', 'postgres') do |r|
        expect(r.stdout).to match(/123/)
        expect(r.stderr).to eq('')
      end
    end
  end
end
require 'spec_helper_acceptance'

describe 'postgresql::server::contrib:', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
  after :all do
    # Cleanup after tests have ran, remove both contrib and server as contrib
    # pulls in the server based packages.
    pp = <<-EOS.unindent
      class { 'postgresql::server':
        ensure => absent,
      }
      class { 'postgresql::server::contrib':
        package_ensure => purged,
      }
    EOS

    apply_manifest(pp, :catch_failures => true)
  end

  it 'test loading class with no parameters' do
    pp = <<-EOS.unindent
      class { 'postgresql::server': }
      class { 'postgresql::server::contrib': }
    EOS

    apply_manifest(pp, :catch_failures => true)
    apply_manifest(pp, :catch_changes => true)
  end
end
require 'spec_helper_acceptance'

describe 'postgresql::lib::devel:', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
  after :all do
    # Cleanup after tests have ran
    apply_manifest("class { 'postgresql::lib::devel': package_ensure => purged }", :catch_failures => true)
  end

  it 'test loading class with no parameters' do
    pp = <<-EOS.unindent
      class { 'postgresql::lib::devel': }
    EOS

    apply_manifest(pp, :catch_failures => true)
    apply_manifest(pp, :catch_changes => true)
  end
end
require 'spec_helper_acceptance'

describe 'postgresql::lib::java:', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
  after :all do
    # Cleanup after tests have ran
    apply_manifest("class { 'postgresql::lib::java': package_ensure => purged }", :catch_failures => true)
  end

  it 'test loading class with no parameters' do
    pending('libpostgresql-java-jdbc not available natively for Ubuntu 10.04 and Debian 6',
      :if => (fact('osfamily') == 'Debian' and ['6', '10'].include?(fact('lsbmajdistrelease'))))

    pp = <<-EOS.unindent
      class { 'postgresql::lib::java': }
    EOS

    apply_manifest(pp, :catch_failures => true)
    apply_manifest(pp, :catch_changes => true)
  end
end
require 'spec_helper_acceptance'

describe 'postgresql::lib::python:', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
  after :all do
    # Cleanup after tests have ran
    apply_manifest("class { 'postgresql::lib::python': package_ensure => purged }", :catch_failures => true)
  end

  it 'test loading class with no parameters' do
    pending('psycopg2 not available natively for centos 5', :if => (fact('osfamily') == 'RedHat' and fact('lsbmajdistrelease') == '5'))

    pp = <<-EOS.unindent
      class { 'postgresql::lib::python': }
    EOS

    apply_manifest(pp, :catch_failures => true)
    apply_manifest(pp, :catch_changes => true)
  end
end
HOSTS:
  centos-510-x64:
    roles:
      - master
    platform: el-5-x86_64
    box : centos-510-x64-virtualbox-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-510-x64-virtualbox-nocm.box
    hypervisor : vagrant
CONFIG:
  type: git
HOSTS:
  centos-59-x64:
    roles:
      - master
    platform: el-5-x86_64
    box : centos-59-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-59-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: git
HOSTS:
  centos-64-x64:
    roles:
      - master
      - database
      - dashboard
    platform: el-6-x86_64
    box : centos-64-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: pe
HOSTS:
  centos-64-x64:
    roles:
      - master
    platform: el-6-x86_64
    box : centos-64-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: git
HOSTS:
  debian-607-x64:
    roles:
      - master
    platform: debian-6-amd64
    box : debian-607-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/debian-607-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: git
HOSTS:
  debian-73-x64:
    roles:
      - master
    platform: debian-7-amd64
    box : debian-73-x64-virtualbox-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/debian-73-x64-virtualbox-nocm.box
    hypervisor : vagrant
CONFIG:
  type: git
HOSTS:
  centos-64-x64:
    roles:
      - master
    platform: el-6-x86_64
    box : centos-64-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: git
HOSTS:
  ubuntu-server-10044-x64:
    roles:
      - master
    platform: ubuntu-10.04-amd64
    box : ubuntu-server-10044-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/ubuntu-server-10044-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: git
HOSTS:
  ubuntu-server-12042-x64:
    roles:
      - master
    platform: ubuntu-12.04-amd64
    box : ubuntu-server-12042-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/ubuntu-server-12042-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: git
require 'spec_helper_acceptance'

describe 'postgresql_psql:', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
  after :all do
    # Cleanup after tests have ran
    apply_manifest("class { 'postgresql::server': ensure => absent }", :catch_failures => true)
  end

  it 'should run some SQL when the unless query returns no rows' do
    pp = <<-EOS.unindent
      class { 'postgresql::server': }

      postgresql_psql { 'foobar':
        db        => 'postgres',
        psql_user => 'postgres',
        command   => 'select 1',
        unless    => 'select 1 where 1=2',
        require   => Class['postgresql::server'],
      }
    EOS

    apply_manifest(pp, :catch_failures => true)
    apply_manifest(pp, :catch_failures => true)
  end

  it 'should not run SQL when the unless query returns rows' do
    pp = <<-EOS.unindent
      class { 'postgresql::server': }

      postgresql_psql { 'foobar':
        db        => 'postgres',
        psql_user => 'postgres',
        command   => 'select * from pg_database limit 1',
        unless    => 'select 1 where 1=1',
        require   => Class['postgresql::server'],
      }
    EOS

    apply_manifest(pp, :catch_failures => true)
    apply_manifest(pp, :catch_changes => true)
  end

end
require 'spec_helper_acceptance'

describe 'postgresql::server::config_entry:', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
  after :all do
    # Cleanup after tests have ran
    apply_manifest("class { 'postgresql::server': ensure => absent }", :catch_failures => true)
  end

  it 'should change setting and reflect it in show all' do
    pp = <<-EOS.unindent
      class { 'postgresql::server': }

      postgresql::server::config_entry { 'check_function_bodies':
        value => 'off',
      }
    EOS

    apply_manifest(pp, :catch_failures => true)
    apply_manifest(pp, :catch_changes => true)

    psql('--command="show all" postgres') do |r|
      expect(r.stdout).to match(/check_function_bodies.+off/)
      expect(r.stderr).to eq('')
    end
  end
end
require 'spec_helper_acceptance'

describe 'postgresql::server::database_grant:', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
  after :all do
    # Cleanup after tests have ran
    apply_manifest("class { 'postgresql::server': ensure => absent }", :catch_failures => true)
  end

  it 'should grant access so a user can create objects in a database' do
    begin
      pp = <<-EOS.unindent
        $db = 'postgres'
        $user = 'psql_grant_tester'
        $password = 'psql_grant_pw'

        class { 'postgresql::server': }

        # Since we are not testing pg_hba or any of that, make a local user for ident auth
        user { $user:
          ensure => present,
        }

        postgresql::server::role { $user:
          password_hash => postgresql_password($user, $password),
        }

        postgresql::server::database { $db: }

        postgresql::server::database_grant { 'grant create test':
          privilege => 'CREATE',
          db        => $db,
          role      => $user,
        }
      EOS

      apply_manifest(pp, :catch_failures => true)
      apply_manifest(pp, :catch_changes => true)

      # Check that the user can create a table in the database
      psql('--command="create table foo (foo int)" postgres', 'psql_grant_tester') do |r|
        expect(r.stdout).to match(/CREATE TABLE/)
        expect(r.stderr).to eq('')
      end
    ensure
      psql('--command="drop table foo" postgres', 'psql_grant_tester')
    end
  end
end
require 'spec_helper_acceptance'

describe 'postgresql::server::database:', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
  after :all do
    # Cleanup after tests have ran
    apply_manifest("class { 'postgresql::server': ensure => absent }", :catch_failures => true)
  end

  it 'should idempotently create a db that we can connect to' do
    begin
      pp = <<-EOS.unindent
        $db = 'postgresql_test_db'
        class { 'postgresql::server': }

        postgresql::server::database { $db: }
      EOS

      apply_manifest(pp, :catch_failures => true)
      apply_manifest(pp, :catch_changes => true)

      psql('--command="select datname from pg_database" postgresql_test_db') do |r|
        expect(r.stdout).to match(/postgresql_test_db/)
        expect(r.stderr).to eq('')
      end
    ensure
      psql('--command="drop database postgresql_test_db" postgres')
    end
  end
end
require 'spec_helper_acceptance'

describe 'postgresql::server::db', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
  after :all do
    # Cleanup after tests have ran
    apply_manifest("class { 'postgresql::server': ensure => absent }", :catch_failures => true)
  end

  it 'should idempotently create a db that we can connect to' do
    begin
      pp = <<-EOS.unindent
        $db = 'postgresql_test_db'
        class { 'postgresql::server': }

        postgresql::server::db { $db:
          user     => $db,
          password => postgresql_password($db, $db),
        }
      EOS

      apply_manifest(pp, :catch_failures => true)
      apply_manifest(pp, :catch_changes => true)

      psql('--command="select datname from pg_database" postgresql_test_db') do |r|
        expect(r.stdout).to match(/postgresql_test_db/)
        expect(r.stderr).to eq('')
      end
    ensure
      psql('--command="drop database postgresql_test_db" postgres')
    end
  end

  it 'should take a locale parameter' do
    pending('no support for locale parameter with centos 5', :if => (fact('osfamily') == 'RedHat' and fact('lsbmajdistrelease') == '5'))
    begin
      pp = <<-EOS.unindent
        class { 'postgresql::server': }
        postgresql::server::db { 'test1':
          user     => 'test1',
          password => postgresql_password('test1', 'test1'),
          encoding => 'UTF8',
          locale   => 'en_NG.UTF-8',
        }
      EOS

      apply_manifest(pp, :catch_failures => true)
      apply_manifest(pp, :catch_changes => true)

      psql('-c "show lc_ctype" test1') do |r|
        expect(r.stdout).to match(/en_NG/)
      end

      psql('-c "show lc_collate" test1') do |r|
        expect(r.stdout).to match(/en_NG/)
      end
    ensure
      psql('--command="drop database test1" postgres')
    end
  end

  it 'should take an istemplate parameter' do
    begin
      pp = <<-EOS.unindent
        $db = 'template2'
        class { 'postgresql::server': }

        postgresql::server::db { $db:
          user       => $db,
          password   => postgresql_password($db, $db),
          istemplate => true,
        }
      EOS

      apply_manifest(pp, :catch_failures => true)
      apply_manifest(pp, :catch_changes => true)

      psql('--command="select datname from pg_database" template2') do |r|
        expect(r.stdout).to match(/template2/)
        expect(r.stderr).to eq('')
      end
    ensure
      psql('--command="drop database template2" postgres', 'postgres', [1,2]) do |r|
        expect(r.stdout).to eq('')
        expect(r.stderr).to match(/cannot drop a template database/)
      end
    end
  end

  it 'should update istemplate parameter' do
    begin
      pp = <<-EOS.unindent
        $db = 'template2'
        class { 'postgresql::server': }

        postgresql::server::db { $db:
          user       => $db,
          password   => postgresql_password($db, $db),
          istemplate => false,
        }
      EOS

      apply_manifest(pp, :catch_failures => true)
      apply_manifest(pp, :catch_changes => true)

      psql('--command="select datname from pg_database" template2') do |r|
        expect(r.stdout).to match(/template2/)
        expect(r.stderr).to eq('')
      end
    ensure
      psql('--command="drop database template2" postgres')
    end
  end

  it 'should take a template parameter' do
    begin
      pp = <<-EOS.unindent
        $db = 'postgresql_test_db'
        class { 'postgresql::server': }

        postgresql::server::db { $db:
          user       => $db,
          template   => 'template1',
          password   => postgresql_password($db, $db),
        }
      EOS

      apply_manifest(pp, :catch_failures => true)
      apply_manifest(pp, :catch_changes => true)

      psql('--command="select datname from pg_database" postgresql_test_db') do |r|
        expect(r.stdout).to match(/postgresql_test_db/)
        expect(r.stderr).to eq('')
      end
    ensure
      psql('--command="drop database postgresql_test_db" postgres')
    end
  end
end
require 'spec_helper_acceptance'

describe 'postgresql::server::grant:', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
  after :all do
    # Cleanup after tests have ran
    apply_manifest("class { 'postgresql::server': ensure => absent }", :catch_failures => true)
  end

  it 'should grant access so a user can create in a database' do
    begin
      pp = <<-EOS.unindent
        $db = 'postgres'
        $user = 'psql_grant_tester'
        $password = 'psql_grant_pw'

        class { 'postgresql::server': }

        # Since we are not testing pg_hba or any of that, make a local user for ident auth
        user { $user:
          ensure => present,
        }

        postgresql::server::role { $user:
          password_hash => postgresql_password($user, $password),
        }

        postgresql::server::database { $db: }

        postgresql::server::grant { 'grant create test':
          object_type => 'database',
          privilege   => 'CREATE',
          db          => $db,
          role        => $user,
        }
      EOS

      apply_manifest(pp, :catch_failures => true)
      apply_manifest(pp, :catch_changes => true)

      # Check that the user can create a table in the database
      psql('--command="create table foo (foo int)" postgres', 'psql_grant_tester') do |r|
        expect(r.stdout).to match(/CREATE TABLE/)
        expect(r.stderr).to eq('')
      end
    ensure
      psql('--command="drop table foo" postgres', 'psql_grant_tester')
    end
  end
end
require 'spec_helper_acceptance'

describe 'postgresql::server::pg_hba_rule:', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
  after :all do
    # Cleanup after tests have ran
    apply_manifest("class { 'postgresql::server': ensure => absent }", :catch_failures => true)
  end

  it 'should create a ruleset in pg_hba.conf' do
    pp = <<-EOS.unindent
      class { 'postgresql::server': }
      postgresql::server::pg_hba_rule { "allow application network to access app database":
        type        => "host",
        database    => "app",
        user        => "app",
        address     => "200.1.2.0/24",
        auth_method => md5,
      }
    EOS

    apply_manifest(pp, :catch_failures => true)
    apply_manifest(pp, :catch_failures => true)

    shell("grep '200.1.2.0/24' /etc/postgresql/*/*/pg_hba.conf || grep '200.1.2.0/24' /var/lib/pgsql/data/pg_hba.conf")
  end

  it 'should create a ruleset in pg_hba.conf that denies db access to db test1' do
    pp = <<-EOS.unindent
      class { 'postgresql::server': }

      postgresql::server::db { "test1":
        user     => "test1",
        password => postgresql_password('test1', 'test1'),
        grant    => "all",
      }

      postgresql::server::pg_hba_rule { "allow anyone to have access to db test1":
        type        => "local",
        database    => "test1",
        user        => "test1",
        auth_method => reject,
        order       => '001',
      }

      user { "test1":
        shell      => "/bin/bash",
        managehome => true,
      }
    EOS

    apply_manifest(pp, :catch_failures => true)

    shell('su - test1 -c \'psql -U test1 -c "\q" test1\'', :acceptable_exit_codes => [2])
  end

  it 'should fail catalogue if postgresql::server::manage_pga_conf is disabled' do
    pp = <<-EOS.unindent
      class { 'postgresql::server':
        manage_pg_hba_conf => false,
      }
      postgresql::server::pg_hba_rule { 'foo':
        type        => "local",
        database    => "test1",
        user        => "test1",
        auth_method => reject,
        order       => '001',
      }
    EOS

    apply_manifest(pp, :expect_failures => true)
  end
end
require 'spec_helper_acceptance'

describe 'server plperl:', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
  after :all do
    # Cleanup after tests have ran
    pp = <<-EOS.unindent
      class { 'postgresql::server': ensure => absent }
      class { 'postgresql::server::plperl': package_ensure => purged }
    EOS

    apply_manifest(pp, :catch_failures => true)
  end

  it 'test loading class with no parameters' do
    pending('no support for plperl with default version on centos 5',
      :if => (fact('osfamily') == 'RedHat' and fact('lsbmajdistrelease') == '5'))
    pp = <<-EOS.unindent
      class { 'postgresql::server': }
      class { 'postgresql::server::plperl': }
    EOS

    apply_manifest(pp, :catch_failures => true)
    apply_manifest(pp, :catch_changes => true)
  end
end
require 'spec_helper_acceptance'

describe 'postgresql::server::role:', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
  after :all do
    # Cleanup after tests have ran
    apply_manifest("class { 'postgresql::server': ensure => absent }", :catch_failures => true)
  end

  it 'should idempotently create a user who can log in' do
    pp = <<-EOS.unindent
      $user = "postgresql_test_user"
      $password = "postgresql_test_password"

      class { 'postgresql::server': }

      # Since we are not testing pg_hba or any of that, make a local user for ident auth
      user { $user:
        ensure => present,
      }

      postgresql::server::role { $user:
        password_hash => postgresql_password($user, $password),
      }
    EOS

    apply_manifest(pp, :catch_failures => true)

    # Check that the user can log in
    psql('--command="select datname from pg_database" postgres', 'postgresql_test_user') do |r|
      expect(r.stdout).to match(/template1/)
      expect(r.stderr).to eq('')
    end
  end

  it 'should idempotently alter a user who can log in' do
    pp = <<-EOS.unindent
      $user = "postgresql_test_user"
      $password = "postgresql_test_password2"

      class { 'postgresql::server': }

      # Since we are not testing pg_hba or any of that, make a local user for ident auth
      user { $user:
        ensure => present,
      }

      postgresql::server::role { $user:
        password_hash => postgresql_password($user, $password),
      }
    EOS

    apply_manifest(pp, :catch_failures => true)
    apply_manifest(pp, :catch_changes => true)

    # Check that the user can log in
    psql('--command="select datname from pg_database" postgres', 'postgresql_test_user') do |r|
      expect(r.stdout).to match(/template1/)
      expect(r.stderr).to eq('')
    end
  end

  it 'should idempotently create a user with a cleartext password' do
    pp = <<-EOS.unindent
      $user = "postgresql_test_user2"
      $password = "postgresql_test_password2"

      class { 'postgresql::server': }

      # Since we are not testing pg_hba or any of that, make a local user for ident auth
      user { $user:
        ensure => present,
      }

      postgresql::server::role { $user:
        password_hash => $password,
      }
    EOS

    apply_manifest(pp, :catch_failures => true)
    apply_manifest(pp, :catch_changes => true)

    # Check that the user can log in
    psql('--command="select datname from pg_database" postgres', 'postgresql_test_user2') do |r|
      expect(r.stdout).to match(/template1/)
      expect(r.stderr).to eq('')
    end
  end
end
require 'spec_helper_acceptance'

describe 'postgresql::server::table_grant:', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
  after :all do
    # Cleanup after tests have ran
    apply_manifest("class { 'postgresql::server': ensure => absent }", :catch_failures => true)
  end

  it 'should grant all accesses to a user' do
    begin
      pp = <<-EOS.unindent
        $db = 'table_grant'
        $user = 'psql_grant_tester'
        $password = 'psql_table_pw'

        class { 'postgresql::server': }

        # Since we are not testing pg_hba or any of that, make a local user for ident auth
        user { $user:
          ensure => present,
        }

        postgresql::server::role { $user:
          password_hash => postgresql_password($user, $password),
        }

        postgresql::server::database { $db: }

        # Create a rule for the user
        postgresql::server::pg_hba_rule { "allow ${user}":
          type        => 'local',
          database    => $db,
          user        => $user,
          auth_method => 'ident',
          order       => 1,
        }

        postgresql_psql { 'Create testing table':
          command => 'CREATE TABLE "test_table" (field integer NOT NULL)',
          db      => $db,
          unless  => "SELECT * FROM pg_tables WHERE tablename = 'test_table'",
          require => Postgresql::Server::Database[$db],
        }

        postgresql::server::table_grant { 'grant insert test':
          privilege => 'ALL',
          table     => 'test_table',
          db        => $db,
          role      => $user,
          require   => Postgresql_psql['Create testing table'],
        }
      EOS

      apply_manifest(pp, :catch_failures => true)
      apply_manifest(pp, :catch_changes => true)

      ## Check that the user can create a table in the database
      psql('--command="create table foo (foo int)" postgres', 'psql_grant_tester') do |r|
        expect(r.stdout).to match(/CREATE TABLE/)
        expect(r.stderr).to eq('')
      end
    ensure
      psql('--command="drop table foo" postgres', 'psql_grant_tester')
    end
  end

  it 'should grant access so a user can insert in a table' do
    begin
      pp = <<-EOS.unindent
        $db = 'table_grant'
        $user = 'psql_grant_tester'
        $password = 'psql_table_pw'

        class { 'postgresql::server': }

        # Since we are not testing pg_hba or any of that, make a local user for ident auth
        user { $user:
          ensure => present,
        }

        postgresql::server::role { $user:
          password_hash => postgresql_password($user, $password),
        }

        postgresql::server::database { $db: }

        # Create a rule for the user
        postgresql::server::pg_hba_rule { "allow ${user}":
          type        => 'local',
          database    => $db,
          user        => $user,
          auth_method => 'ident',
          order       => 1,
        }

        postgresql_psql { 'Create testing table':
          command => 'CREATE TABLE "test_table" (field integer NOT NULL)',
          db      => $db,
          unless  => "SELECT * FROM pg_tables WHERE tablename = 'test_table'",
          require => Postgresql::Server::Database[$db],
        }

        postgresql::server::table_grant { 'grant insert test':
          privilege => 'INSERT',
          table     => 'test_table',
          db        => $db,
          role      => $user,
          require   => Postgresql_psql['Create testing table'],
        }
      EOS

      apply_manifest(pp, :catch_failures => true)
      apply_manifest(pp, :catch_changes => true)

      ## Check that the user can create a table in the database
      psql('--command="create table foo (foo int)" postgres', 'psql_grant_tester') do |r|
        expect(r.stdout).to match(/CREATE TABLE/)
        expect(r.stderr).to eq('')
      end
    ensure
      psql('--command="drop table foo" postgres', 'psql_grant_tester')
    end
  end
end
require 'spec_helper_acceptance'

describe 'postgresql::server::tablespace:', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
  after :all do
    # Cleanup after tests have ran
    apply_manifest("class { 'postgresql::server': ensure => absent }", :catch_failures => true)
  end

  it 'should idempotently create tablespaces and databases that are using them' do
    pp = <<-EOS.unindent
      class { 'postgresql::server': }

      file { '/tmp/postgres/pg_tablespaces':
        ensure => 'directory',
        owner  => 'postgres',
        group  => 'postgres',
        mode   => '0700',
      }

      postgresql::server::tablespace { 'tablespace1':
        location => '/tmp/postgres/pg_tablespaces/space1',
      }
      postgresql::server::database { 'tablespacedb1':
        encoding   => 'utf8',
        tablespace => 'tablespace1',
      }
      postgresql::server::db { 'tablespacedb2':
        user       => 'dbuser2',
        password   => postgresql_password('dbuser2', 'dbuser2'),
        tablespace => 'tablespace1',
      }

      postgresql::server::role { 'spcuser':
        password_hash => postgresql_password('spcuser', 'spcuser'),
      }
      postgresql::server::tablespace { 'tablespace2':
        location => '/tmp/postgres/pg_tablespaces/space2',
        owner    => 'spcuser',
      }
      postgresql::server::database { 'tablespacedb3':
        encoding   => 'utf8',
        tablespace => 'tablespace2',
      }
    EOS

    shell('mkdir -p /tmp/postgres')
    # Apply appropriate selinux labels
    if fact('osfamily') == 'RedHat'
      if shell('getenforce').stdout =~ /Enforcing/
        shell('chcon -Rv --type=postgresql_db_t /tmp/postgres')
      end
    end
    apply_manifest(pp, :catch_failures => true)
    apply_manifest(pp, :catch_changes => true)

    # Check that databases use correct tablespaces
    psql('--command="select ts.spcname from pg_database db, pg_tablespace ts where db.dattablespace = ts.oid and db.datname = \'"\'tablespacedb1\'"\'"') do |r|
      expect(r.stdout).to match(/tablespace1/)
      expect(r.stderr).to eq('')
    end

    psql('--command="select ts.spcname from pg_database db, pg_tablespace ts where db.dattablespace = ts.oid and db.datname = \'"\'tablespacedb3\'"\'"') do |r|
      expect(r.stdout).to match(/tablespace2/)
      expect(r.stderr).to eq('')
    end
  end
end
require 'spec_helper_acceptance'

describe 'server:', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
  after :all do
    # Cleanup after tests have ran
    apply_manifest("class { 'postgresql::server': ensure => absent }", :catch_failures => true)
  end

  it 'test loading class with no parameters' do
    pp = <<-EOS.unindent
      class { 'postgresql::server': }
    EOS

    apply_manifest(pp, :catch_failures => true)
    apply_manifest(pp, :catch_changes => true)
  end

  describe port(5432) do
    it { should be_listening }
  end

  describe 'setting postgres password' do
    it 'should install and successfully adjust the password' do
      pp = <<-EOS.unindent
        class { 'postgresql::server':
          postgres_password          => 'foobarbaz',
          ip_mask_deny_postgres_user => '0.0.0.0/32',
        }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/\[set_postgres_postgrespw\]\/returns: executed successfully/)
      end
      apply_manifest(pp, :catch_changes => true)

      pp = <<-EOS.unindent
        class { 'postgresql::server':
          postgres_password          => 'TPSR$$eports!',
          ip_mask_deny_postgres_user => '0.0.0.0/32',
        }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/\[set_postgres_postgrespw\]\/returns: executed successfully/)
      end
      apply_manifest(pp, :catch_changes => true)

    end
  end
end

describe 'server without defaults:', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
  context 'test installing non-default version of postgresql' do
    after :all do
      psql('--command="drop database postgresql_test_db" postgres', 'postgres')
      pp = <<-EOS.unindent
        if $::osfamily == 'Debian' {
          class { 'apt': }
          # XXX Need to purge postgresql-common after uninstalling 9.3 because
          # it leaves the init script behind. Poor packaging.
          package { 'postgresql-common':
            ensure  => purged,
            require => Class['postgresql::server'],
          }
        }
        class { 'postgresql::globals':
          ensure              => absent,
          manage_package_repo => true,
          version             => '9.3',
        }
        class { 'postgresql::server':
          ensure => absent,
        }
      EOS
      expect(apply_manifest(pp, :catch_failures => true).stderr).to eq('')
    end

    it 'perform installation and create a db' do
      pp = <<-EOS.unindent
        if $::osfamily == 'Debian' {
          class { 'apt': }
        }
        class { "postgresql::globals":
          version             => "9.3",
          manage_package_repo => true,
          encoding            => 'UTF8',
          locale              => 'en_US.UTF-8',
          xlogdir             => '/tmp/pg_xlogs',
        }
        class { "postgresql::server": }
        postgresql::server::db { "postgresql_test_db":
          user     => "foo1",
          password => postgresql_password('foo1', 'foo1'),
        }
        postgresql::server::config_entry { 'port':
          value => '5432',
        }
      EOS

      expect(apply_manifest(pp, :catch_failures => true).stderr).to eq('')
      apply_manifest(pp, :catch_changes => true)

      shell('test -d /tmp/pg_xlogs') do |r|
        expect(r.stdout).to eq('')
        expect(r.stderr).to eq('')
      end

      psql('postgresql_test_db --command="select datname from pg_database limit 1"')
    end

    describe port(5432) do
      it { should be_listening }
    end
  end

  unless ((fact('osfamily') == 'RedHat' and fact('lsbmajdistrelease') == '5') ||
    fact('osfamily') == 'Debian')

    context 'override locale and encoding' do
      after :each do
        apply_manifest("class { 'postgresql::server': ensure => absent }", :catch_failures => true)
      end

      it 'perform installation with different locale and encoding' do
        pp = <<-EOS.unindent
          class { 'postgresql::server':
            locale   => 'en_NG',
            encoding => 'UTF8',
          }
        EOS

        apply_manifest(pp, :catch_failures => true)
        apply_manifest(pp, :catch_changes => true)

        # Remove db first, if it exists for some reason
        shell('su postgres -c "dropdb test1"', :acceptable_exit_codes => [0,1,2])
        shell('su postgres -c "createdb test1"')
        shell('su postgres -c \'psql -c "show lc_ctype" test1\'') do |r|
          expect(r.stdout).to match(/en_NG/)
        end

        shell('su postgres -c \'psql -c "show lc_collate" test1\'') do |r|
          expect(r.stdout).to match(/en_NG/)
        end
      end
    end
  end
end

describe 'server with firewall:', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
  after :all do
    apply_manifest("class { 'postgresql::server': ensure => absent }", :catch_failures => true)
  end

  context 'test installing postgresql with firewall management on' do
    it 'perform installation and make sure it is idempotent' do
      pending('no support for firewall with fedora', :if => (fact('operatingsystem') == 'Fedora'))
      pp = <<-EOS.unindent
        class { 'firewall': }
        class { "postgresql::server":
          manage_firewall => true,
        }
      EOS

      apply_manifest(pp, :catch_failures => true)
      apply_manifest(pp, :catch_changes => true)
    end
  end
end

describe 'server without pg_hba.conf:', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
  after :all do
    apply_manifest("class { 'postgresql::server': ensure => absent }", :catch_failures => true)
  end

  context 'test installing postgresql without pg_hba.conf management on' do
    it 'perform installation and make sure it is idempotent' do
      pp = <<-EOS.unindent
        class { "postgresql::server":
          manage_pg_hba_conf => false,
        }
      EOS

      apply_manifest(pp, :catch_failures => true)
      apply_manifest(pp, :catch_changes => true)
    end
  end
end
require 'spec_helper_acceptance'

describe 'unsupported distributions and OSes', :if => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
  it 'should fail for client' do
    pp = <<-EOS
    class { 'postgresql::client': }
    EOS
    expect(apply_manifest(pp, :expect_failures => true).stderr).to match(/does not provide defaults for osfamily/i)
  end
  it 'should fail for server' do
    pp = <<-EOS
    class { 'postgresql::server': }
    EOS
    expect(apply_manifest(pp, :expect_failures => true).stderr).to match(/does not provide defaults for osfamily/i)
  end
end
require 'spec_helper_acceptance'

describe 'postgresql::validate_db_connection:', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
  before :all do
    # Setup postgresql server and a sample database for tests to use.
    pp = <<-EOS.unindent
      $db = 'foo'
      class { 'postgresql::server': }

      postgresql::server::db { $db:
        user     => $db,
        password => postgresql_password($db, $db),
      }
    EOS

    apply_manifest(pp, :catch_failures => true)
  end

  after :all do
    # Remove postgresql server after all tests have ran.
    apply_manifest("class { 'postgresql::server': ensure => absent }", :catch_failures => true)
  end

  it 'should run puppet with no changes declared if socket connectivity works' do
    pp = <<-EOS.unindent
      postgresql::validate_db_connection { 'foo':
        database_name => 'foo',
        run_as        => 'postgres',
      }
    EOS

    apply_manifest(pp, :catch_failures => true)
  end

  it 'should keep retrying if database is down' do
    # So first we shut the db down, then background a startup routine with a
    # sleep 10 in front of it. That way the tests should continue while
    # the pause and db startup happens in the background.
    shell("/etc/init.d/postgresql* stop")
    shell('nohup bash -c "sleep 10; /etc/init.d/postgresql* start" > /dev/null 2>&1 &')

    pp = <<-EOS.unindent
      postgresql::validate_db_connection { 'foo':
        database_name => 'foo',
        tries         => 30,
        sleep         => 1,
        run_as        => 'postgres',
      }
    EOS

    apply_manifest(pp, :catch_failures => true)
  end

  it 'should run puppet with no changes declared if db ip connectivity works' do
    pp = <<-EOS.unindent
      postgresql::validate_db_connection { 'foo':
        database_host     => 'localhost',
        database_name     => 'foo',
        database_username => 'foo',
        database_password => 'foo',
      }
    EOS

    apply_manifest(pp, :catch_failures => true)
  end

  it 'should fail catalogue if database connectivity fails' do
    pp = <<-EOS.unindent
      postgresql::validate_db_connection { 'foobarbaz':
        database_host     => 'localhost',
        database_name     => 'foobarbaz',
        database_username => 'foobarbaz',
        database_password => 'foobarbaz',
      }
    EOS

    apply_manifest(pp, :expect_failures => true)
  end
end
require 'puppetlabs_spec_helper/module_spec_helper'

RSpec.configure do |c|
  c.mock_with :rspec do |mock|
    mock.syntax = [:expect, :should]
  end
  c.include PuppetlabsSpec::Files

  c.before :each do
    # Ensure that we don't accidentally cache facts and environment
    # between test cases.
    Facter::Util::Loader.any_instance.stubs(:load_all)
    Facter.clear
    Facter.clear_messages

    # Store any environment variables away to be restored later
    @old_env = {}
    ENV.each_key {|k| @old_env[k] = ENV[k]}
  end

  c.after :each do
    PuppetlabsSpec::Files.cleanup
  end
end

# Convenience helper for returning parameters for a type from the
# catalogue.
def param(type, title, param)
  param_value(catalogue, type, title, param)
end
require 'beaker-rspec/spec_helper'
require 'beaker-rspec/helpers/serverspec'

class String
  # Provide ability to remove indentation from strings, for the purpose of
  # left justifying heredoc blocks.
  def unindent
    gsub(/^#{scan(/^\s*/).min_by{|l|l.length}}/, "")
  end
end

def shellescape(str)
  str = str.to_s

  # An empty argument will be skipped, so return empty quotes.
  return "''" if str.empty?

  str = str.dup

  # Treat multibyte characters as is.  It is caller's responsibility
  # to encode the string in the right encoding for the shell
  # environment.
  str.gsub!(/([^A-Za-z0-9_\-.,:\/@\n])/, "\\\\\\1")

  # A LF cannot be escaped with a backslash because a backslash + LF
  # combo is regarded as line continuation and simply ignored.
  str.gsub!(/\n/, "'\n'")

  return str
end

def psql(psql_cmd, user = 'postgres', exit_codes = [0], &block)
  psql = "psql #{psql_cmd}"
  shell("su #{shellescape(user)} -c #{shellescape(psql)}", :acceptable_exit_codes => exit_codes, &block)
end

unless ENV['RS_PROVISION'] == 'no'
  hosts.each do |host|
    if host.is_pe?
      install_pe
    else
      install_puppet
      on host, "mkdir -p #{host['distmoduledir']}"
    end
  end
end

UNSUPPORTED_PLATFORMS = ['AIX','windows','Solaris','Suse']

RSpec.configure do |c|
  # Project root
  proj_root = File.expand_path(File.join(File.dirname(__FILE__), '..'))

  # Readable test descriptions
  c.formatter = :documentation

  # Configure all nodes in nodeset
  c.before :suite do
    # Install module and dependencies
    puppet_module_install(:source => proj_root, :module_name => 'postgresql')
    hosts.each do |host|
      on host, "/bin/touch #{default['puppetpath']}/hiera.yaml"
      on host, 'chmod 755 /root'
      if fact('osfamily') == 'Debian'
        on host, "echo \"en_US ISO-8859-1\nen_NG.UTF-8 UTF-8\nen_US.UTF-8 UTF-8\n\" > /etc/locale.gen"
        on host, '/usr/sbin/locale-gen'
        on host, '/usr/sbin/update-locale'
      end
      on host, puppet('module','install','puppetlabs-stdlib'), { :acceptable_exit_codes => [0,1] }
      on host, puppet('module','install','puppetlabs-firewall'), { :acceptable_exit_codes => [0,1] }
      on host, puppet('module','install','puppetlabs-apt'), { :acceptable_exit_codes => [0,1] }
      on host, puppet('module','install','puppetlabs-concat'), { :acceptable_exit_codes => [0,1] }
    end
  end
end
require 'spec_helper'

describe 'postgresql::client', :type => :class do
  let :facts do
    {
      :osfamily => 'Debian',
      :operatingsystem => 'Debian',
      :operatingsystemrelease => '6.0',
    }
  end

  describe 'with parameters' do
    let :params do
      {
        :package_ensure => 'absent',
        :package_name => 'mypackage',
      }
    end

    it 'should modify package' do
      should contain_package("postgresql-client").with({
        :ensure => 'absent',
        :name => 'mypackage',
        :tag => 'postgresql',
      })
    end
  end

  describe 'with no parameters' do
    it 'should create package with postgresql tag' do
      should contain_package('postgresql-client').with({
        :tag => 'postgresql',
      })
    end
  end
end
require 'spec_helper'

describe 'postgresql::globals', :type => :class do
  let :facts do
    {
      :osfamily               => 'Debian',
      :operatingsystem        => 'Debian',
      :operatingsystemrelease => '6.0',
      :lsbdistid              => 'Debian',
    }
  end

  describe 'with no parameters' do
    it 'should work' do
      should contain_class("postgresql::globals")
    end
  end

  describe 'manage_package_repo => true' do
    let(:params) do
      {
        :manage_package_repo => true,
      }
    end
    it 'should pull in class postgresql::repo' do
      should contain_class("postgresql::repo")
    end
  end
end
require 'spec_helper'

describe 'postgresql::lib::devel', :type => :class do
  let :facts do
    {
      :osfamily => 'Debian',
      :operatingsystem => 'Debian',
      :operatingsystemrelease => '6.0',
    }
  end
  it { should contain_class("postgresql::lib::devel") }
end
require 'spec_helper'

describe 'postgresql::lib::java', :type => :class do

  describe 'on a debian based os' do
    let :facts do {
      :osfamily => 'Debian',
      :operatingsystem => 'Debian',
      :operatingsystemrelease => '6.0',
    }
    end
    it { should contain_package('postgresql-jdbc').with(
      :name   => 'libpostgresql-jdbc-java',
      :ensure => 'present'
    )}
  end

  describe 'on a redhat based os' do
    let :facts do {
      :osfamily => 'RedHat',
      :operatingsystem => 'RedHat',
      :operatingsystemrelease => '6.4',
    }
    end
    it { should contain_package('postgresql-jdbc').with(
      :name => 'postgresql-jdbc',
      :ensure => 'present'
    )}
    describe 'when parameters are supplied' do
      let :params do
        {:package_ensure => 'latest', :package_name => 'somepackage'}
      end
      it { should contain_package('postgresql-jdbc').with(
        :name => 'somepackage',
        :ensure => 'latest'
      )}
    end
  end

end
require 'spec_helper'

describe 'postgresql::lib::python', :type => :class do

  describe 'on a redhat based os' do
    let :facts do {
      :osfamily => 'RedHat',
      :operatingsystem => 'RedHat',
      :operatingsystemrelease => '6.4',
    }
    end
    it { should contain_package('python-psycopg2').with(
      :name => 'python-psycopg2',
      :ensure => 'present'
    )}
  end

  describe 'on a debian based os' do
    let :facts do {
      :osfamily => 'Debian',
      :operatingsystem => 'Debian',
      :operatingsystemrelease => '6.0',
    }
    end
    it { should contain_package('python-psycopg2').with(
      :name => 'python-psycopg2',
      :ensure => 'present'
    )}
  end

end
require 'spec_helper'

describe 'postgresql::params', :type => :class do
  let :facts do
    {
      :osfamily => 'Debian',
      :operatingsystem => 'Debian',
      :operatingsystemrelease => '6.0',
    }
  end
  it { should contain_class("postgresql::params") }
end
require 'spec_helper'

describe 'postgresql::repo', :type => :class do
  let :facts do
    {
      :osfamily               => 'Debian',
      :operatingsystem        => 'Debian',
      :operatingsystemrelease => '6.0',
      :lsbdistid              => 'Debian',
    }
  end

  describe 'with no parameters' do
    it 'should instantiate apt_postgresql_org class' do
      should contain_class('postgresql::repo::apt_postgresql_org')
    end
  end
end
require 'spec_helper'

describe 'postgresql::server::contrib', :type => :class do
  let :pre_condition do
    "class { 'postgresql::server': }"
  end

  let :facts do
    {
      :osfamily => 'Debian',
      :operatingsystem => 'Debian',
      :operatingsystemrelease => '6.0',
      :kernel => 'Linux',
      :concat_basedir => tmpfilename('contrib'),
    }
  end

  describe 'with parameters' do
    let(:params) do
      {
        :package_name => 'mypackage',
        :package_ensure => 'absent',
      }
    end

    it 'should create package with correct params' do
      should contain_package('postgresql-contrib').with({
        :ensure => 'absent',
        :name => 'mypackage',
        :tag => 'postgresql',
      })
    end
  end

  describe 'with no parameters' do
    it 'should create package with postgresql tag' do
      should contain_package('postgresql-contrib').with({
        :tag => 'postgresql',
      })
    end
  end
end
require 'spec_helper'

describe 'postgresql::server::initdb', :type => :class do
  let (:pre_condition) do
    "include postgresql::server"
  end
  describe 'on RedHat' do
    let :facts do
      {
        :osfamily => 'RedHat',
        :operatingsystem => 'CentOS',
        :operatingsystemrelease => '6.0',
        :concat_basedir => tmpfilename('server'),
      }
    end
    it { should contain_file('/var/lib/pgsql/data').with_ensure('directory') }
  end
  describe 'on Amazon' do
    let :facts do
      {
        :osfamily => 'RedHat',
        :operatingsystem => 'Amazon',
        :concat_basedir => tmpfilename('server'),
      }
    end
    it { should contain_file('/var/lib/pgsql9/data').with_ensure('directory') }
  end
end

require 'spec_helper'

describe 'postgresql::server::plperl', :type => :class do
  let :facts do
    {
      :osfamily => 'Debian',
      :operatingsystem => 'Debian',
      :operatingsystemrelease => '6.0',
      :kernel => 'Linux',
      :concat_basedir => tmpfilename('plperl'),
    }
  end

  let :pre_condition do
    "class { 'postgresql::server': }"
  end

  describe 'with no parameters' do
    it { should contain_class("postgresql::server::plperl") }
    it 'should create package' do
      should contain_package('postgresql-plperl').with({
        :ensure => 'present',
        :tag => 'postgresql',
      })
    end
  end

  describe 'with parameters' do
    let :params do
      {
        :package_ensure => 'absent',
        :package_name => 'mypackage',
      }
    end

    it { should contain_class("postgresql::server::plperl") }
    it 'should create package with correct params' do
      should contain_package('postgresql-plperl').with({
        :ensure => 'absent',
        :name => 'mypackage',
        :tag => 'postgresql',
      })
    end
  end
end
require 'spec_helper'

describe 'postgresql::server', :type => :class do
  let :facts do
    {
      :osfamily => 'Debian',
      :operatingsystem => 'Debian',
      :operatingsystemrelease => '6.0',
      :concat_basedir => tmpfilename('server'),
      :kernel => 'Linux',
    }
  end

  describe 'with no parameters' do
    it { should contain_class("postgresql::params") }
    it { should contain_class("postgresql::server") }
    it 'should validate connection' do
      should contain_postgresql__validate_db_connection('validate_service_is_running')
    end
  end

  describe 'manage_firewall => true' do
    let(:params) do
      {
        :manage_firewall => true,
        :ensure => true,
      }
    end

    it 'should create firewall rule' do
      should contain_firewall("5432 accept - postgres")
    end
  end

  describe 'ensure => absent' do
    let(:params) do
      {
        :ensure => 'absent',
        :datadir => '/my/path',
        :xlogdir => '/xlog/path',
      }
    end

    it 'should make package purged' do
      should contain_package('postgresql-server').with({
        :ensure => 'purged',
      })
    end

    it 'stop the service' do
      should contain_service('postgresqld').with({
        :ensure => false,
      })
    end

    it 'should remove datadir' do
      should contain_file('/my/path').with({
        :ensure => 'absent',
      })
    end

    it 'should remove xlogdir' do
      should contain_file('/xlog/path').with({
        :ensure => 'absent',
      })
    end
  end

  describe 'package_ensure => absent' do
    let(:params) do
      {
        :package_ensure => 'absent',
      }
    end

    it 'should remove the package' do
      should contain_package('postgresql-server').with({
        :ensure => 'purged',
      })
    end

    it 'should still enable the service' do
      should contain_service('postgresqld').with({
        :ensure => true,
      })
    end
  end

  describe 'needs_initdb => true' do
    let(:params) do
      {
        :needs_initdb => true,
      }
    end

    it 'should contain proper initdb exec' do
      should contain_exec('postgresql_initdb')
    end
  end
end
require 'spec_helper'

describe 'postgresql::server::config_entry', :type => :define do
  let :facts do
    {
      :osfamily => 'RedHat',
      :operatingsystem => 'RedHat',
      :operatingsystemrelease => '6.4',
    }
  end

  let(:title) { 'config_entry'}

  let :target do
    tmpfilename('postgresql_conf')
  end

  context "syntax check" do
    let(:params) { { :ensure => 'present'} }
    it { should contain_postgresql__server__config_entry('config_entry') }
  end
end

require 'spec_helper'

describe 'postgresql::server::database_grant', :type => :define do
  let :facts do
    {
      :osfamily => 'Debian',
      :operatingsystem => 'Debian',
      :operatingsystemrelease => '6.0',
    }
  end

  let :title do
    'test'
  end

  let :params do
    {
      :privilege => 'ALL',
      :db => 'test',
      :role => 'test',
    }
  end

  it { should contain_postgresql__server__database_grant('test') }
  it { should contain_postgresql__server__grant('database:test') }
end
require 'spec_helper'

describe 'postgresql::server::database', :type => :define do
  let :facts do
    {
      :osfamily => 'Debian',
      :operatingsystem => 'Debian',
      :operatingsystemrelease => '6.0',
    }
  end
  let :title do
    'test'
  end
  it { should contain_postgresql__server__database('test') }
  it { should contain_postgresql_psql("Check for existence of db 'test'") }
end
require 'spec_helper'

describe 'postgresql::server::db', :type => :define do
  let :facts do
    {
      :osfamily => 'Debian',
      :operatingsystem => 'Debian',
      :operatingsystemrelease => '6.0',
    }
  end

  let :title do
    'test'
  end

  let :params do
    {
      :user => 'test',
      :password => 'test',
      :owner => 'tester',
    }
  end

  it { should contain_postgresql__server__db('test') }
  it { should contain_postgresql__server__database('test').with_owner('tester') }
  it { should contain_postgresql__server__role('test') }
  it { should contain_postgresql__server__database_grant('GRANT test - ALL - test') }
end
require 'spec_helper'

describe 'postgresql::server::grant', :type => :define do
  let :facts do
    {
      :osfamily => 'Debian',
      :operatingsystem => 'Debian',
      :operatingsystemrelease => '6.0',
    }
  end

  let :title do
    'test'
  end

  let :params do
    {
      :db => 'test',
      :role => 'test',
    }
  end

  it { should contain_postgresql__server__grant('test') }
end
require 'spec_helper'

describe 'postgresql::server::pg_hba_rule', :type => :define do
  let :facts do
    {
      :osfamily => 'Debian',
      :operatingsystem => 'Debian',
      :operatingsystemrelease => '6.0',
      :concat_basedir => tmpfilename('pg_hba'),
    }
  end
  let :title do
    'test'
  end
  let :target do
    tmpfilename('pg_hba_rule')
  end

  context 'test template 1' do
    let :params do
      {
        :type => 'host',
        :database => 'all',
        :user => 'all',
        :address => '1.1.1.1/24',
        :auth_method => 'md5',
        :target => target,
      }
    end
    it do
      content = param('concat::fragment', 'pg_hba_rule_test', 'content')
      content.should =~ /host\s+all\s+all\s+1\.1\.1\.1\/24\s+md5/
    end
  end

  context 'test template 2' do
    let :params do
      {
        :type => 'local',
        :database => 'all',
        :user => 'all',
        :auth_method => 'ident',
        :target => target,
      }
    end
    it do
      content = param('concat::fragment', 'pg_hba_rule_test', 'content')
      content.should =~ /local\s+all\s+all\s+ident/
    end
  end

  context 'test template 3' do
    let :params do
      {
        :type => 'host',
        :database => 'all',
        :user => 'all',
        :address => '0.0.0.0/0',
        :auth_method => 'ldap',
        :auth_option => 'foo=bar',
        :target => target,
      }
    end
    it do
      content = param('concat::fragment', 'pg_hba_rule_test', 'content')
      content.should =~ /host\s+all\s+all\s+0\.0\.0\.0\/0\s+ldap\s+foo=bar/
    end
  end

  context 'validation' do
    context 'validate type test 1' do
      let :params do
        {
          :type => 'invalid',
          :database => 'all',
          :user => 'all',
          :address => '0.0.0.0/0',
          :auth_method => 'ldap',
          :target => target,
        }
      end
      it 'should fail parsing when type is not valid' do
        expect {subject}.to raise_error(Puppet::Error,
          /The type you specified \[invalid\] must be one of/)
      end
    end

    context 'validate auth_method' do
      let :params do
        {
          :type => 'local',
          :database => 'all',
          :user => 'all',
          :address => '0.0.0.0/0',
          :auth_method => 'invalid',
          :target => target,
        }
      end

      it 'should fail parsing when auth_method is not valid' do
        expect {subject}.to raise_error(Puppet::Error,
          /The auth_method you specified \[invalid\] must be one of/)
      end
    end

    context 'validate unsupported auth_method' do
      let :pre_condition do
        <<-EOS
          class { 'postgresql::globals':
            version => '9.0',
          }
          class { 'postgresql::server': }
        EOS
      end

      let :params do
        {
          :type => 'local',
          :database => 'all',
          :user => 'all',
          :address => '0.0.0.0/0',
          :auth_method => 'peer',
          :target => target,
        }
      end

      it 'should fail parsing when auth_method is not valid' do
        expect {subject}.to raise_error(Puppet::Error,
          /The auth_method you specified \[peer\] must be one of: trust, reject, md5, sha1, password, gss, sspi, krb5, ident, ldap, radius, cert, pam/)
      end
    end

    context 'validate supported auth_method' do
      let :pre_condition do
        <<-EOS
          class { 'postgresql::globals':
            version => '9.2',
          }
          class { 'postgresql::server': }
        EOS
      end

      let :params do
        {
          :type => 'local',
          :database => 'all',
          :user => 'all',
          :address => '0.0.0.0/0',
          :auth_method => 'peer',
          :target => target,
        }
      end

      it do
        content = param('concat::fragment', 'pg_hba_rule_test', 'content')
        content.should =~ /local\s+all\s+all\s+0\.0\.0\.0\/0\s+peer/
      end
    end

  end
end
require 'spec_helper'

describe 'postgresql::server::role', :type => :define do
  let :facts do
    {
      :osfamily => 'Debian',
      :operatingsystem => 'Debian',
      :operatingsystemrelease => '6.0',
    }
  end

  let :title do
    'test'
  end

  let :params do
    {
      :password_hash => 'test',
    }
  end

  it { should contain_postgresql__server__role('test') }
end
require 'spec_helper'

describe 'postgresql::server::table_grant', :type => :define do
  let :facts do
    {
      :osfamily => 'Debian',
      :operatingsystem => 'Debian',
      :operatingsystemrelease => '6.0',
    }
  end

  let :title do
    'test'
  end

  let :params do
    {
      :privilege => 'ALL',
      :db => 'test',
      :role => 'test',
      :table => 'foo',
    }
  end

  it { should contain_postgresql__server__table_grant('test') }
  it { should contain_postgresql__server__grant('table:test') }
end
require 'spec_helper'

describe 'postgresql::server::tablespace', :type => :define do
  let :facts do
    {
      :osfamily => 'Debian',
      :operatingsystem => 'Debian',
      :operatingsystemrelease => '6.0',
    }
  end

  let :title do
    'test'
  end

  let :params do
    {
      :location => '/srv/data/foo',
    }
  end

  it { should contain_postgresql__server__tablespace('test') }
end
require 'spec_helper'

describe 'postgresql::validate_db_connection', :type => :define do
  let :facts do
    {
      :osfamily => 'Debian',
      :operatingsystem => 'Debian',
      :operatingsystemrelease => '6.0',
    }
  end

  let :title do
    'test'
  end

  describe 'should work with only default parameters' do
    it { should contain_postgresql__validate_db_connection('test') }
  end

  describe 'should work with all parameters' do
    let :params do
      {
        :database_host => 'test',
        :database_name => 'test',
        :database_password => 'test',
        :database_username => 'test',
        :database_port => 5432,
        :run_as => 'postgresq',
        :sleep => 4,
        :tries => 30,
      }
    end
    it { should contain_postgresql__validate_db_connection('test') }
  end
end
require 'spec_helper'

describe 'postgresql_acls_to_resources_hash', :type => :puppet_function do
  context 'individual transform tests' do
    it do
      input = 'local   all             postgres                                ident'
      result = {
        "postgresql class generated rule test 0"=>{
          "type"=>"local",
          "database"=>"all",
          "user"=>"postgres",
          "auth_method"=>"ident",
          "order"=>"100",
        },
      }

      should run.with_params([input], 'test', 100).and_return(result)
    end

    it do
      input = 'local   all             root                                ident'
      result = {
        "postgresql class generated rule test 0"=>{
          "type"=>"local",
          "database"=>"all",
          "user"=>"root",
          "auth_method"=>"ident",
          "order"=>"100",
        },
      }

      should run.with_params([input], 'test', 100).and_return(result)
    end

    it do
      input_array = [
        'local   all             all                                     ident',
      ]
      result = {
        "postgresql class generated rule test 0"=>{
          "type"=>"local",
          "database"=>"all",
          "user"=>"all",
          "auth_method"=>"ident",
          "order"=>"100",
        },
      }

      should run.with_params(input_array, 'test', 100).and_return(result)
    end

    it do
      input = 'host    all             all             127.0.0.1/32            md5'
      result = {
        "postgresql class generated rule test 0"=>{
          "type"=>"host",
          "database"=>"all",
          "user"=>"all",
          "address"=>"127.0.0.1/32",
          "auth_method"=>"md5",
          "order"=>"100",
        },
      }

      should run.with_params([input], 'test', 100).and_return(result)
    end

    it do
      input = 'host    all             all             0.0.0.0/0            md5'
      result = {
        "postgresql class generated rule test 0"=>{
          "type"=>"host",
          "database"=>"all",
          "user"=>"all",
          "address"=>"0.0.0.0/0",
          "auth_method"=>"md5",
          "order"=>"100",
        },
      }

      should run.with_params([input], 'test', 100).and_return(result)
    end

    it do
      input = 'host    all             all             ::1/128                 md5'
      result = {
        "postgresql class generated rule test 0"=>{
          "type"=>"host",
          "database"=>"all",
          "user"=>"all",
          "address"=>"::1/128",
          "auth_method"=>"md5",
          "order"=>"100",
        },
      }

      should run.with_params([input], 'test', 100).and_return(result)
    end

    it do
      input = 'host    all             all             1.1.1.1 255.255.255.0    md5'
      result = {
        "postgresql class generated rule test 0"=>{
          "type"=>"host",
          "database"=>"all",
          "user"=>"all",
          "address"=>"1.1.1.1 255.255.255.0",
          "auth_method"=>"md5",
          "order"=>"100",
        },
      }

      should run.with_params([input], 'test', 100).and_return(result)
    end

    it do
      input = 'host    all             all             1.1.1.1 255.255.255.0   ldap ldapserver=ldap.example.net ldapprefix="cn=" ldapsuffix=", dc=example, dc=net"'
      result = {
        "postgresql class generated rule test 0"=>{
          "type"=>"host",
          "database"=>"all",
          "user"=>"all",
          "address"=>"1.1.1.1 255.255.255.0",
          "auth_method"=>"ldap",
          "auth_option"=>"ldapserver=ldap.example.net ldapprefix=\"cn=\" ldapsuffix=\", dc=example, dc=net\"",
          "order"=>"100",
        },
      }

      should run.with_params([input], 'test', 100).and_return(result)
    end
  end

  it 'should return an empty hash when input is empty array' do
    should run.with_params([], 'test', 100).and_return({})
  end
end
require 'spec_helper'

describe 'postgresql_escape', :type => :puppet_function do
  it { should run.with_params('foo').
    and_return('$$foo$$') }
end
describe 'postgresql_escape', :type => :puppet_function do
  it { should run.with_params('fo$$o').
    and_return('$ed$fo$$o$ed$') }
end
require 'spec_helper'

describe 'postgresql_password', :type => :puppet_function do
  it { should run.with_params('foo', 'bar').
    and_return('md596948aad3fcae80c08a35c9b5958cd89') }
end
require 'spec_helper'
require "tempfile"

provider_class = Puppet::Type.type(:postgresql_conf).provider(:parsed)

describe provider_class do
  let(:title) { 'postgresql_conf' }
  let(:provider) {
    conf_class = Puppet::Type.type(:postgresql_conf)
    provider = conf_class.provider(:parsed)
    conffile = tmpfilename('postgresql.conf')
    provider.any_instance.stubs(:target).returns conffile
    provider
  }

  before do
  end

  after :each do
    provider.initvars
  end

  describe "simple configuration that should be allowed" do
    it "should parse a simple ini line" do
      provider.parse_line("listen_addreses = '*'").should ==
        { :name=>"listen_addreses", :value=>"*", :comment=>nil, :record_type=>:parsed }
    end

    it "should parse a simple ini line (2)" do
      provider.parse_line("   listen_addreses = '*'").should ==
        { :name=>"listen_addreses", :value=>"*", :comment=>nil, :record_type=>:parsed }
    end

    it "should parse a simple ini line (3)" do
      provider.parse_line("listen_addreses = '*' # dont mind me").should ==
        { :name=>"listen_addreses", :value=>"*", :comment=>"dont mind me", :record_type=>:parsed }
    end

    it "should parse a comment" do
      provider.parse_line("# dont mind me").should ==
        { :line=>"# dont mind me", :record_type=>:comment }
    end

    it "should parse a comment (2)" do
      provider.parse_line(" \t# dont mind me").should ==
        { :line=>" \t# dont mind me", :record_type=>:comment }
    end

    it "should allow includes" do
      provider.parse_line("include puppetextra").should ==
        { :name=>"include", :value=>"puppetextra", :comment=>nil, :record_type=>:parsed }
    end

    it "should allow numbers thorugh without quotes" do
      provider.parse_line("wal_keep_segments = 32").should ==
        { :name=>"wal_keep_segments", :value=>"32", :comment=>nil, :record_type=>:parsed }
    end

    it "should allow blanks thorugh " do
      provider.parse_line("").should ==
        { :line=>"", :record_type=>:blank }
    end

    it "should parse keys with dots " do
      provider.parse_line("auto_explain.log_min_duration = 1ms").should ==
        { :name => "auto_explain.log_min_duration", :value => "1ms", :comment => nil, :record_type => :parsed }
    end
  end

  describe "configuration that should be set" do
    it "should set comment lines" do
      provider.to_line({ :line=>"# dont mind me", :record_type=>:comment }).should ==
        '# dont mind me'
    end

    it "should set blank lines" do
      provider.to_line({ :line=>"", :record_type=>:blank }).should ==
        ''
    end

    it "should set simple configuration" do
      provider.to_line({:name=>"listen_addresses", :value=>"*", :comment=>nil, :record_type=>:parsed }).should ==
        "listen_addresses = '*'"
    end

    it "should set simple configuration with period in name" do
      provider.to_line({:name => "auto_explain.log_min_duration", :value => '100ms', :comment => nil, :record_type => :parsed }).should ==
        "auto_explain.log_min_duration = 100ms"
    end

    it "should set simple configuration even with comments" do
      provider.to_line({:name=>"listen_addresses", :value=>"*", :comment=>'dont mind me', :record_type=>:parsed }).should ==
        "listen_addresses = '*' # dont mind me"
    end

    it 'should quote includes' do
      provider.to_line( {:name=>"include", :value=>"puppetextra", :comment=>nil, :record_type=>:parsed }).should ==
        "include 'puppetextra'"
    end

    it 'should quote multiple words' do
      provider.to_line( {:name=>"archive_command", :value=>"rsync up", :comment=>nil, :record_type=>:parsed }).should ==
        "archive_command = 'rsync up'"
    end

    it 'shouldn\'t quote numbers' do
      provider.to_line( {:name=>"wal_segments", :value=>"32", :comment=>nil, :record_type=>:parsed }).should ==
        "wal_segments = 32"
    end
  end
end

require 'spec_helper'

describe Puppet::Type.type(:postgresql_psql).provider(:ruby) do
  let(:name) { 'rspec psql test' }
  let(:resource) do
    Puppet::Type.type(:postgresql_psql).new({ :name => name, :provider => :ruby }.merge attributes)
  end

  let(:provider) { resource.provider }

  context("#run_sql_command") do
    describe "with default attributes" do
      let(:attributes) do { :db => 'spec_db' } end

      it "executes with the given psql_path on the given DB" do
        expect(provider).to receive(:run_command).with(['psql', '-d',
          attributes[:db], '-t', '-c', 'SELECT something'], 'postgres',
          'postgres')

        provider.run_sql_command("SELECT something")
      end
    end
    describe "with psql_path and db" do
      let(:attributes) do {
        :psql_path  => '/opt/postgres/psql',
        :psql_user  => 'spec_user',
        :psql_group => 'spec_group',
        :cwd        => '/spec',
        :db         => 'spec_db'
      } end

      it "executes with the given psql_path on the given DB" do
        expect(Dir).to receive(:chdir).with(attributes[:cwd]).and_yield
        expect(provider).to receive(:run_command).with([attributes[:psql_path],
          '-d', attributes[:db], '-t', '-c', 'SELECT something'],
          attributes[:psql_user], attributes[:psql_group])

        provider.run_sql_command("SELECT something")
      end
    end
    describe "with search_path string" do
      let(:attributes) do {
        :search_path => "schema1"
      } end

      it "executes with the given search_path" do
        expect(provider).to receive(:run_command).with(['psql', '-t', '-c',
          'set search_path to schema1; SELECT something'],
          'postgres', 'postgres')

        provider.run_sql_command("SELECT something")
      end
    end
    describe "with search_path array" do
      let(:attributes) do {
        :search_path => ['schema1','schema2'],
      } end

      it "executes with the given search_path" do
        expect(provider).to receive(:run_command).with(['psql', '-t', '-c',
          'set search_path to schema1,schema2; SELECT something'],
          'postgres',
          'postgres'
        )

        provider.run_sql_command("SELECT something")
      end
    end

  end

  context("#command") do
    context "when unless is specified" do
      [:true, :false, true, false].each do |refresh|
        context "and refreshonly is #{refresh}" do
          let(:attributes) { {
            :command     => 'SELECT something',
            :db          => 'spec_db',
            :unless      => 'SELECT something',
            :refreshonly => refresh
          } }

          it "does not fail when the status is successful" do
            expect(provider).to receive(:run_unless_sql_command).and_return ["1 row returned", 0]
            provider.command
          end

          it "returns the given command when rows are returned" do
            expect(provider).to receive(:run_unless_sql_command).and_return ["1 row returned", 0]
            expect(provider.command).to eq("SELECT something")
          end

          it "does not return the given command when no rows are returned" do
            expect(provider).to receive(:run_unless_sql_command).and_return ["0 rows returned", 0]
            expect(provider.command).to_not eq("SELECT something")
          end

          it "raises an error when the sql command fails" do
            allow(provider).to receive(:run_unless_sql_command).and_return ["Something went wrong", 1]
            expect { provider.command }.to raise_error(Puppet::Error, /Something went wrong/)
          end
        end
      end
    end

    context "when unless is not specified" do
      context "and refreshonly is true" do
        let(:attributes) do {
          :command     => 'SELECT something',
          :db          => 'spec_db',
          :refreshonly => :true
        } end
        it "does not run unless sql command" do
          expect(provider).to_not receive(:run_unless_sql_command)
          provider.command
        end

        it "returns the given command do disable sync" do
          expect(provider.command).to eq("SELECT something")
        end
      end

      context "and refreshonly is false" do
        let(:attributes) do {
          :command     => 'SELECT something',
          :db          => 'spec_db',
          :refreshonly => :false
        } end
        it "does not run unless sql command" do
          expect(provider).to_not receive(:run_unless_sql_command)
          provider.command
        end

        it "does not return the command so as to enable sync" do
          expect(provider.command).to_not eq("SELECT something")
        end
      end
    end
  end
end
require 'spec_helper'

describe Puppet::Type.type(:postgresql_psql), "when validating attributes" do
  [:name, :unless, :db, :psql_path, :psql_user, :psql_group].each do |attr|
    it "should have a #{attr} parameter" do
      expect(Puppet::Type.type(:postgresql_psql).attrtype(attr)).to eq(:param)
    end
  end

  [:command].each do |attr|
    it "should have a #{attr} property" do
      expect(Puppet::Type.type(:postgresql_psql).attrtype(attr)).to eq(:property)
    end
  end
end

describe Puppet::Type.type(:postgresql_psql), :unless => Puppet.features.microsoft_windows? do
  subject do
    Puppet::Type.type(:postgresql_psql).new({:name => 'rspec'}.merge attributes)
  end

  describe "available attributes" do
    {
      :name        => "rspec",
      :command     => "SELECT stuff",
      :unless      => "SELECT other,stuff",
      :db          => "postgres",
      :psql_path   => "/bin/false",
      :psql_user   => "postgres",
      :psql_group  => "postgres",
      :cwd         => "/var/lib",
      :refreshonly => :true,
      :search_path => [ "schema1", "schema2"]
    }.each do |attr, value|
      context attr do
        let(:attributes) do { attr => value } end
        its([attr]) { should == value }
      end
    end

    context "default values" do
      let(:attributes) do {} end
      its([:psql_path]) { should eq("psql") }
      its([:psql_user]) { should eq("postgres") }
      its([:psql_group]) { should eq("postgres") }
      its([:cwd]) { should eq("/tmp") }
      its(:refreshonly?) { should be_false }
    end
  end

  describe "#refreshonly" do
    [true, :true].each do |refreshonly|
      context "=> #{refreshonly.inspect}" do
        let(:attributes) do { :refreshonly => refreshonly } end
        it "has a value of true" do
          expect(subject.refreshonly?).to be_true
        end
        it "will not enforce command on sync because refresh() will be called" do
          expect(subject.provider).to_not receive(:command=)
          subject.property(:command).sync
        end
      end
    end

    [false, :false].each do |refreshonly|
      context "=> #{refreshonly.inspect}" do
        let(:attributes) do { :refreshonly => refreshonly } end
        it "has a value of false" do
          expect(subject.refreshonly?).to be_false
        end
        it "will enforce command on sync because refresh() will not be called" do
          expect(subject.provider).to receive(:command=)
          subject.property(:command).sync
        end
      end
    end
  end

  ## If we refresh the resource, the command should always be run regardless of
  ## refreshonly
  describe "when responding to refresh" do
    [true, :true, false, :false].each do |refreshonly|
      context "with refreshonly => #{refreshonly.inspect}" do
        let(:attributes) do { :refreshonly => refreshonly } end
        it "will enforce command on sync" do
          expect(subject.provider).to receive(:command=)
          subject.refresh
        end
      end
    end
  end
end
#! /usr/bin/env ruby
require 'spec_helper'

describe Puppet::Type.type(:postgresql_conf) do
  before do
    @provider_class = described_class.provide(:simple) { mk_resource_methods }
    @provider_class.stubs(:suitable?).returns true
    described_class.stubs(:defaultprovider).returns @provider_class
  end

  describe "namevar validation" do
    it "should have :name as its namevar" do
      described_class.key_attributes.should == [:name]
    end
    it "should not invalid names" do
      expect { described_class.new(:name => 'foo bar') }.to raise_error(Puppet::Error, /Invalid value/)
    end
    it "should allow dots in names" do
      expect { described_class.new(:name => 'foo.bar') }.to_not raise_error
    end
  end

  describe "when validating attributes" do
    [:name, :provider].each do |param|
      it "should have a #{param} parameter" do
        described_class.attrtype(param).should == :param
      end
    end

    [:value, :target].each do |property|
      it "should have a #{property} property" do
        described_class.attrtype(property).should == :property
      end
    end
  end

  describe "when validating values" do
    describe "ensure" do
      it "should support present as a value for ensure" do
        expect { described_class.new(:name => 'foo', :ensure => :present) }.to_not raise_error
      end
      it "should support absent as a value for ensure" do
        expect { described_class.new(:name => 'foo', :ensure => :absent) }.to_not raise_error
      end
      it "should not support other values" do
        expect { described_class.new(:name => 'foo', :ensure => :foo) }.to raise_error(Puppet::Error, /Invalid value/)
      end
    end
  end
end

# Rule Name: <%=@name%>
# Description: <%=@description%>
# Order: <%=@order%>
<%=@type%>	<%=@database%>	<%=@user%>	<%=@address%>	<%=@auth_method%>	<%=@auth_option%>
The MIT License (MIT)

Copyright (c) 2013 Juan Treminio and other contributors
https://puphpet.com

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
# Puppet module: puphpet

This is a Puppet module for [PuPHPet](https://puphpet.com)-related code
#!/bin/bash
XDEBUG_CONFIG="idekey=xdebug" php -dxdebug.remote_host=`echo $SSH_CLIENT | cut -d "=" -f 2 | awk '{print $1}'` "$@"
#
# hash_key_equals.rb
#

module Puppet::Parser::Functions

  newfunction(:hash_key_equals, :type => :rvalue, :doc => <<-'ENDHEREDOC') do |args|

    Returns true if the variable passed to this function is a hash,
    it contains the key requested, and the key matches value.
    ENDHEREDOC

    unless args.length == 3
      raise Puppet::ParseError, ("hash_key_equals(): wrong number of arguments (#{args.length}; must be 3)")
    end

    hashVar       = args[0]
    keyVar        = args[1]
    expectedValue = args[2]

    unless hashVar.is_a?(Hash)
      return false
    end

    unless hashVar.has_key?(keyVar)
      return false
    end

    unless hashVar[keyVar].to_i == expectedValue.to_i
      return false
    end

    return true

  end
end
#
# hash_key_true.rb
#

module Puppet::Parser::Functions

  newfunction(:hash_key_true, :type => :rvalue, :doc => <<-'ENDHEREDOC') do |args|

    Returns true if the key within hash is truthy
    ENDHEREDOC

    unless args.length == 2
      raise Puppet::ParseError, ("hash_key_true(): wrong number of arguments (#{args.length}; must be 2)")
    end

    arr = args[0]
    key = args[1]

    unless arr.is_a?(Hash)
      return false
    end

    unless arr.has_key?(key)
      return false
    end

    if arr[key].nil?
      return false
    end

    if arr[key] == false
      return false
    end

    if arr[key] == 'false'
      return false
    end

    if arr[key].empty?
      return false
    end

    return true

  end
end
#
# value_true.rb
#

module Puppet::Parser::Functions

  newfunction(:value_true, :type => :rvalue, :doc => <<-'ENDHEREDOC') do |args|

    Returns true if value is truthy
    ENDHEREDOC

    unless args.length == 1
      raise Puppet::ParseError, ("value_true(): wrong number of arguments (#{args.length}; must be 1)")
    end

    value = args[0]

    if value.nil?
      return false
    end

    if value == false
      return false
    end

    if value == 0
      return false
    end

    if value == '0'
      return false
    end

    if value == 'false'
      return false
    end

    if value.empty?
      return false
    end

    return true

  end
end
require 'puppet/provider/package'

# Lifted from https://github.com/willdurand/puppet-nodejs

Puppet::Type.type(:package).provide :npm, :parent => Puppet::Provider::Package do
  desc "npm is a package management for node.js. This provider only handles global packages."

  has_feature :versionable

  if Puppet::Util::Package.versioncmp(Puppet.version, '3.0') >= 0
    has_command(:npm, '/usr/bin/npm') do
      is_optional
      environment :HOME => "/root"
    end
  else
    optional_commands :npm => 'npm'
  end

  def self.npmlist
    begin
      output = execute([command(:npm), 'list', '--json', '--global'], {:combine => false})
      # ignore any npm output lines to be a bit more robust
      output = PSON.parse(output.lines.select{ |l| l =~ /^((?!^npm).*)$/}.join("\n"))
      @npmlist = output['dependencies'] || {}
    rescue Exception => e
      Puppet.debug("Error: npm list --json command error #{e.message}")
      @npmlist = {}
    end
  end

  def npmlist
    self.class.npmlist
  end

  def self.instances
    @npmlist ||= npmlist
    @npmlist.collect do |k,v|
      new({:name=>k, :ensure=>v['version'], :provider=>'npm'})
    end
  end

  def query
    list = npmlist

    if list.has_key?(resource[:name]) and list[resource[:name]].has_key?('version')
      version = list[resource[:name]]['version']
      { :ensure => version, :name => resource[:name] }
    else
      { :ensure => :absent, :name => resource[:name] }
    end
  end

  def latest
    if /#{resource[:name]}@([\d\.]+)/ =~ npm('outdated', '--global',  resource[:name])
      @latest = $1
    else
      @property_hash[:ensure] unless @property_hash[:ensure].is_a? Symbol
    end
  end

  def update
    resource[:ensure] = @latest
    self.install
  end

  def install
    if resource[:ensure].is_a? Symbol
      package = resource[:name]
    else
      package = "#{resource[:name]}@#{resource[:ensure]}"
    end

    if resource[:source]
      npm('install', '--global', resource[:source])
    else
      npm('install', '--global', package)
    end
  end

  def uninstall
    npm('uninstall', '--global', resource[:name])
  end
end
class puphpet::adminer(
  $location,
  $owner       = 'www-data',
  $php_package = 'php'
) {

  if ! defined(File[$location]) {
    file { $location:
      replace => no,
      ensure  => directory,
      mode    => 775,
      require => Package[$php_package]
    }
  }

  exec{ "download adminer to ${location}":
    command => "wget http://www.adminer.org/latest.php -O ${location}/index.php",
    require => File[$location],
    creates => "${location}/index.php",
    returns => [ 0, 4 ],
  }

}
# Sets up Apache to use fastcgi
# Useful for things like php-fpm or hhvm

class puphpet::apache::fpm {

  include ::puphpet::params
  include ::apache::params

  if $::operatingsystem == 'debian' {
    include ::puphpet::debian::non_free
  }

  if ! defined(Class['apache::mod::mime']) {
    class { 'apache::mod::mime': }
  }
  if ! defined(Class['apache::mod::alias']) {
    class { 'apache::mod::alias': }
  }
  if ! defined(Class['apache::mod::proxy']) {
    class { 'apache::mod::proxy': }
  }
  if ! defined(Class['apache::mod::proxy_http']) {
    class { 'apache::mod::proxy_http': }
  }
  if ! defined(Apache::Mod['proxy_fcgi']) {
    apache::mod{ 'proxy_fcgi': }
  }
  if ! defined(Apache::Mod['actions']) {
    apache::mod{ 'actions': }
  }

}
# This depends on puppetlabs/apache: https://github.com/puppetlabs/puppetlabs-apache

class puphpet::apache::modpagespeed (
  $url     = $puphpet::params::apache_mod_pagespeed_url,
  $package = $puphpet::params::apache_mod_pagespeed_package,
  $ensure  = 'present'
) {

  $download_location = $::osfamily ? {
    'Debian' => '/.puphpet-stuff/mod-pagespeed.deb',
    'Redhat' => '/.puphpet-stuff/mod-pagespeed.rpm'
  }

  $provider = $::osfamily ? {
    'Debian' => 'dpkg',
    'Redhat' => 'yum'
  }

  exec { "download apache mod-pagespeed to ${download_location}":
    creates => $download_location,
    command => "wget ${url} -O ${download_location}",
    timeout => 30,
    path    => '/usr/bin'
  }

  package { $package:
    ensure   => $ensure,
    provider => $provider,
    source   => $download_location,
    notify   => Service['httpd']
  }

  file { "${apache::params::mod_dir}/pagespeed.conf":
    purge => false,
  }

  if $apache::params::mod_enable_dir != undef {
    file { "${apache::params::mod_enable_dir}/pagespeed.conf":
      purge => false,
    }
  }

  if ! defined(Apache::Mod['pagespeed']) {
    apache::mod{ 'pagespeed':
      require => Package[$package],
    }
  }

  $pagespeed_load = "${apache::params::mod_dir}/pagespeed.load"

  exec { 'mod_pagespeed httpd 2.4':
    command => "perl -p -i -e 's#mod_pagespeed.so#mod_pagespeed_ap24.so#gi' ${pagespeed_load}",
    onlyif  => "test -f ${pagespeed_load}",
    unless  => "grep -x 'mod_pagespeed_ap24.so' ${pagespeed_load}",
    path    => [ '/bin/', '/sbin/', '/usr/bin/', '/usr/sbin/' ],
    require => Apache::Mod['pagespeed'],
    notify  => Service['httpd']
  }

}
# Adds non-free repos to Debian
# A bit hacky but works well
#
# This depends on
#   puppetlabs/apt: https://github.com/puppetlabs/puppetlabs-apt

class puphpet::debian::non_free (
  $release = $::lsbdistcodename
) {

  $sources_list = '/etc/apt/sources.list'

  $deb_srcs = [
    "deb http://http.us.debian.org/debian ${release} main",
    "deb-src http://http.us.debian.org/debian ${release} main",
    "deb http://security.debian.org/ ${release}/updates main",
    "deb-src http://security.debian.org/ ${release}/updates main",
    "deb http://http.us.debian.org/debian ${release}-updates main",
    "deb-src http://http.us.debian.org/debian ${release}-updates main",
    "deb http://http.debian.net/debian ${release} main",
    "deb-src http://http.debian.net/debian ${release} main",
    "deb http://http.debian.net/debian ${release}-updates main",
    "deb-src http://http.debian.net/debian ${release}-updates main",
  ]

  each( $deb_srcs ) |$value| {
    exec { "add contrib non-free to ${value}":
      command => "perl -p -i -e 's#${value}#${value} contrib non-free#gi' ${sources_list}",
      onlyif  => "grep -x '${value}' ${sources_list}",
      path    => [ '/bin/', '/sbin/', '/usr/bin/', '/usr/sbin/' ],
      notify  => Exec['apt_update'],
    }
  }

}
# This depends on
#   puppetlabs/apt: https://github.com/puppetlabs/puppetlabs-apt
#   example42/puppet-yum: https://github.com/example42/puppet-yum
#   puppetlabs/puppetlabs-apache: https://github.com/puppetlabs/puppetlabs-apache (if apache)

class puphpet::hhvm(
  $nightly = false,
  $webserver
) {

  $real_webserver = $webserver ? {
    'apache'  => 'apache2',
    'httpd'   => 'apache2',
    'apache2' => 'apache2',
    'nginx'   => 'nginx',
    'fpm'     => 'fpm',
    'cgi'     => 'cgi',
    'fcgi'    => 'cgi',
    'fcgid'   => 'cgi',
    undef     => undef,
  }

  if $nightly == true {
    $package_name_base = $puphpet::params::hhvm_package_name_nightly
  } else {
    $package_name_base = $puphpet::params::hhvm_package_name
  }

  if $nightly == true and $::osfamily == 'Redhat' {
    warning('HHVM-nightly is not available for RHEL distros. Falling back to normal release')
  }

  case $::operatingsystem {
    'debian': {
      if $::lsbdistcodename != 'wheezy' {
        fail('Sorry, HHVM currently only works with Debian 7+.')
      }

      include ::puphpet::debian::non_free
    }
    'ubuntu': {
      if ! ($lsbdistcodename in ['precise', 'raring', 'trusty']) {
        fail('Sorry, HHVM currently only works with Ubuntu 12.04, 13.10 and 14.04.')
      }

      apt::key { '5D50B6BA': key_server => 'hkp://keyserver.ubuntu.com:80' }

      if $lsbdistcodename in ['lucid', 'precise'] {
        apt::ppa { 'ppa:mapnik/boost': require => Apt::Key['5D50B6BA'], options => '' }
      }
    }
    'centos': {
      $require = defined(Class['my_fw::post']) ? {
        true    => Class['my_fw::post'],
        default => [],
      }

      package { 'jemalloc':
        ensure   => latest,
        provider => yum,
      }

      yum::managed_yumrepo { 'hop5':
        descr    => 'hop5 repository',
        baseurl  => 'http://www.hop5.in/yum/el6/',
        gpgkey   => 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-HOP5',
        enabled  => 1,
        gpgcheck => 0,
        priority => 1,
      }
    }
  }
  if $real_webserver == 'apache2' {
    include ::puphpet::apache::fpm
  }

  $os = downcase($::operatingsystem)

  case $::osfamily {
    'debian': {
      apt::key { 'hhvm':
        key        => '16d09fb4',
        key_source => 'http://dl.hhvm.com/conf/hhvm.gpg.key',
      }

      apt::source { 'hhvm':
        location          => "http://dl.hhvm.com/${os}",
        repos             => 'main',
        required_packages => 'debian-keyring debian-archive-keyring',
        include_src       => false,
        require           => Apt::Key['hhvm']
      }
    }
  }

  if ! defined(Package[$package_name_base]) {
    package { $package_name_base:
      ensure => present
    }
  }

}
define puphpet::ini (
  $php_version,
  $webserver,
  $ini_filename = 'zzzz_custom.ini',
  $entry,
  $value        = '',
  $ensure       = present
) {

  warning('puphpet::ini is deprecated; please use puphpet::php::ini')

  ::puphpet::php::ini { $name:
    php_version  => $php_version,
    webserver    => $webserver,
    ini_filename => $ini_filename,
    entry        => $entry,
    value        => $value,
    ensure       => $ensure,
  }
}
class puphpet inherits puphpet::params {}
# This depends on
#   puppetlabs/apt: https://github.com/puppetlabs/puppetlabs-apt
#   example42/puppet-yum: https://github.com/example42/puppet-yum

class puphpet::mariadb(
  $distro  = $::operatingsystem,
  $release = $::lsbdistcodename,
  $arch    = $::architecture,
  $version = '10.0',
  $url     = $puphpet::params::apache_mod_pagespeed_url,
  $package = $puphpet::params::apache_mod_pagespeed_package
) {

  $arch_package_name = $::architecture ? {
    'i386'   => 'x86',
    'amd64'  => 'amd64',
    'x86_64' => 'amd64'
  }

  case $::osfamily {
    'debian': {
      $os = downcase($::operatingsystem)

      apt::source { 'mariadb':
        location          => "http://mirror.jmu.edu/pub/mariadb/repo/${version}/${os}",
        release           => $release,
        repos             => 'main',
        required_packages => 'debian-keyring debian-archive-keyring',
        key               => '1BB943DB',
        key_server        => 'hkp://keyserver.ubuntu.com:80',
        include_src       => true
      }

      apt::pin { 'mariadb':
        packages => '*',
        priority => 1000,
        origin   => 'mirror.jmu.edu',
      }
    }
    'redhat': {
      yum::managed_yumrepo { 'MariaDB':
        descr         => 'MariaDB - mariadb.org',
        baseurl       => "http://yum.mariadb.org/${version}/centos6-${arch_package_name}",
        enabled       => 1,
        gpgcheck      => 0,
        priority      => 1
      }
    }
  }
}
# This depends on puppetlabs-puppet-mysql: https://github.com/puppetlabs/puppetlabs-mysql

define puphpet::mysql::db (
  $dbname,
  $user,
  $password,
  $host,
  $grant    = [],
  $sql_file = false
) {
  if ! value_true($dbname) or ! value_true($password) or ! value_true($host) {
    fail( 'DB requires that name, password and host be set. Please check your settings!' )
  }

  include ::mysql::params

  if ! defined(Mysql_database[$dbname]) {
    $db_resource = {
      ensure   => present,
      charset  => 'utf8',
      collate  => 'utf8_general_ci',
      provider => 'mysql',
      require  => [
        Class['::mysql::server'],
        Class['::mysql::client']
      ],
    }
    ensure_resource('mysql_database', $dbname, $db_resource)
  }

  if ! defined(Mysql_user[$user]) {
    $user_resource = {
      ensure        => present,
      password_hash => mysql_password($password),
      provider      => 'mysql',
      require       => Class['::mysql::server'],
    }
    ensure_resource('mysql_user', "${user}@${host}", $user_resource)
  }

  $table = "${dbname}.*"

  if ! defined(Mysql_grant["${user}@${host}/${table}"]) {
    mysql_grant { "${user}@${host}/${table}":
      privileges => $grant,
      provider   => 'mysql',
      user       => "${user}@${host}",
      table      => $table,
      require    => [
        Mysql_database[$dbname],
        Mysql_user["${user}@${host}"],
        Class['::mysql::server']
      ],
    }
  }

  if $sql_file {
    exec{ "${dbname}-import":
      command     => "/usr/bin/mysql ${dbname} < ${sql_file}",
      onlyif      => "test -f ${sql_file}",
      logoutput   => true,
      environment => "HOME=${::root_home}",
      refreshonly => true,
      require     => Mysql_grant["${user}@${host}/${table}"],
      subscribe   => Mysql_database[$dbname],
    }
  }

}
class puphpet::nginx(
  $fastcgi_pass = '127.0.0.1:9000',
  $webroot      = $puphpet::params::nginx_webroot_location
) inherits puphpet::params {

  $conf_file = $::osfamily ? {
    'debian' => '/etc/nginx/conf.d/default.conf',
    'redhat' => '/etc/nginx/conf.d/default.conf',
    default  => '/etc/nginx/conf.d/default.conf',
  }

  file { [
      '/var/log',
      '/var/log/nginx',
      '/var/log/nginx/log'
    ]:
    ensure  => directory,
    recurse => true,
  }

  file { [
      '/var/log/nginx/log/host.access.log',
      '/var/log/nginx/log/host.error.log'
    ]:
    ensure  => present,
    mode    => 0777,
    replace => 'no',
    require => File['/var/log/nginx/log']
  }

  file {"${conf_file} puphpet::nginx override":
    ensure  => present,
    path    => $conf_file,
    replace => 'yes',
    content => template('puphpet/nginx/default_conf.erb')
  }

}
# Installs node.js and npm

class puphpet::nodejs {

  file { '/.puphpet-stuff/node_install.sh':
    ensure  => present,
    owner   => root,
    mode    => 0755,
    content => template("${module_name}/nodejs/install.erb"),
  }
  -> exec { 'install-node':
    command => '/.puphpet-stuff/node_install.sh',
    creates => '/usr/bin/node',
  }

}
class puphpet::params {

  $xdebug_package = $::osfamily ? {
    'Debian' => 'php5-xdebug',
    'Redhat' => 'php-pecl-xdebug'
  }

  $xhprof_package = $::osfamily ? {
    'Debian' => $::operatingsystem ? {
      'ubuntu' => false,
      'debian' => 'php5-xhprof'
    },
    'Redhat' => 'xhprof'
  }

  $apache_webroot_location = $::osfamily ? {
    'Debian' => '/var/www',
    'Redhat' => '/var/www/html'
  }

  $apache_mod_pagespeed_url = $::osfamily ? {
    'Debian' => $::architecture ? {
        'i386'   => 'https://dl-ssl.google.com/dl/linux/direct/mod-pagespeed-stable_current_i386.deb',
        'amd64'  => 'https://dl-ssl.google.com/dl/linux/direct/mod-pagespeed-stable_current_amd64.deb',
        'x86_64' => 'https://dl-ssl.google.com/dl/linux/direct/mod-pagespeed-stable_current_amd64.deb'
      },
    'Redhat' => $::architecture ? {
        'i386'   => 'https://dl-ssl.google.com/dl/linux/direct/mod-pagespeed-stable_current_i386.rpm',
        'amd64'  => 'https://dl-ssl.google.com/dl/linux/direct/mod-pagespeed-stable_current_x86_64.rpm',
        'x86_64' => 'https://dl-ssl.google.com/dl/linux/direct/mod-pagespeed-stable_current_x86_64.rpm'
      },
  }

  $apache_mod_pagespeed_package = 'mod-pagespeed-stable'

  $nginx_default_conf_location = $::osfamily ? {
    'Debian' => '/etc/nginx/conf.d/default.conf',
    'Redhat' => '/etc/nginx/conf.d/default.conf'
  }

  $nginx_webroot_location = $::osfamily ? {
    'Debian' => '/var/www/html',
    'Redhat' => '/var/www/html'
  }

  $mariadb_package_client_name = $::osfamily ? {
    'Debian' => 'mariadb-client',
    'Redhat' => 'MariaDB-client',
  }

  $mariadb_package_server_name = $::osfamily ? {
    'Debian' => 'mariadb-server',
    'Redhat' => 'MariaDB-server',
  }

  $hhvm_package_name = 'hhvm'
  $hhvm_package_name_nightly = $::osfamily ? {
    'Debian' => 'hhvm-nightly',
    'Redhat' => 'hhvm'
  }

  $ssl_cert_location = $::osfamily ? {
    'Debian' => '/etc/ssl/certs/ssl-cert-snakeoil.pem',
    'Redhat' => '/etc/ssl/certs/ssl-cert-snakeoil'
  }

  $ssl_key_location = $::osfamily ? {
    'Debian' => '/etc/ssl/private/ssl-cert-snakeoil.key',
    'Redhat' => '/etc/ssl/certs/ssl-cert-snakeoil'
  }

  $php_fpm_conf = $::osfamily ? {
    'Debian' => '/etc/php5/fpm/pool.d/www.conf',
    'Redhat' => '/etc/php-fpm.d/www.conf',
  }

  $php_cgi_package = $::osfamily ? {
    'Debian' => 'php5-cgi',
    'Redhat' => 'php-cgi'
  }

}
class puphpet::php::composer (
  $php_package   = 'php',
  $composer_home = false
){

  $composer_home_real = $composer_home ? {
    false   => false,
    undef   => false,
    ''      => false,
    default => $composer_home,
  }

  if $composer_home_real {
    file { $composer_home_real:
      ensure  => directory,
      owner   => 'www-data',
      group   => 'www-data',
      mode    => 0775,
      require => [
        Group['www-data'],
        Group['www-user']
      ],
    }

    file_line { "COMPOSER_HOME=${composer_home_real}":
      path => '/etc/environment',
      line => "COMPOSER_HOME=${composer_home_real}",
    }
  }

  class { '::composer':
    target_dir      => '/usr/local/bin',
    composer_file   => 'composer',
    download_method => 'curl',
    logoutput       => false,
    tmp_path        => '/tmp',
    php_package     => $php_package,
    curl_package    => 'curl',
    suhosin_enabled => false,
  }

}
/*
 * Some PHP packages require extra repos.
 * ex: PECL mongo is best to fetch Mongo's official repo
 */

define puphpet::php::extra_repos {

  $downcase_name = downcase($name)

  if $downcase_name == 'mongo' and ! defined(Class['mongodb::globals']) {
    class { 'mongodb::globals':
      manage_package_repo => true,
    }
  }

}
# Defines where we can expect PHP ini files and paths to be located.
#
# Different OS, OS version, webserver and PHP versions all contributes
# to making a mess of where we can expect INI files to be found.
#
# I have listed a bunch of places:
#
# 5.3
#     DEBIAN 6 - squeeze
#         CLI
#             /etc/php5/cli/conf.d        -> /etc/php5/conf.d
#         APACHE
#             FOLDERS: apache2/  cli/  conf.d/  php.ini
#             /etc/php5/apache2/conf.d    -> /etc/php5/conf.d
#         NGINX
#             FOLDERS: cli/  conf.d/  fpm/
#             /etc/php5/fpm/conf.d        -> /etc/php5/conf.d
#     DEBIAN 7 - wheezy
#         APACHE
#             NOT CORRECT; PHP 5.4 INSTALLED
#         NGINX
#             NOT CORRECT; PHP 5.4 INSTALLED
#     UBUNTU 10.04 - lucid
#         CLI
#             /etc/php5/cli/conf.d        -> /etc/php5/conf.d
#         APACHE
#             FOLDERS: apache2/  cli/  conf.d/  php.ini
#             /etc/php5/apache2/conf.d    -> /etc/php5/conf.d
#         NGINX
#             FOLDERS: cli/  conf.d/  fpm/
#             /etc/php5/fpm/conf.d        -> /etc/php5/conf.d
#     UBUNTU 12.04 - precise
#         CLI
#             /etc/php5/cli/conf.d        -> /etc/php5/conf.d
#         APACHE
#             FOLDERS: apache2/  cli/  conf.d/  php.ini
#             /etc/php5/apache2/conf.d    -> /etc/php5/conf.d
#         NGINX
#             FOLDERS: cli/  conf.d/  fpm/
#             /etc/php5/fpm/conf.d        -> /etc/php5/conf.d
#     UBUNTU 14.04 - trusty
#         APACHE
#             NOT CORRECT; PHP 5.5 INSTALLED
#         NGINX
#             NOT CORRECT; PHP 5.5 INSTALLED
# 5.4
#     CENTOS 6
#         CLI
#             /etc/php.d
#         APACHE
#             /etc/php.d
#     DEBIAN 6 - squeeze
#         CLI
#             /etc/php5/cli/conf.d        -> /etc/php5/conf.d/*   -> /etc/php5/mods-available/*
#         APACHE
#             FOLDERS: apache2/  cli/  conf.d/  mods-available/  php.ini
#             /etc/php5/apache2/conf.d    -> /etc/php5/conf.d/*   -> /etc/php5/mods-available/*
#         NGINX
#             FOLDERS: cli/  conf.d/  fpm/  mods-available/
#             /etc/php5/fpm/conf.d        -> /etc/php5/conf.d/*   -> /etc/php5/mods-available/*
#     DEBIAN 7 - wheezy
#         CLI
#             /etc/php5/cli/conf.d        -> /etc/php5/conf.d/*   -> /etc/php5/mods-available/*
#         APACHE
#             FOLDERS: apache2/  cli/  conf.d/  mods-available/  php.ini
#             /etc/php5/apache2/conf.d    -> /etc/php5/conf.d/*   -> /etc/php5/mods-available/*
#         NGINX
#             FOLDERS: cli/  conf.d/  fpm/  mods-available/
#             /etc/php5/fpm/conf.d        -> /etc/php5/conf.d/*   -> /etc/php5/mods-available/*
#     UBUNTU 10.04 - lucid
#         CLI
#             /etc/php5/cli/conf.d        -> /etc/php5/conf.d/*   -> /etc/php5/mods-available/*
#         APACHE
#             FOLDERS: apache2/  cli/  conf.d/  mods-available/  php.ini
#             /etc/php5/apache2/conf.d    -> /etc/php5/conf.d/*   -> /etc/php5/mods-available/*
#         NGINX
#             FOLDERS: cli/  conf.d/  fpm/  mods-available/
#             /etc/php5/fpm/conf.d        -> /etc/php5/conf.d/*   -> /etc/php5/mods-available/*
#     UBUNTU 12.04 - precise
#         CLI
#             /etc/php5/cli/conf.d        -> /etc/php5/conf.d/*   -> /etc/php5/mods-available/*
#         APACHE
#             FOLDERS: apache2/  cli/  conf.d/  mods-available/  php.ini
#             /etc/php5/apache2/conf.d    -> /etc/php5/conf.d/*   -> /etc/php5/mods-available/*
#         NGINX
#             FOLDERS: cli/  conf.d/  fpm/  mods-available/
#             /etc/php5/fpm/conf.d        -> /etc/php5/conf.d/*   -> /etc/php5/mods-available/*
#     UBUNTU 14.04 - trusty
#         APACHE
#             NOT CORRECT; PHP 5.5 INSTALLED
#         NGINX
#             NOT CORRECT; PHP 5.5 INSTALLED
# 5.5
#     DEBIAN 6 - squeeze
#         APACHE
#             NOT A VALID OPTION
#         NGINX
#             NOT A VALID OPTION
#     DEBIAN 7 - wheezy
#         CLI
#             /etc/php5/cli/conf.d/*      -> /etc/php5/mods-available/*
#         APACHE
#             FOLDERS: apache2/  cli/  mods-available/  php.ini
#             /etc/php5/apache2/conf.d/*  -> /etc/php5/mods-available/*
#         NGINX
#             FOLDERS: cli/  fpm/  mods-available/
#             /etc/php5/fpm/conf.d/*      -> /etc/php5/mods-available/*
#     UBUNTU 10.04 - lucid
#         APACHE
#             NOT A VALID OPTION
#         NGINX
#             NOT A VALID OPTION
#     UBUNTU 12.04 - precise
#         CLI
#             /etc/php5/cli/conf.d/*      -> /etc/php5/mods-available/*
#         APACHE
#             FOLDERS: cli/  apache2/  mods-available/
#             /etc/php5/apache2/conf.d/*      -> /etc/php5/mods-available/*
#         NGINX
#             FOLDERS: cli/  fpm/  mods-available/
#             /etc/php5/fpm/conf.d/*      -> /etc/php5/mods-available/*
#     UBUNTU 14.04 - trusty
#         CLI
#             /etc/php5/cli/conf.d/*      -> /etc/php5/conf.d/*
#         APACHE
#             FOLDERS: apache2/  cli/  mods-available/  php.ini
#             /etc/php5/cli/conf.d/*      -> /etc/php5/mods-available/*
#             /etc/php5/apache2/conf.d/*  -> /etc/php5/mods-available/*
#         NGINX
#             FOLDERS: cli/  fpm/  mods-available/
#             /etc/php5/cli/conf.d/*      -> /etc/php5/mods-available/*
#             /etc/php5/fpm/conf.d/*      -> /etc/php5/mods-available/*
#
# This depends on example42/puppet-php: https://github.com/example42/puppet-php
#
define puphpet::php::ini (
  $php_version,
  $webserver,
  $ini_filename = 'zzzz_custom.ini',
  $entry,
  $value  = '',
  $ensure = present
  ) {

  $real_webserver = $webserver ? {
    'apache'   => 'apache2',
    'httpd'    => 'apache2',
    'apache2'  => 'apache2',
    'nginx'    => 'fpm',
    'php5-fpm' => 'fpm',
    'php-fpm'  => 'fpm',
    'fpm'      => 'fpm',
    'cgi'      => 'cgi',
    'fcgi'     => 'cgi',
    'fcgid'    => 'cgi',
    undef      => undef,
  }

  case $php_version {
    '5.3', '53': {
      case $::osfamily {
        'debian': {
          $target_dir  = '/etc/php5/conf.d'
          $target_file = "${target_dir}/${ini_filename}"

          if ! defined(File[$target_file]) {
            file { $target_file:
              replace => no,
              ensure  => present,
              require => Package['php']
            }
          }
        }
        'redhat': {
          $target_dir  = '/etc/php.d'
          $target_file = "${target_dir}/${ini_filename}"

          if ! defined(File[$target_file]) {
            file { $target_file:
              replace => no,
              ensure  => present,
              require => Package['php']
            }
          }
        }
        default: { fail('This OS has not yet been defined for PHP 5.3!') }
      }
    }
    '5.4', '54': {
      case $::osfamily {
        'debian': {
          $target_dir  = '/etc/php5/mods-available'
          $target_file = "${target_dir}/${ini_filename}"

          if ! defined(File[$target_file]) {
            file { $target_file:
              replace => no,
              ensure  => present,
              require => Package['php']
            }
          }

          $symlink = "/etc/php5/conf.d/${ini_filename}"

          if ! defined(File[$symlink]) {
            file { $symlink:
              ensure  => link,
              target  => $target_file,
              require => File[$target_file],
            }
          }
        }
        'redhat': {
          $target_dir  = '/etc/php.d'
          $target_file = "${target_dir}/${ini_filename}"

          if ! defined(File[$target_file]) {
            file { $target_file:
              replace => no,
              ensure  => present,
              require => Package['php']
            }
          }
        }
        default: { fail('This OS has not yet been defined for PHP 5.4!') }
      }
    }
    '5.5', '55', '5.6', '56': {
      case $::osfamily {
        'debian': {
          $target_dir  = '/etc/php5/mods-available'
          $target_file = "${target_dir}/${ini_filename}"

          $webserver_ini_location = $real_webserver ? {
              'apache2' => '/etc/php5/apache2/conf.d',
              'cgi'     => '/etc/php5/cgi/conf.d',
              'fpm'     => '/etc/php5/fpm/conf.d',
              undef     => undef,
          }
          $cli_ini_location = '/etc/php5/cli/conf.d'

          if ! defined(File[$target_file]) {
            file { $target_file:
              replace => no,
              ensure  => present,
              require => Package['php']
            }
          }

          if $webserver_ini_location != undef and ! defined(File["${webserver_ini_location}/${ini_filename}"]) {
            file { "${webserver_ini_location}/${ini_filename}":
              ensure  => link,
              target  => $target_file,
              require => File[$target_file],
            }
          }

          if ! defined(File["${cli_ini_location}/${ini_filename}"]) {
            file { "${cli_ini_location}/${ini_filename}":
              ensure  => link,
              target  => $target_file,
              require => File[$target_file],
            }
          }
        }
        'redhat': {
          $target_dir  = '/etc/php.d'
          $target_file = "${target_dir}/${ini_filename}"

          if ! defined(File[$target_file]) {
            file { $target_file:
              replace => no,
              ensure  => present,
              require => Package['php']
            }
          }
        }
        default: { fail('This OS has not yet been defined for PHP 5.5!') }
      }
    }
    default: { fail('Unrecognized PHP version') }
  }

  if $real_webserver != undef {
    if $real_webserver == 'cgi' {
      $webserver_service = 'apache2'
    } else {
      $webserver_service = $webserver
    }

    $notify_service = Service[$webserver_service]
  } else {
    $notify_service = []
  }

  php::augeas{ "${entry}-${value}" :
    target  => $target_file,
    entry   => $entry,
    value   => $value,
    ensure  => $ensure,
    require => File[$target_file],
    notify  => $notify_service,
  }

}
/*
 * This "translates" PHP module package names into system-specific names.
 */

define puphpet::php::module (
  $service_autorestart
){

  $package = $::osfamily ? {
    'Debian' => {
      'mbstring' => false, # Comes packaged with PHP, not available in repos
    },
    'Redhat' => {
      #
    }
  }

  $downcase_name = downcase($name)

  if has_key($package, $downcase_name) {
    $package_name = $package[$downcase_name]
  }
  else {
    $package_name = $name
  }

  if $package_name and ! defined(::Php::Module[$package_name]) {
    ::php::module { $package_name:
      service_autorestart => $service_autorestart,
    }
  }

}
/*
 * This returns PEAR packages requiring beta stability
 */

define puphpet::php::pear (
  $service_name        = '',
  $service_autorestart,
){

  $package = {
    'auth_sasl2'                => 'beta',
    'config_lite'               => 'beta',
    'console_getoptplus'        => 'beta',
    'mdb2_driver_mysql'         => false,
    'mdb2_driver_mysqli'        => false,
    'pear_command_packaging'    => 'alpha',
    'pear_frontend_gtk2'        => false,
    'php_beautifier'            => 'beta',
    'php_parser'                => 'alpha',
    'php_parser_docblockparser' => 'alpha',
    'soap'                      => 'beta',
    'testing_selenium'          => 'beta',
    'versioncontrol_git'        => 'alpha',
    'versioncontrol_svn'        => 'alpha',
    'xml_parser2'               => 'beta',
    'xml_util2'                 => 'alpha',
  }

  $downcase_name = downcase($name)

  if has_key($package, $downcase_name) {
    $package_name    = $name
    $preferred_state = $package[$downcase_name]
  }
  else {
    $package_name    = $name
    $preferred_state = 'stable'
  }

  if $package_name and $preferred_state and ! defined(::Php::Pear::Module[$package_name]) {
    ::php::pear::module { $name:
      use_package         => false,
      preferred_state     => $preferred_state,
      service             => $service_name,
      service_autorestart => $service_autorestart,
    }
  }

}
/*
 * This "translates" PECL package names into system-specific names.
 * For example, APCu does not install correctly on CentOS via PECL,
 * but there is a system package for it that works well. Use that
 * instead of the PECL package.
 */

define puphpet::php::pecl (
  $service_autorestart
){

  $ignore = {
    'date_time' => true,
    'mysql'     => true,
  }

  $pecl = $::osfamily ? {
    'Debian' => {
      'mongo' => $::lsbdistcodename ? {
        'precise' => 'mongo',
        default   => false,
      },
    },
    'Redhat' => {
      #
    }
  }

  $pecl_beta = $::osfamily ? {
    'Debian' => {
      'augeas'      => 'augeas',
      'zendopcache' => $::operatingsystem ? {
        'debian' => false,
        'ubuntu' => 'ZendOpcache',
      },
    },
    'Redhat' => {
      #
    }
  }

  $package = $::osfamily ? {
    'Debian' => {
      'apc'         => $::operatingsystem ? {
        'debian' => 'php5-apc',
        'ubuntu' => 'php5-apcu',
      },
      'apcu'        => 'php5-apcu',
      'imagick'     => 'php5-imagick',
      'memcache'    => 'php5-memcache',
      'memcached'   => 'php5-memcached',
      'mongo'       => $::lsbdistcodename ? {
        'precise' => false,
        default   => 'php5-mongo',
      },
      'redis'       => 'php5-redis',
      'sqlite'      => 'php5-sqlite',
      'zendopcache' => 'php5-zendopcache',
    },
    'Redhat' => {
      'apc'         => 'php-pecl-apcu',
      'apcu'        => 'php-pecl-apcu',
      'imagick'     => 'php-pecl-imagick',
      'memcache'    => 'php-pecl-memcache',
      'memcached'   => 'php-pecl-memcached',
      'mongo'       => 'php-pecl-mongo',
      'redis'       => 'php-pecl-redis',
      'sqlite'      => 'php-pecl-sqlite',
      'zendopcache' => 'php-pecl-zendopcache',
    }
  }

  $auto_answer_hash = {
    'mongo' => 'no\n'
  }

  $downcase_name = downcase($name)

  if has_key($auto_answer_hash, $downcase_name) {
    $auto_answer = $auto_answer_hash[$downcase_name]
  } else {
    $auto_answer = '\\n'
  }

  if has_key($ignore, $downcase_name) and $ignore[$downcase_name] {
    $pecl_name       = $pecl[$downcase_name]
    $package_name    = false
    $preferred_state = 'stable'
  }
  elsif has_key($pecl, $downcase_name) and $pecl[$downcase_name] {
    $pecl_name       = $pecl[$downcase_name]
    $package_name    = false
    $preferred_state = 'stable'
  }
  elsif has_key($pecl_beta, $downcase_name) and $pecl_beta[$downcase_name] {
    $pecl_name       = $pecl_beta[$downcase_name]
    $package_name    = false
    $preferred_state = 'beta'
  }
  elsif has_key($package, $downcase_name) and $package[$downcase_name] {
    $pecl_name    = false
    $package_name = $package[$downcase_name]
  }
  else {
    $pecl_name    = $name
    $package_name = false
  }

  if $pecl_name and ! defined(::Php::Pecl::Module[$pecl_name]) {
    ::php::pecl::module { $pecl_name:
      use_package         => false,
      preferred_state     => $preferred_state,
      auto_answer         => $auto_answer,
      service_autorestart => $service_autorestart,
    }
  }
  elsif $package_name and ! defined(Package[$package_name]) {
    package { $package_name:
      ensure  => present,
      require => Class['Php::Devel'],
    }
  }

}
# This depends on
#   puppetlabs/apt: https://github.com/puppetlabs/puppetlabs-apt
#   example42/puppet-yum: https://github.com/example42/puppet-yum

class puphpet::php::repos (
  $php_version
){

  case $::operatingsystem {
    'debian': {
      # Squeeze: 5.3 (default) && 5.4
      if $::lsbdistcodename == 'squeeze' and $php_version == '54' {
       ::apt::source { 'packages.dotdeb.org-php54-repo.puphpet':
          location          => 'http://repo.puphpet.com/dotdeb/',
          release           => 'squeeze-php54',
          repos             => 'all',
          required_packages => 'debian-keyring debian-archive-keyring',
          key               => '89DF5277',
          key_server        => 'keys.gnupg.net',
          include_src       => true
        }
      }
      # Wheezy : 5.4 (default) && 5.5 && 5.6
      elsif $::lsbdistcodename == 'wheezy' and $php_version == '55' {
       ::apt::source { 'packages.dotdeb.org-php55-repo.puphpet':
          location          => 'http://repo.puphpet.com/dotdeb/',
          release           => 'wheezy-php55',
          repos             => 'all',
          required_packages => 'debian-keyring debian-archive-keyring',
          key               => '89DF5277',
          key_server        => 'keys.gnupg.net',
          include_src       => true
        }
      }
      elsif $::lsbdistcodename == 'wheezy' and $php_version == '56' {
       ::apt::source { 'packages.dotdeb.org-php56-repo.puphpet':
          location          => 'http://repo.puphpet.com/dotdeb/',
          release           => 'wheezy-php56',
          repos             => 'all',
          required_packages => 'debian-keyring debian-archive-keyring',
          key               => '89DF5277',
          key_server        => 'keys.gnupg.net',
          include_src       => true
        }
      }
    }
    'ubuntu': {
      if ! defined(::Apt::Key['4F4EA0AAE5267A6C']) {
        ::apt::key { '4F4EA0AAE5267A6C':
          key_server => 'hkp://keyserver.ubuntu.com:80'
        }
      }

      # Lucid 10.04, Precise 12.04, Quantal 12.10,
      # Raring 13.04: 5.3 (default <= 12.10) && 5.4 (default <= 13.04)
      if $::lsbdistcodename in ['lucid', 'precise', 'quantal', 'raring', 'trusty']
        and $php_version == '54'
      {
        $options = $::lsbdistcodename ? {
          'lucid' => '',
          default => '-y'
        }

        ::apt::ppa { 'ppa:ondrej/php5-oldstable':
          require => ::Apt::Key['4F4EA0AAE5267A6C'],
          options => $options
        }
      }
      # 12.04/10, 13.04/10, 14.04: 5.5
      elsif $::lsbdistcodename in ['precise', 'quantal', 'raring', 'saucy', 'trusty']
        and $php_version == '55'
      {
        ::apt::ppa { 'ppa:ondrej/php5':
          require => ::Apt::Key['4F4EA0AAE5267A6C']
        }
      }
      elsif $::lsbdistcodename in ['lucid'] and $php_version == '55' {
        err('You have chosen to install PHP 5.5 on Ubuntu 10.04 Lucid. This will probably not work!')
      }
      # Ubuntu 14.04 can do PHP 5.6
      elsif $::lsbdistcodename == 'trusty' and $php_version == '56' {
        ::apt::ppa { 'ppa:ondrej/php5-5.6':
          require => ::Apt::Key['4F4EA0AAE5267A6C']
        }
      }
    }
    'redhat', 'centos': {
      include ::yum::repo::remi

      # remi_php55 requires the remi repo as well
      if $php_version == '55' {
        include ::yum::repo::remi_php55
      }
      # remi_php56 requires the remi repo as well
      elsif $php_version == '56' {
        ::yum::managed_yumrepo { 'remi-php56':
          descr          => 'Les RPM de remi pour Enterpise Linux $releasever - $basearch - PHP 5.6',
          mirrorlist     => 'http://rpms.famillecollet.com/enterprise/$releasever/php56/mirror',
          enabled        => 1,
          gpgcheck       => 1,
          gpgkey         => 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-remi',
          gpgkey_source  => 'puppet:///modules/yum/rpm-gpg/RPM-GPG-KEY-remi',
          priority       => 1,
        }
      }
    }
  }

}
class puphpet::php::xdebug (
  $install_cli = true,
  $webserver,
  $compile     = false,
  $ensure      = present
) inherits puphpet::params {

  if $webserver != undef {
    $notify_service = Service[$webserver]
  } else {
    $notify_service = []
  }

  if !$compile and ! defined(Package[$puphpet::params::xdebug_package]) {
    package { 'xdebug':
      name    => $puphpet::params::xdebug_package,
      ensure  => installed,
      require => Package['php'],
      notify  => $notify_service,
    }
  } else {
    # php 5.6 requires xdebug be compiled, for now
    case $::operatingsystem {
      'debian': {$mod_dir = '/usr/lib/php5/20131226-zts'}
      'ubuntu': {$mod_dir = '/usr/lib/php5/20131226'}
      'redhat', 'centos': {$mod_dir = '/usr/lib64/php/modules'}
    }

    exec { 'git clone https://github.com/xdebug/xdebug.git /.puphpet-stuff/xdebug':
      creates => '/.puphpet-stuff/xdebug',
      require => Class['Php::Devel'],
    }
    -> exec { 'phpize && ./configure --enable-xdebug && make':
      creates => '/.puphpet-stuff/xdebug/configure',
      cwd     => '/.puphpet-stuff/xdebug',
    }
    -> exec { "cp /.puphpet-stuff/xdebug/modules/xdebug.so ${mod_dir}":
      creates => "${mod_dir}/xdebug.so",
    }

    puphpet::php::ini { 'xdebug/zend_extension':
      entry       => "XDEBUG/zend_extension",
      value       => "${mod_dir}/xdebug.so",
      php_version => '5.6',
      webserver   => $webserver,
      require     => Exec["cp /.puphpet-stuff/xdebug/modules/xdebug.so ${mod_dir}"],
    }
  }

  # shortcut for xdebug CLI debugging
  if $install_cli and defined(File['/usr/bin/xdebug']) == false {
    file { '/usr/bin/xdebug':
      ensure  => present,
      mode    => '+X',
      source  => 'puppet:///modules/puphpet/xdebug_cli_alias.erb',
      require => Package['php']
    }
  }

}
class puphpet::php::xhprof (
  $php_version      = '54',
  $webroot_location = '/var/www',
  $webserver_service
) inherits puphpet::params {

  exec { 'delete-xhprof-path-if-empty-folder':
    command => "rm -rf ${webroot_location}/xhprof",
    onlyif  => "test ! -f ${webroot_location}/xhprof/extension/config.m4"
  }

  vcsrepo { "${webroot_location}/xhprof":
    ensure   => present,
    provider => git,
    source   => 'https://github.com/facebook/xhprof.git',
    require  => Exec['delete-xhprof-path-if-empty-folder']
  }

  file { "${webroot_location}/xhprof/xhprof_html":
    ensure  => directory,
    mode    => 0775,
    require => Vcsrepo["${webroot_location}/xhprof"]
  }

  if $::operatingsystem == 'ubuntu' and $php_version != '53' {
    exec { 'configure xhprof':
      cwd     => "${webroot_location}/xhprof/extension",
      command => 'phpize && ./configure && make && make install',
      require => [
        Vcsrepo["${webroot_location}/xhprof"],
        Class['Php::Devel']
      ],
      path    => [ '/bin/', '/usr/bin/' ]
    }

    puphpet::php::ini { 'add xhprof ini extension':
      php_version  => $php_version,
      webserver    => $webserver_service,
      ini_filename => '20-xhprof-custom.ini',
      entry        => 'XHPROF/extension',
      value        => 'xhprof.so',
      ensure       => 'present',
      require      => Exec['configure xhprof']
    }

    puphpet::php::ini { 'add xhprof ini xhprof.output_dir':
      php_version  => $php_version,
      webserver    => $webserver_service,
      ini_filename => '20-xhprof-custom.ini',
      entry        => 'XHPROF/xhprof.output_dir',
      value        => '/tmp',
      ensure       => 'present',
      require      => Exec['configure xhprof']
    }

    composer::exec { 'xhprof-composer-run':
      cmd     => 'install',
      cwd     => "${webroot_location}/xhprof",
      require => [
        Class['composer'],
        Exec['configure xhprof']
      ]
    }
  } else {
    $xhprof_package = $puphpet::params::xhprof_package

    if $webserver_service != undef and is_string($webserver_service) {
      $xhprof_package_notify = [Service[$webserver_service]]
    } elsif $webserver_service != undef {
      $xhprof_package_notify = $webserver_service
    } else {
      $xhprof_package_notify = []
    }

    if ! defined(Package[$xhprof_package]) {
      package { $xhprof_package:
        ensure  => installed,
        require => Package['php'],
        notify  => $xhprof_package_notify,
      }
    }

    composer::exec { 'xhprof-composer-run':
      cmd     => 'install',
      cwd     => "${webroot_location}/xhprof",
      require => [
        Class['composer'],
        File["${webroot_location}/xhprof/xhprof_html"]
      ]
    }
  }

}
# This depends on
#   puppetlabs/apt: https://github.com/puppetlabs/puppetlabs-apt

class puphpet::phpmyadmin(
  $dbms             = 'mysql::server',
  $webroot_location = '/var/www'
) inherits puphpet::params {

  if $::osfamily == 'debian' {
    if $::operatingsystem == 'ubuntu' {
      apt::key { '80E7349A06ED541C': key_server => 'hkp://keyserver.ubuntu.com:80' }
      apt::ppa { 'ppa:nijel/phpmyadmin': require => Apt::Key['80E7349A06ED541C'] }
    }

    $phpMyAdmin_package = 'phpmyadmin'
    $phpMyAdmin_folder  = 'phpmyadmin'
  } elsif $::osfamily == 'redhat' {
    $phpMyAdmin_package = 'phpMyAdmin.noarch'
    $phpMyAdmin_folder  = 'phpMyAdmin'
  } else {
    error('phpMyAdmin module currently only works with Debian or RHEL families')
  }

  if ! defined(Package[$phpMyAdmin_package]) {
    package { $phpMyAdmin_package:
      require => Class[$dbms]
    }
  }

  if ! defined(File[$webroot_location]) {
    file { $webroot_location:
      ensure  => directory,
      require => Package[$phpMyAdmin_package]
    }
  }

  exec { 'cp phpmyadmin to webroot':
    command => "cp -LR /usr/share/${phpMyAdmin_folder} ${webroot_location}/phpmyadmin",
    onlyif  => "test ! -d ${mysql_pma_webroot_location}/phpmyadmin",
    require => [
      Package[$phpMyAdmin_package],
      File[$webroot_location]
    ]
  }

}
class puphpet::python::pip {

  Exec { path => [ '/usr/bin/', '/usr/local/bin', '/bin', '/usr/local/sbin', '/usr/sbin', '/sbin' ] }

  if ! defined(Package['python-setuptools']) {
    package { 'python-setuptools': }
  }

  exec { 'easy_install pip':
    unless  => 'which pip',
    require => Package['python-setuptools'],
  }

  if $::osfamily == 'RedHat' {
    exec { 'rhel pip_provider_name_fix':
      command     => 'alternatives --install /usr/bin/pip-python pip-python /usr/bin/pip 1',
      subscribe   => Exec['easy_install pip'],
      unless      => 'which pip-python',
    }
  }

}
class puphpet::ssl_cert
  inherits puphpet::params {

  case $::osfamily {
    'debian': {
      if ! defined(Package['ssl-cert']) {
        package { 'ssl-cert':
          ensure => latest,
        }
      }

      exec { 'make-ssl-cert generate-default-snakeoil --force-overwrite':
        creates => [
          $puphpet::params::ssl_cert_location,
          $puphpet::params::ssl_key_location
        ],
        require => Package['ssl-cert'],
        path    => [ '/bin/', '/usr/bin/', '/usr/sbin/' ]
      }
    }
    'redhat': {
      if ! defined(Package['openssl']) {
        package { 'openssl':
          ensure => latest,
        }
      }

      exec { "make-dummy-cert ${puphpet::params::ssl_cert_location}":
        creates => $puphpet::params::ssl_cert_location,
        require => Package['openssl'],
        path    => [ '/bin/', '/usr/bin/', '/usr/sbin/', '/etc/pki/tls/certs/' ]
      }
    }
  }

}
# This depends on
#   ajcrowe/supervisord: https://github.com/ajcrowe/puppet-supervisord

class puphpet::supervisord {

  if ! defined(Class['::supervisord']) {
    class{ 'puphpet::python::pip': }

    class { '::supervisord':
      install_pip => false,
      require     => [
        Class['::my_fw::post'],
        Class['puphpet::python::pip'],
      ],
    }
  }

}
class puphpet::xdebug (
  $install_cli = true,
  $webserver,
  $compile     = false,
  $ensure      = present
) inherits puphpet::params {

  warning('puphpet::xdebug is deprecated; please use puphpet::php::xdebug')

  class { '::puphpet::php::xdebug':
    install_cli => $install_cli,
    webserver   => $webserver,
    compile     => $compile,
    ensure      => $ensure,
  }
}
class puphpet::xhprof (
  $php_version      = '54',
  $webroot_location = '/var/www',
  $webserver_service
) inherits puphpet::params {

  warning('puphpet::xhprof is deprecated; please use puphpet::php::xhprof')

  class { '::puphpet::php::xhprof':
    php_version       => $php_version,
    webroot_location  => $webroot_location,
    webserver_service => webserver_service,
  }

}

{
  "name": "puphpet-puppet",
  "version": "1.0",
  "author": "puphpet",
  "summary": "Puppet module for PuPHPet",
  "license": "MIT",
  "source": "git://github.com/puphpet/puppet-puphpet.git",
  "project_page": "https://github.com/puphpet/puppet-puphpet",
  "issues_url": "https://github.com/puphpet/puppet-puphpet/issues",
  "operatingsystem_support": [
    {
      "operatingsystem": "CentOS",
      "operatingsystemrelease": [
        "5",
        "6",
        "7"
      ]
    },
    {
      "operatingsystem": "Debian",
      "operatingsystemrelease": [
        "6",
        "7"
      ]
    },
    {
      "operatingsystem": "Ubuntu",
      "operatingsystemrelease": [
        "10.04",
        "12.04",
        "14.04"
      ]
    }
  ],
  "requirements": [
    {
      "name": "puppet",
      "version_requirement": "3.x"
    }
  ],
  "description": "Puppet module for PuPHPet",
  "dependencies": [
  ]
}
<%= @vhost['custom_fragment'] %>

<% if !@require_mod_php %>
<% if @vhost.has_key?('engine') %>
<% if @vhost['engine'] == 'php' %>
    ProxyPassMatch ^/(.*\.php(/.*)?)$ fcgi://<%= @fcgi_string %><%= @vhost['docroot'] %>/$1
<% end %>
<% end %>
<% end %>
<%= scope.function_template(['apache/httpd.conf.erb']) -%>

FastCgiExternalServer <%= @docroot %>/hhvm.external -host <%= @hhvm_values['settings']['host'] %>:<%= @hhvm_values['settings']['port'] %>
AddHandler hhvm .php
Action hhvm /usr/lib/cgi-bin/hhvm.external
Alias /usr/lib/cgi-bin/ <%= @docroot %>/
#!/bin/sh

PHP_FCGI_MAX_REQUESTS=10000
export PHP_FCGI_MAX_REQUESTS

exec <%= @phpcgi %>
# FcgidMaxRequestsPerProcess should be <= PHP_FCGI_MAX_REQUESTS
FcgidMaxRequestsPerProcess 10000

<Location />
    AddHandler fcgid-script .php
    Options +ExecCGI
    FcgidWrapper /usr/local/bin/php-wrapper .php
</Location>
server {
   listen                80;
   server_name           localhost;

   index index.php index.html index.htm;

   access_log            /var/log/nginx/log/host.access.log;
   error_log             /var/log/nginx/log/host.error.log;

   location / {
     root  <%= @webroot %>;
     try_files  $uri  $uri/  /index.php?$args ;
     index  index.html index.htm index.php;
   }

   location ~ \.php$ {
     root  <%= @webroot %>;
     try_files  $uri  $uri/  /index.php?$args ;
     index  index.html index.htm index.php;

     fastcgi_index index.php;
     fastcgi_param PATH_INFO $fastcgi_path_info;
     fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
     fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
     fastcgi_pass  <%= @fastcgi_pass %>;
     fastcgi_split_path_info ^(.+\.php)(/.+)$;
     include fastcgi_params;
   }
 }
#!/bin/bash

LATEST_NODE=$(curl 'http://nodejs.org/dist/latest/SHASUMS.txt' | grep 'linux-x64.tar.gz' | awk '{ print $2 }')
wget --quiet --tries=5 --connect-timeout=10 --no-check-certificate -O '/.puphpet-stuff/nodestable.tar.gz' "http://nodejs.org/dist/latest/${LATEST_NODE}"

cd '/usr/local/'

tar xzvf '/.puphpet-stuff/nodestable.tar.gz' --strip=1

ln -s '/usr/local/bin/node' '/usr/bin/node'
ln -s '/usr/local/bin/npm' '/usr/bin/npm'
fixtures:
  repositories:
    "concat": "git://github.com/puppetlabs/puppetlabs-concat.git"
    "stdlib": "git://github.com/puppetlabs/puppetlabs-stdlib.git"
  symlinks:
    "puppi": "#{source_dir}"
source 'https://rubygems.org'

puppetversion = ENV['PUPPET_VERSION']
gem 'puppet', puppetversion, :require => false
gem 'puppet-lint'
gem 'puppetlabs_spec_helper', '>= 0.1.0'
gem 'puppet-blacksmith', '>= 2.0.0'
language: ruby
rvm:
  - 1.8.7
  - 1.9.3
script:
  - "rake spec SPEC_OPTS='--format documentation'"
env:
  - PUPPET_VERSION="~> 2.6.0"
  - PUPPET_VERSION="~> 2.7.0"
  - PUPPET_VERSION="~> 3.0.0"
  - PUPPET_VERSION="~> 3.1.0"
matrix:
  exclude:
    - rvm: 1.9.3
      env: PUPPET_VERSION="~> 2.6.0"
      gemfile: .gemfile

gemfile: .gemfile
notifications:
  email:
    - al@lab42.it
Copyright (C) 2013 Alessandro Franceschi / Lab42

for the relevant commits Copyright (C) by the respective authors.

Contact Lab42 at: info@lab42.it

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
name 'example42-puppi'
version '2.1.8'

author 'lab42'
license 'Apache'
project_page 'http://www.example42.com'
source 'git://github.com/example42/puppi'
summary 'Installs and configures Puppi'
description 'This module provides the Puppi libraries required by Example42 modules and, if explicitely included, the puppi command, its working environment, the defines and procedures to deploy applications'
# Puppi: Puppet Knowledge to the CLI

Puppi One and Puppi module written by Alessandro Franceschi / al @ lab42.it

Puppi Gem by Celso Fernandez / Zertico

Source: http://www.example42.com

Licence: Apache 2

Puppi is a Puppet module and a CLI command.
It's data is entirely driven by Puppet code.
It can be used to standardize and automate the deployment of web applications
or to provides quick and standard commands to query and check your system's resources

Its structure provides FULL flexibility on the actions required for virtually any kind of
application deployment and information gathering.

The module provides:

* Old-Gen and Next-Gen Puppi implementation

* A set of scripts that can be used in chain to automate any kind of deployment

* Puppet defines that make it easy to prepare a puppi set of commands for a project deployment

* Puppet defines to populate the output of the different actions


## HOW TO INSTALL

Download Puppi from GitHub and place it in your modules directory: 

       git clone https://github.com/example42/puppi.git /etc/puppet/modules/puppi

To use the Puppi "Original, old and widely tested" version, just declare or include the puppi class

       class { 'puppi': }

To test the Next-Gen version you can perform the following command. Please note that this module is
not stable yet:
        class { 'puppi':
          version => '2',
        }

If you have resources conflicts, do not install automatically the Puppi dependencies (commands and packages)

        class { 'puppi':
          install_dependencies => false,
        }


## HOW TO USE

Once Puppi is installed you can use it to:

* Easily define in Puppet manifests Web Applications deploy procedures. For example:

        puppi::project::war { "myapp":
            source           => "http://repo.example42.com/deploy/prod/myapp.war",
            deploy_root      => "/opt/tomcat/myapp/webapps",
        }

* Integrate with your modules for puppi check, info and log 

* Enable Example42 modules integration


## HOW TO USE WITH EXAMPLE42 MODULES

The Example42 modules provide (optional) Puppi integration.
Once enabled for each module you have puppi check, info and log commands.

To eanble Puppi in OldGen Modules, set in the scope these variables:

        $puppi = yes   # Enables puppi integration.
        $monitor = yes # Enables automatic monitoring 
        $monitor_tool = "puppi" # Sets puppi as monitoring tool

For the NextGen modules set the same parameters via Hiera, at Top Scope or as class arguments:

        class { 'openssh':
          puppi        => yes, 
          monitor      => yes,
          monitor_tool => 'puppi', 
        }


## USAGE OF THE PUPPI COMMAND (OLD GEN)

        puppi <action> <project_name> [ -options ]

The puppi command has these possibile actions:

First time initialization of the defined project (if available)
        puppi init <project>

Deploy the specified project
        puppi deploy <project>

Rollback to a previous deploy state
        puppi rollback <project>

Run local checks on system and applications
        puppi check

Tail system or application logs
        puppi log

Show system information (for all or only the specified topic)
        puppi info [topic]

Show things to do (or done) manually on the system (not done via Puppet)
        puppi todo

In the deploy/rollback/init actions, puppi runs the commands in /etc/puppi/projects/$project/$action, logs their status and then run the commands in /etc/puppi/projects/$project/report to provide reporting, in whatever, pluggable, way.

You can also provide some options:

* -f : Force puppi commands execution also on CRITICAL errors

* -i : Interactively ask confirmation for every command

* -t : Test mode. Just show the commands that should be executed without doing anything

* -d <yes|full>: Debug mode. Show debugging info during execution

* -o "parameter=value parameter2=value2" : Set manual options to override defaults. The options must be in parameter=value syntax, separated by spaces and inside double quotes.


Some common puppi commnds when you log for an application deployment:

        puppi check
        puppi log &    # (More readable if done on another window)
        puppi deploy myapp
        puppi check
        puppi info myapp


## THE PUPPI MODULE

The set of commands needed for each of these actions are entirely managed with specific
Puppet "basic defines":

Create the main project structure. One or more different deployment projects can exist on a node.
        puppi::project

Create a single command to be placed in the init sequence. It's not required for every project.
        puppi::initialize

Create a single command to be placed in the deploy sequence. More than one is generally needed for each project.
        puppi::deploy

Create a single command to be placed in the rollback sequence. More than one is generally needed for each project.
        puppi::rollback

Create a single check (based on Nagios plugins) for a project or for the whole host (host wide checks are auto generated by Example42 monitor module)
        puppi::check

Create a reporting command to be placed in the report sequence.
        puppi::report

Create a log filename entry for a project or the whole hosts.
        puppi::log

Create an info entry with the commands used to provide info on a topic
        puppi::info

Read details in the relevant READMEs


## FILE PATHS (all of them are provided, and can be configured, in the puppi module):

A link to the actual version of puppi enabled
        /usr/sbin/puppi

The original puppi bash command.
        /usr/sbin/puppi.one

Puppi (one) main config file. Various puppi wide paths are defined here.
        /etc/puppi/puppi.conf

Directory where by default all the host wide checks can be placed. If you use the Example42 monitor module and have "puppi" as $monitor_tool, this directory is automatically filled with Nagios plugins based checks.
        /etc/puppi/checks/ ($checksdir)

Directory that containts projects subdirs, with the commands to be run for deploy, rollback and check actions. They are completely built (and purged) by the Puppet module.
        /etc/puppi/projects/ ($projectsdir)

The general-use scripts directory, these are used by the above commands and may require one or more arguments.
        /etc/puppi/scripts/ ($scriptsdir)

The general-use directory where files are placed which contain the log paths to be used by puppi log
        /etc/puppi/logs/ ($logssdir)

The general-use directory where files are placed which contain the log paths to be used by puppi log
        /etc/puppi/info/ ($infodir)

Where all data to rollback is placed.
        /var/lib/puppi/archive/ ($archivedir)

Where logs and reports of the different commands are placed.
        /var/log/puppi/ ($logdir)

Temporary, scratchable, directory where Puppi places temporary files.
        /tmp/puppi/ ($workdir)

A runtime configuration file, which is used by all all the the scripts invoked by puppi to read and write dynamic variables at runtime. This is necessary to mantain "state" information that changes on every puppi run (such as the deploy datetime, used for backups).
        /tmp/puppi/$project/config


## HOW TO CUSTOMIZE
It should be clear that with puppi you have full flexibility in the definition of a deployment 
procedure, since the puppi command is basically a wrapper that executes arbitrary scripts with
a given sequence, in pure KISS logic.

The advantanges though, are various:
* You have a common syntax to manage deploys and rollbacks on an host

* In your Puppet manifests, you can set in simple, coherent and still flexible and customizable
  defines all the elements, you need for your application deployments. 
  Think about it: with just a Puppet define you build the whole deploy logic

* Reporting for each deploy/rollback is built-in and extensible 

* Automatic checks can be built in the deploy procedure

* You have a common, growing, set of general-use scripts for typical actions

* You have quick and useful command to see what's happening on the system (puppi check, log, info)

There are different parts where you can customize the behaviour of puppi:

* The set of general-use scripts in /etc/puppi/scripts/ ( this directory is filled with the content
  of puppi/files/scripts/ ) can/should be enhanced. These can be arbitrary scripts in whatever
  language. If you want to follow puppi's logic, though, consider that they should import the
  common and runtime configuration files and have an exit code logic similar to the one of
  Nagios plugins: 0 is OK, 1 is WARNING, 2 is CRITICAL. Note that by default a script that 
  exits with WARNING doesn't block the deploy procedure, on the other hand, if a script exits
  with CRITICAL (exit 2) by default it blocks the procedure.
  Take a second, also, to explore the runtime config file created by the puppi command that
  contains variables that can be set and used by the scripts invoked by puppi.

* The custom project defines that describe deploy templates. These are placed in
  puppi/manifests/project/ and can request all the arguments you want to feed your scripts with.
  Generally is a good idea to design a standard enough template that can be used for all the 
  cases where the deployment procedure involves similar steps. Consider also that you can handle
  exceptions with variables (see the $loadbalancer_ip usage in puppi/manifests/project/maven.pp)


## (NO) DEPENDENCIES AND CONFLICTS
Puppi is self contained. It doesn't require other modules.
(And is required by all Example42 modules).

For correct functionality by default some extra packages are installed.
If you have conflicts with your existing modules, set the argument:
  install_dependencies => false

# PUPPI CHECK INSTRUCTIONS
Documentation and examples related to the puppi action check

## SYNOPSIS (cli)
        puppi check [project_name] [-r yes|no|fail]

## EXAMPLES (cli)
Run host-wide checks.
        puppi check
Run project "myapp" specific tests AND host-wide checks
        puppi check myapp

Run checks and send reports only if some of them fail
        puppi check -r fail

Run checks and send reports
        puppi check -r yes

Run checks and show only failed ones
        puppi check -s fail

## EXAMPLES (puppet)
The basic define related to a check is:
        puppi::check   - Creates a single command to be placed in the check sequence.

A simple example might be:
        puppi::check { 'Port_Apache':
          command  => "check_tcp -H ${fqdn} -p 80" ,
        }

but also something that uses variables Puppet already knows
        puppi::check { 'apache_process':
          command  => "check_procs  -c 1: -C ${apache::params::processname}" ,
        }

To avoid repetitions you can include the relevant checks in defines you already have
to manage, for example, virtualhosts, and use the data you already provide to configure
their local puppi checks. 
        puppi::check { "Url_$name":
          enable   => $enable,
          command  => "check_http -I '${target}' -p '${port}' -u '${url}' -s '${pattern}'" ,
        }

You can also use custom scripts for your checks. They should behave similarly to Nagios plugins inn their exit codes: 0 for SUCCESS, 1 for WARNINGS, 2 for CRITICAL. In this case you've to specify the directory there the scripts stays:
        puppi::check { 'my_stack':
          command  => 'stack_check.sh',
          bade_dir => '/usr/bin',
        }


## EXAMPLES (with example42 puppet modules)
If you use the whole Example42 modules set you get automatically many service related checks out of the box.
Just set (via an ENC, facts or manifests) these puppet variables:
        $monitor="yes" # To enable automagic monitoring
        $monitor_tool = "puppi"  # As monitoring tool define at least puppi. If you like Nagios, you may use:
        $monitor_tool = ["nagios","puppi"] # This enables the below checks both for Puppi and Nagios
        $puppi=yes # To enable puppi extensions autoloading

To the port and service checks automatically added for the included modules, you can add custom url checks 
with something like:
        monitor::url { "URL_Check_Database_Connection":
          url      => "http://www.example42.com/check/db",
          pattern  => 'SUCCESS',
          port     => '80',
          target   => "${fqdn}",
        }

# PUPPI DEPLOY INSTRUCTIONS
Documentation and examples related to the puppi actions: deploy, rollback and init

## SYNOPSIS (COMMAND LINE)
Shell command to launch a deploy:
        puppi deploy <project_name>
        puppi deploy <project_name> [-f] [-i] [-t] [-d yes|full] [-r yes|no|fail] [-p "parameter=value parameter2=value2"]

Shell command to launch a rollback:
        puppi rollback <project_name> 

Shell command to launch the first deploy:
        puppi init <project_name>


## EXAMPLES (cli)

Deploy myapp with the standard logic/parameters defined in Puppet:
        puppi deploy myapp

Deploy myapp and doesn't stop in case of Critical errors:
        puppi deploy myapp -f

Deploy myapp in interactive mode. Confirmation is asked for each step
        puppi deploy myapp -i

Test mode. Just show the commands that would be executed
        puppi deploy myapp -t

Deploy myapp with full debugging output
        puppi deploy myapp -d full

Deploy myapp in interactive mode and sets some custom options that override the standard Puppet params.
Note that these parameters change according to the script you use (and the scripts must honour this override in order to make this option work).
        puppi deploy myapp -i -o "version=1.1 source_url=http://dev.example42.com/code/my_app/"

Make the first deploy of "myapp". Can be optional and may require a subsequent puppi deploy myapp
        puppi init myapp

Rollback myapp to a previous archived state. User is asked to choose which deploy to override. Note that by default you have 5 backups to rollback from. Older backups are automatically removed.
        puppi rollback myapp

Automatically rollback to the latest saved state (unattended).
        puppi rollback myapp latest


## EXAMPLES (puppet)
Here follow some sample defines you can use out of the box in your manifests once you include puppi.
Get a war from $source and deploy it in $deploy_root:
        puppi::project::war { 'myapp':
          source           => 'http://repo.example42.com/deploy/prod/myapp.war',
          deploy_root      => '/store/tomcat/myapp/webapps',
        }

Get a tarball from $source, unpack it in $deploy_root, restart service called apache and send a mail
to $report_mail (you can have a comma separated list of destination addresses):
        puppi::project::tar { 'mysite':
          source           => 'rsync://repo.example42.com/deploy/prod/release.tgz',
          init_script      => 'apache',
          deploy_root      => '/var/www/html/',
          report_email     => 'sysadmins@example42.com',
          enable           => 'true', # Redundant
        }

Get a tarfile with a .sql query file and apply to to you local Mysql with the credentials provided:
        puppi::project::mysql { 'myweb_sql':
          source          => 'http://repo.example42.com/deploy/prod/database.sql.gz',
          mysql_user      => 'myweb',
          mysql_password  => $secret::mysql_myweb_pw,
          mysql_host      => 'localhost',
          mysql_database  => 'myweb',
          report_email    => 'sysadmins@example42.com,dbadmins@example42.com',
          enable          => 'true',
        }

Get a list of files from $source, retrieve the actual files from $source_baseurl and place them
in $deploy_root
        puppi::project::files { 'gfxupdates':
          source           => 'http://deploy.example42.com/prod/website2/list.txt',
          source_baseurl   => 'http://design.example42.com/website2/gfx/',
          deploy_root      => '/var/www/html/gfx',
          report_email     => 'sysadmins@example42.com,designers@example42.com',
          enable           => 'true',
        }

Deploy from a Nexus repository (retrieve maven-metadata.xml from dir specified in $source), get the war 
(version is achieved from the "release" tag in the xml) and deploy it in $deploy_root and then restart tomcat.
        puppi::project::maven { 'supersite':
          source           => 'http://nexus.example42.com/nexus/content/repositories/releases/it/example42/supersite/',
          deploy_root      => '/usr/local/tomcat/supersite/webapps',
          init_script      => 'tomcat',
          report_email     => 'sysadmins@example42.com',
          enable           => 'true',
        }

Get the maven-metadata.xml from a Nexus repository and deploy:
- The release war in $deploy_root
- A configurations tarball tagged with the Maven qualifier $config_suffix in $config_root
- A static files tarball tagged with the Maven qualifier $document_suffix in $document_root
        puppi::project::maven { 'supersite':
          source           => 'http://nexus.example42.com/nexus/content/repositories/releases/it/example42/supersite/',
          deploy_root      => '/usr/local/tomcat/supersite/webapps',
          config_suffix    => 'cfg',
          config_root      => '/srv/htdocs/supersite',
          document_suffix  => 'css',
          document_root    => '/srv/htdocs/supersite',
          init_script      => 'tomcat',
          report_email     => 'sysadmins@example42.com',
          enable           => 'true',
        }

The same deploy Nexus repository with some more options:
- A Source dir to be used to deploy static files when issuing "puppi init supersite"
- A block from a loadbalancer IP (managing different sites addresess)
- Some more elaborate rsync exclusion rules
- A backup retention of 3 archives (instead of the default 5)
        puppi::project::maven { 'supersite':
          source           => 'http://nexus.example42.com/nexus/content/repositories/releases/it/example42/supersite/',
          deploy_root      => '/usr/local/tomcat/supersite/webapps',
          config_suffix    => 'cfg',
          config_root      => '/srv/htdocs/supersite',
          document_suffix  => 'css',
          document_root    => '/srv/htdocs/supersite',
          document_init_source => 'rsync://backup.example42.com/initdir/supersite/',
          firewall_src_ip  => $site ? {
              dr      => '192.168.101.1/30',
              main    => '192.168.1.1/30',
          },
          backup_rsync_options => '--exclude .snapshot --exclude /doc_root/autojs/*** --exclude /doc_root/autocss/*** --exclude /doc_root/xsl',
          backup_retention => '3',
          init_script      => 'tomcat',
          report_email     => 'sysadmins@example42.com',
          enable           => 'true',
        }

An elaborated war deploy:
- get from $source,
- execute /usr/local/bin/mychecks.sh as root before the deploy
(or better with sequence number 39)
- deploy to /data/tomcat/myapp/webapps as user pippo
- stop and start tomcat-myapp but also monit and puppet
- backup passing  $backup_rsync_options to rsync:
        puppi::project::war { 'myapp':
          source                  => 'http://repo.example42.com/deploy/prod/myapp.war',
          deploy_root             => '/store/tomcat/myapp/webapps',
          predeploy_customcommand => '/usr/local/bin/mychecks.sh',
          predeploy_priority      => '39',
          predeploy_user          => 'root',
          backup_rsync_options    => '--exclude logs/',
          user                    => 'pippo',
          init_script             => 'tomcat-myapp',
          deploy_root             => '/data/tomcat/myapp/webapps',
          report_email            => 'sysadmins@example42.com',
          disable_services        => 'monit puppet',
        }
An example of usage of the generic builder define to deploy a zip file, with an example custom
post deploy command executed as root (as all puppi commands, if not specified otherwise)
        puppi::project::builder { 'cms':
          source                   => 'http://repo.example42.com/deploy/cms/cms.zip',
          source_type              => 'zip',
          user                     => 'root',
          deploy_root              => '/var/www',
          postdeploy_customcommand => 'chown -R www-data /var/www/files',
          postdeploy_user          => 'root',
          postdeploy_priority      => '41',
          report_email             => 'sysadmins@example42.com',
          enable                   => 'true',
        }

These are just examples, possibilities are many, refer to the docs in puppi/manifests/project/*.pp
to have a full list of the available options.


## BASIC PUPPI DEFINES
The above puppi::projects defines manage more or less complex deployments procedures for different kind of projects. They are just samples of possible procedures and you may create your one ones, if the ones provided there don't fit your needs.
They will have to contain one or more of these basic puppi defines.

Create the main project structure. One or more different deployment projects can exist on a node.
        puppi::project

Create a single command to be placed in the init sequence. It's not required for every project.
        puppi::initialize

Create a single command to be placed in the deploy sequence. More than one is generally needed for each project.
        puppi::deploy

Create a single command to be placed in the rollback sequence. More than one is generally needed for each project.
         puppi::rollback

These defines have generally a standard structure and similar arguments.
Every one is reversable (enable => false) but you can wipe out the whole /etc/puppi directory
to have it rebuilt from scratch. Here is an example for a single deploy command:
        puppi::deploy { 'Retrieve files':       # The $name of the define is used in the file name
          command  => 'get_curl.sh',          # The name of the general-use script to use
          argument => 'file:///storage/file', # The argument(s) passed to the above script
          priority => '10',                   # Lower priority scripts are executed first
          user     => 'root',                 # As what user we run the script
          project  => 'my-web.app',           # The name of the project to use
        }

This define creates a file named:
        /etc/puppi/projects/${project}/deploy/${priority}-${name}
Its content is, simply:
        su - ${user} -c "export project=${project} && /etc/puppi/scripts/${command} ${arguments}"


## DEPLOY PROCEDURES DEFINES
The puppi module provides some examples of deploy workflows they are in the puppi/manifests/project
directory and contain simple to use defines that contain one puppi::project and several puppi::deploy and
puppi::rollback defines to design a specific workflow using the builtin commands present in
puppi/files/scripts.
Note that if you need to design your own deploy procedure you have different options:
- Verify if you can reuse the existing ones, using optional arguments as pre/postdeploy_commands
- Use the existing ones as a base to make you own custom defines, reusing parts of their logic 
  and the builtin commands (puppi/files/scripts/*) they use
- Write your own commands (in whatever language) and integrate them in your own procedure.

Here follow the main and most reusable deploy workflows defines available in puppi/manifests/project/.
The have generally a set of common arguments that make you manage if to stop and restart specific 
services, if you want to isolate your server from a loadbalancer during the deploy procedure, what to backup,
how many backup copies to mantain, if to send a report mail to specific addresses and if you need
to run custom commands during the standard procedure.
For all of the you have to specify a source from where to get the source files (http/ftp/rsync/file..) 
a directory where to place them and the user that has to own the deploy files.
Full documentation is available in the relevant .pp files

- puppi::project::tar - Use this to retrieve and deploy a simple tar file
- puppi::project::war - Use this to retrieve and deploy a war
- puppi::project::files - Use this to deploy one or more files based on a provided list
- puppi::project::dir - Use this to syncronize a remote directory to a local deploy one
- puppi::project::mysql - Use this to retrive and apply a .sql file for mysql schema updates 
- puppi::project::maven - Use this to deploy war and tar files generated via Maven released on Nexus or similar. A good source of Open Source Java artifacts is http://www.artifact-repository.org/
- puppi::project::builder - This is a general purpose define that incorporates most the of cases provided by the above procedures


## BUILTIN COMMANDS
The puppi/files/scripts directory in the module contains some general usage "native" bash scripts
that can be used in custom deployments. They are generally made to work together according to a
specific logic, which is at the base of the deploy procedures defines in puppi/manifests/project/
but you're free to write your own scripts, in whatever language, according to your needs.

The default scripts are engineered to follow these steps for a deployment:
- Remote files are downloaded in /tmp/puppi/$project/store or directly in the predeploy
  directory: /tmp/puppi/$project/deploy
- If  necessary the downloaded files are expanded in one or more predeploy directories
  (default:/tmp/puppi/$project/deploy).
- Runtime configuration entries might be saved in /tmp/puppi/$project/config
- Files are eventually backed from the deploy directory (Apache' docroot, Tomcat webapps or whatever)
  to the archive directory (/var/lib/puppi/archive/$project). Older backups are deleted (by default
  there's a retention of 5 backups).
- Files are copied from the predeploy directory to the deploy dir.
- Relevant services are eventually stopped and started

The most used common scripts are (they might have different arguments, some of them are quite simple):
- get_file.sh - Retrieves a file via ssh/http/rsync/svn and places it in a temp dir (store or predeploy)
- deploy.sh - Copies the files in the predeploy dir to deploy dir
- archive.sh - Backups and restores files in deploy dir
- service.sh - Stops or starts one or more services
- wait.sh - Waits for the presence or absence of a file, for the presence of a string in a file or a defined number or seconds.
- get_metadata.sh - Extracts metadata from various sources in order to provide info to other scripts. These info are save in the Runtime configuration file (/tmp/puppi/$project/config)
- report_mail.sh - Sends a mail with the report of the operations done

General functions, used by both the puppi command and these scripts, are in puppi/files/scripts/functions
# PUPPI INFO README
The puppi info commands executes scripts in /etc/puppi/info/ which are generated by templates provided by the puppi::info define
These scripts are supposed to show status details on the omonimous info topic.

## SYNOPSIS (cli)
        puppi info [topic] [-i]

## EXAMPLES (cli)
Show host-wide infos. Much stuff.
        puppi info

Show info about apache (connections, processes, config, logs...)
        puppi info apache

Interactively select the info topics you want to show
        puppi info -i

Show complete info and send reports (email, rest ... )
        puppi info -r yes

Grep the output with the string defined
        puppi info -g <string>


## EXAMPLES (puppet)
The basic define related to a info is puppi::info, it creates a script executed
when running "puppi info $name" based on the provided template.
Customize the template to customize the info you want to see.

A sample that just runs commands using the default template:
        puppi::info { 'network':
          description => 'Network settings and stats' ,
          run         => [ 'ifconfig' , 'route -n' , 'cat /etc/resolv.conf' , 'netstat -natup | grep LISTEN' ],
        }

You can have more useful and dedicated info topics using a custom puppi::info define inside your
own defines. For example in a define that creates a tomcat instance you can add something like:
        puppi::info::instance { "tomcat-${instance_name}":
          servicename => "tomcat-${instance_name}",
          processname => "${instance_name}",
          configdir   => "${tomcat::params::storedir}/${instance_name}/conf/",
          bindir      => "${tomcat::params::storedir}/${instance_name}/bin/",
          pidfile     => "${instance_rundir}/tomcat-${instance_name}.pid",
          datadir     => "${instance_path}/webapps",
          logdir      => "${instance_logdir}",
          httpport    => "${instance_httpport}",
          controlport => "${instance_controlport}",
          ajpport     => "${instance_ajpport}",
          templatefile=> "puppi/info/instance.erb",
          description => "Info for ${instance_name} Tomcat instance" ,
        }
which has custom arguments, feeded by the data you provided to the define, and a custom
template file that uses these variables. 

## EXAMPLES (with example42 puppet modules)
If you use the old Example42 modules set you get automatically many service related infos out of the box to be used with Puppi One.
NextGen modules are supposed to provide pupi info intergration on Puppi Two (TO DO)
Just set (via an ENC, facts or manifests) $puppi=yes to enable puppi extensions autoloading.
This will automatically deploy info topics related to the modules you use.

# PUPPI LOG README
Documentation and examples related to the puppi action log

## SYNOPSIS (cli)
        puppi log [topic] [-i]

## EXAMPLES (cli)

Tails (tail -10f) all the known logs.
        puppi log

Tails only the logs related to the given topic
        puppi log apache

Choose interactively which logs to show
        puppi log

Grep the output with the string defined
        puppi log -g <string>

## EXAMPLES (puppet)
The basic define related to a log is:
        puppi::log
it creates a file in /etc/puppi/logs/ with one or more logs paths.

A simple, operating system aware, example might be:
        puppi::log { 'auth':
          description => 'Users and authentication' ,
          log => $::operatingsystem ? { 
            redhat => '/var/log/secure',
            darwin => '/var/log/secure.log',
            ubuntu => ['/var/log/user.log','/var/log/auth.log'],
          }
        }

but also something that uses variables Puppet already knows
        puppi::log { "tomcat-${instance_name}":
          log => "${tomcat::params::storedir}/${instance_name}/logs/catalina.out"
        }

EXAMPLES (with example42 puppet modules)
If you use the old Example42 modules set you get automatically many service related logs out of the box to be used with Puppi One.
NextGen modules are supposed to provide puppi log intergration on Puppi Two (TO DO)

require 'rubygems'
require 'puppetlabs_spec_helper/rake_tasks'
require 'puppet_blacksmith/rake_tasks'
require 'puppet-lint'
PuppetLint.configuration.send("disable_80chars")
PuppetLint.configuration.send('disable_class_parameter_defaults')
{
    "name": "example42/puppi",
    "description": "Puppet driven applications deployment tool",
    "homepage": "https://github.com/example42/puppi",
    "type": "library",
    "license": "Apache License, Version 2.0",
    "authors": [
        {
            "name": "Example42",
            "homepage": "http://www.example42.com/"
        }
    ]
}
Default ReadMe File.
Edit puppi/files/info/readme/readme to change this message
No extra node or role related info available.
To have node or role specific extar info, create 
modules/puppi/files/info/readme/readme--$hostname or
modules/puppi/files/info/readme/readme-$role 
#!/bin/bash
# File Managed by Puppet
# Possible Usage:
# Run this command at the end of each Puppet run to be 
# immediately notified if a Puppet Runs has broken some service
# 
# Options:
# -m destination_email
# -i <interval> (in seconds) before retrying a Puppi check
# -r <number_of_retries> how many attempts to retry if there are failures
#
# In puppet.conf add something like:
# postrun_command = "/usr/bin/mailpuppicheck -m roots@example.com"
#
retries=1
interval=2
workdir="/tmp"
counter=0
while [ $# -gt 0 ]; do
  case "$1" in
    -m)
      mail=$2
      shift 2 ;;
    -i)
      internal=$2
      shift 2 ;;
    -r)
      retries=$2
      shift 2 ;;
  esac
done

if [ ! $mail ] ; then
    echo "Provide at least an email addess"
    exit 1
fi

# randfile="$(mktemp)"
lastrunfile=$workdir/puppicheck_lastrun
savedfile=$workdir/puppicheck_saved

while [ $counter -lt $retries ] ; do
  puppi check | grep FAILED > $lastrunfile
  if [ "x$?" == "x0" ] ; then
    errors="yes"
    sleep $interval
  else
    errors="no"
    echo "Run $counter - Errors $errors"
    echo > $savedfile
    exit 0
  fi
  echo "Run $counter - Errors $errors"
  let counter=$counter+1
done

diff $lastrunfile $savedfile
if [ "x$?" == "x0" ] ; then
  echo "No changes detected"
else
  echo "Changes detected"
  notify="yes"
fi

cp $lastrunfile $savedfile
if [ "x$notify" == "xyes" ] ; then 
  # Yes, it's ugly
  cat -v $lastrunfile  | sed -e 's:\^\[\[60G\[\^\[\[0;31m: :g' | sed -e 's:\^\[\[0;39m\]\^M: :g' | mail -s "[puppet] Errors after Puppet run on $(hostname -f)" $mail
  echo "Sent notification"
fi

exit 0
#!/usr/bin/env ruby

# Client program for the mcollective puppi agent 
#
# Released under Apache License 2.0

require 'mcollective'

include MCollective::RPC

options = rpcoptions do |parser, options|
    options[:timeout] = 180

    parser.define_head "Execute Puppi commands"
    parser.banner = "Usage: mc-puppi [filters] command [project] [puppioptions]"
    parser.separator ""
    parser.separator "Available commands:"
    parser.separator "  check [project] - Run puppi check"
    parser.separator "  info [topic] - Run puppi info. For all or specified topic"
    parser.separator "  log [topic] - Run puppi log. For all or specified topic"
    parser.separator "  todo - Run puppi todo"
    parser.separator "  deploy <project> - Run puppi deploy on the defined project"
    parser.separator "  configure <project> - Run puppi configure on the defined project"
    parser.separator "  rollback <project> - Run puppi rollback latest on the defined project"
    parser.separator "  init <project> - Run puppi init on the defined project"
end

if MCollective::Util.empty_filter?(options[:filter])
    print("Do you really want to operate on services unfiltered? (y/n): ")
    STDOUT.flush

    exit unless STDIN.gets.chomp =~ /^y$/
end

if ARGV.length >= 1
    command = ARGV.shift
    project = ARGV.shift
    puppioptions = ARGV.shift

    unless command =~ /^(check|deploy|rollback|init|configure|info|log|todo)$/
        puts("Command has to be check|info|log|deploy|rollback|init|configure|todo")
        exit 1
    end
else
    puts("Please specify at least a command")
    exit 1
end

mc = rpcclient("puppi", :options => options)
mc.progress = true
# mc.send(command, {:project => project}) do |resp|
args = {};
args[:project] = project if project
args[:puppioptions] = puppioptions if puppioptions
mc.send(command, args) do |resp|
    begin
#        puts resp[:serverid]
        puts resp[:body][:data]
#        puts resp[:body][:exitcode]

    rescue RPCError => er
        puts "RPC Agent error: #{er}"
    end
end

metadata    :name        => "SimpleRPC Agent For PUPPI Commands",
            :description => "Agent to query PUPPI commands via MCollective", 
            :author      => "Al @ Lab42",
            :license     => "Apache License 2.0",
            :version     => "0.3",
            :url         => "http://www.example42.com/",
            :timeout     => 600

[ "check" , "log" , "info" ].each do |myact| 
    action myact, :description => "Run puppi myact" do
        display :always

        input :project,
              :prompt      => "Project",
              :description => "PUPPI project",
              :type        => :string,
              :validation  => '^[a-zA-Z\-\.=_\d]+$',
              :optional    => true,
              :maxlength   => 50

        input :puppioptions,
              :prompt      => "Puppi options",
              :description => "PUPPI options",
              :type        => :string,
              :validation  => '^[a-zA-Z\-\.=_\d]+$',
              :optional    => true,
              :maxlength   => 50

        output :data,
              :description => "Output from the Puppi run",
              :display_as  => "Output"

        output :exitcode,
              :description  => "Exit Code from the Puppi run",
              :display_as => "Exit Code"
    end
end

[ "deploy" , "rollback" , "init" , "configure" ].each do |myact|
    action myact, :description => "Run puppi myact" do
        display :always

        input :project,
              :prompt      => "Project",
              :description => "PUPPI project",
              :type        => :string,
              :validation  => '^[a-zA-Z\-\.=_\d]+$',
              :optional    => false,
              :maxlength   => 50

        input :puppioptions,
              :prompt      => "Puppi options",
              :description => "PUPPI options",
              :type        => :string,
              :validation  => '^[a-zA-Z\-\.=_\d]+$',
              :optional    => true,
              :maxlength   => 50

        output :data,
              :description => "Output from the Puppi run",
              :display_as  => "Output"

        output :exitcode,
              :description  => "Exit Code from the Puppi run",
              :display_as => "Exit Code"
    end
end

module MCollective
    module Agent
        class Puppi<RPC::Agent
            metadata    :name        => "SimpleRPC Agent For PUPPI Commands",
                        :description => "Agent to execute PUPPI actions via MCollective",
                        :author      => "Al @ Lab42",
                        :license     => "Apache License 2.0",
                        :version     => "0.3",
                        :url         => "http://www.example42.com/",
                        :timeout     => 600

            def check_action
#                   validate :project, :shellsafe
                    project = request[:project] if request[:project]
                    reply.data = %x[puppi check #{project}].chomp
                    if ($?.exitstatus > 0)
                      reply.fail "FAILED: #{reply.data}"
                    end
            end

            def info_action
#                   validate :project, :shellsafe
                    project = request[:project] if request[:project]
                    reply.data = %x[puppi info #{project}].chomp
                    if ($?.exitstatus > 0)
                      reply.fail "FAILED: #{reply.data}"
                    end
            end

            def log_action
#                   validate :project, :shellsafe
                    project = request[:project] if request[:project]
                    reply.data = %x[puppi log #{project} -c 10].chomp
                    if ($?.exitstatus > 0)
                      reply.fail "FAILED: #{reply.data}"
                    end
            end

            def deploy_action
                    validate :project, :shellsafe
                    project = request[:project] if request[:project]
                    if (!File.directory? "/etc/puppi/projects/#{project}")
                      reply.fail "No such project #{project}"
                      return
                    end
                    puppioptions = request[:puppioptions]
                    reply.data = %x[puppi deploy #{project} -o "#{puppioptions}"].chomp
                    if ($?.exitstatus > 0)
                      reply.fail "FAILED: #{reply.data}"
                    end
            end

            def rollback_action
                    validate :project, :shellsafe
                    project = request[:project] if request[:project]
                    reply.data = %x[puppi rollback #{project} latest].chomp
                    if ($?.exitstatus > 0)
                      reply.fail "FAILED: #{reply.data}"
                    end
            end

            def init_action
                    validate :project, :shellsafe
                    project = request[:project] if request[:project]
                    reply.data = %x[puppi init #{project}].chomp
                    if ($?.exitstatus > 0)
                      reply.fail "FAILED: #{reply.data}"
                    end
            end
            
            def configure_action
                  validate :project, :shellsafe
                  project = request[:project] if request[:project]
                  reply.data = %x[puppi configure #{project}].chomp
                  if ($?.exitstatus > 0)
                    reply.fail "FAILED: #{reply.data}"
                  end
            end

        end
    end
end
# vi:tabstop=4:expandtab:ai
#!/bin/bash
# File Managed by Puppet
PATH=$PATH:/usr/local/bin

if [ ! $1 ] ; then
    echo "Provide at least a match pattern. For example:"
    echo "role=fep-pgol"
    exit 1
fi

filtered=$(echo $* | sed "s/[^a-Z0-9= _.\-]//Ig")

randfile="$(mktemp)"

trap "rm -f $randfile" SIGINT SIGTERM EXIT

myarg=$(echo $filtered | sed -e "s/ / -F /g")

mc-puppi check -F $myarg | tee $randfile
grep FAILED $randfile && exit 1
exit 0

#!/bin/bash
# File Managed by Puppet
PATH=$PATH:/usr/local/bin

if [ ! $2 ] ; then
    echo "Provide the hostname and the project you want to deploy:"
    echo "superdeploy web01.example42.com myapp"
    exit 1
fi

filtered=$(echo $* | sed "s/[^a-Z0-9= _.\-]//Ig")

randfile="$(mktemp)"

trap "rm -f $randfile" SIGINT SIGTERM EXIT

myarg=$(echo $filtered | sed -e "s/ / -F /g")

mc-puppi deploy -I $1 $2 | tee $randfile
grep FAILED $randfile && exit 1
exit 0

#!/bin/bash
# archive.sh - Made for Puppi

# Sources common header for Puppi scripts
. $(dirname $0)/header || exit 10

# Show help
showhelp () {
    echo "This script is used to backup or restore contents to/from puppi archivedir"
    echo "It has the following options:"
    echo "-b <backup_source> - Backups the files to be changed in the defined directory"
    echo "-r <recovery_destination> - Recovers file to the provided destination"
    echo "-s <copy|move> - Specifies the backup strategy (move or copy files)"
    echo "-t <tag> - Specifies a tag to be used for the backup"
    echo "-d <variable> - Specifies the runtime variable that defines the predeploy dir"
    echo "-c <yes|no> - Specifies if you want compressed (tar.gz) archives. Default: yes"
    echo "-o 'options' - Specifies the rsync options to use during backup. Use it to specify custom "
    echo "               exclude patterns of files you don't want to archive, for example"
    echo "-m <full|diff> - Specifies the backup type: 'full' backups all the files in backup_source,"
    echo "                 'diff' backups only the files deployed"
    echo "-n <number> - Number of copies of backups to keep on the filesystem. Default 5"
    echo 
    echo "Examples:"
    echo "archive.sh -b /var/www/html/my_app -t html -c yes"
}

# Arguments check
if [ "$#" = "0" ] ; then
    showhelp
    exit
fi

# Default settings
compression=yes
backuptag=all
strategy=copy
backupmethod=full
bakret=5

while [ $# -gt 0 ]; do
  case "$1" in
    -b)
      backuproot=$2
#      [ $deploy_root ] && backuproot=$deploy_root # This is needed to allow override of $deploy_root via puppi cmd. But breaks on puppi::project::maven
      action=backup
      shift 2 ;;
    -r)
      backuproot=$2
#      [ $deploy_root ] && backuproot=$deploy_root # This is needed to allow override of $deploy_root via puppi cmd. But breaks on puppi::project::maven
      action=recovery
      shift 2 ;;
    -t)
      backuptag=$2
      shift 2 ;;
    -s)
      case "$2" in
        mv) strategy="move" ;;
        move) strategy="move" ;;
        *) strategy="copy" ;;
      esac
      shift 2 ;;
    -m)
      case "$2" in
        diff) backupmethod="diff" ;;
        *) backupmethod="full" ;;
      esac
      shift 2 ;;
    -c)
      case "$2" in
        yes) compression="yes" ;;
        y) compression="yes" ;;
        *) compression="none" ;;
      esac
      shift 2  ;;
    -d)
      predeploydir="$(eval "echo \${$(echo $2)}")"
      shift 2 ;;
    -o) 
      rsync_options=$2
      shift 2 ;;
    -n)
      bakret=$2
      shift 2 ;;
    *)
      showhelp
      exit
      ;;
  esac
done


# Backup and Restore functions
backup () {
    mkdir -p $archivedir/$project/$tag/$backuptag
    if [ $archivedir/$project/latest ] ; then
        rm -f $archivedir/$project/latest
    fi
    ln -sf $archivedir/$project/$tag $archivedir/$project/latest

    filelist=$storedir/filelist
    cd $predeploydir
    find . | cut -c 3- | grep -v "^$" > $filelist

    if [ "$strategy" = "move" ] ; then 
        for file in $(cat $filelist) ; do
            mv $backuproot/$file $archivedir/$project/$tag/$backuptag/
        done
        if [ "$backupmethod" = "full" ] ; then
            rsync -a $rsync_options $backuproot/ $archivedir/$project/$tag/$backuptag/
        fi
    else
        if [ "$backupmethod" = "full" ] ; then
            rsync -a $rsync_options $backuproot/ $archivedir/$project/$tag/$backuptag/
        else
            rsync -a $rsync_options --files-from=$filelist $backuproot/ $archivedir/$project/$tag/$backuptag/
        fi
    fi

    if [ "$compression" = "yes" ] ; then
        cd $archivedir/$project/$tag/$backuptag/
        tar -czf ../$backuptag.tar.gz .
        cd $archivedir/$project/$tag/
        rm -rf $archivedir/$project/$tag/$backuptag/
    fi
}

recovery () {
    if [ ! $rollbackversion ] ; then
        echo "Variable rollbackversion must exist!"
        exit 2 
    fi

    if [ -d $archivedir/$project ] ; then
        cd $archivedir/$project
    else 
        echo "Can't find archivedir for this project"
        exit 2
    fi

    if [ "$compression" = "yes" ] ; then
        cd $backuproot/
        tar -xzf $archivedir/$project/$rollbackversion/$backuptag.tar.gz .
    else 
        rsync -a $rsync_options $rollbackversion/$backuptag/* $backuproot
    fi

}

delete_old () {
    # We don't count the "latest" symlink
    bakret=$(expr $bakret + 1 )

    cd $archivedir/$project

    ddirs=$(ls -1p 2>/dev/null | wc -l)
    while [ $ddirs -gt $bakret ]
    do
        victim=$(ls -tr 2>/dev/null | head -1)
        rm -rf $victim && echo "Deleted old $archivedir/$project/$victim"
        ddirs=$(ls -1p 2>/dev/null | wc -l)
    done
}

# Action!
case "$action" in
    backup) backup ; delete_old ;;
    recovery) recovery ;;
esac
#!/bin/bash
# check_project.sh - Made for Puppi
# This script runs the checks defined in $projectsdir/$project/check and then in $checksdir
# It can be used to automatically run tests during the deploy procedure

# Sources common header for Puppi scripts
. $(dirname $0)/header || exit 10

# Main functions
handle_check () {
        RETVAL=$?
        if [ "$RETVAL" = "1" ] ; then
            EXITWARN="1"
        fi
        if [ "$RETVAL" = "2" ] ; then
            EXITCRIT="1"
        fi
}

check () {
    for command in $(ls -v1 $projectsdir/$project/check) ; do
        "$projectsdir/$project/check/$command"
        handle_check
    done

    for command in $(ls -v1 $checksdir) ; do
        "$checksdir/$command" 
        handle_check
    done
}

# For nicer output when launched via cli
echo -n "\n"

# Run checks
check

# Manage general return code
if [ "$EXITCRIT" = "1" ] ; then
    exit 1
fi

if [ "$EXITWARN" = "1" ] ; then
    exit 1
fi
#!/bin/bash
# checkwardir.sh - Made for Puppi

# Sources common header for Puppi scripts
. $(dirname $0)/header || exit 10

# Show help
showhelp () {
    echo "This script is used to check if a webapp directory is successfully created or removed"
    echo " after the (un)deploy of a war file"
    echo "It implies that a directory with the name of the war file is created in the same path"
    echo "-p <warname> - Waits until war created dir is present"
    echo "-a <warname> - Wait until war created dir is absent"
    echo "-s <seconds> - Wait some more seconds after the check"
    echo "-c <configentry> - Name of the runtime config variable that contains the warname"
    echo "Examples:"
    echo "checkwardir.sh -p /store/tomcat/myapp/webapps/myapp.war"
    echo "checkwardir.sh -a /store/tomcat/myoldapp/webapps/myoldapp.war"
}

seconds=2

while [ $# -gt 0 ]; do
  case "$1" in
    -s)
      seconds=$2
      shift 2
      ;;
    -p)
      check="present"
      warname=$2
      shift 2
      ;;
    -a)
      check="absent"
      warname=$2
      shift 2
      ;;
    -c)
      warname="$(eval "echo \${$(echo ${2})}")"      
      shift 2
      ;;
    *)
      showhelp
      exit
      ;;
  esac
done

checkdir () {
    wardir=${warname%\.*}
    while true
       do
        if [ $check == absent ] ; then
            [ ! -d $wardir ] && break
        else
            [ -f $wardir/WEB-INF/web.xml ] && break
        fi
        sleep $seconds
    done
}

checkdir
#!/bin/bash
# clean_filelist.sh - Made for Puppi

# Sources common header for Puppi scripts
. $(dirname $0)/header || exit 10

# Show help
showhelp () {
    echo "This script is used to cleanup a list of files to download from unwanted data"
    echo "It has 1 optional argument:"
    echo "The prefix, present in the list, to cut out when defining files to deploy"
    echo "The list file is defined as $downloadedfile , these variables are gathered from the Puppi runtime"
    echo "  config file."
    echo 
    echo "Example:"
    echo "clean_filelist.sh http://svn.example42.com/myproject"
}


if [ $1 ] ; then
    prefix=$1
else
    prefix=""
fi

deployfilelist=$downloadedfile

# Clean list
cleanlist () {

    sed -i "s/^$prefix//g" $deployfilelist

}

cleanlist
#!/bin/bash
# database.sh - Made for Puppi

# Sources common header for Puppi scripts
. $(dirname $0)/header || exit 10

# Show help
showhelp () {
    echo "This script executes database queries and dumps"
    echo "It integrates and uses variables provided by other core Puppi scripts"
    echo "It has the following options:"
    echo "-t <database_type> The database type. Currently only mysql is suppoerted"
    echo "-a <action> The action to perform:"
    echo "            run - Run a mysql command based on a given .sql file"
    echo "            dump - Dump the specified database in the archive dir"
    echo "            restore - Restore the specified database from the archive dir"
    echo "-d <database_name> The database name to manage"
    echo "-u <database_user> The database user used to run the queries"
    echo "-p <database_password> The user password"
    echo "-h <host> The database server hostname"
}

# Arguments defaults
db_type=mysql
db_action=run
db_user=root
db_host=localhost
db_password=""

# Check Arguments
while [ $# -gt 0 ]; do
  case "$1" in
    -t)
      db_type=$2
      shift 2 ;;
    -a)
      db_action=$2
      shift 2 ;;
    -d)
      db_name=$2
      shift 2 ;;
    -u)
      db_user=$2
      shift 2 ;;
    -p)
      db_password=$2
      shift 2 ;;
    -h)
      db_host=$2
      shift 2 ;;
  esac
done



mysql_run () {
    case "$db_action" in
      run)
        file $downloadedfile | grep gzip &>/dev/null 2>&1 && sqlfile_type="gzip"
        file $downloadedfile | grep Zip &>/dev/null 2>&1 && sqlfile_type="zip"
        case "$sqlfile_type" in
          gzip)
            zcat $downloadedfile | mysql -u $db_user -p$db_password -h $db_host $db_name
            check_retcode ;;
          zip)
            unzip -p $downloadedfile | mysql -u $db_user -p$db_password -h $db_host $db_name
            check_retcode ;;
          *)
            mysql -u $db_user -p$db_password -h $db_host $db_name < $downloadedfile
            check_retcode ;;
        esac
        ;;
      dump)
        mkdir -p $archivedir/$project/$tag
        if [ $archivedir/$project/latest ] ; then
            rm -f $archivedir/$project/latest
        fi
        ln -sf $archivedir/$project/$tag $archivedir/$project/latest

        mysqldump -u $db_user -p$db_password -h $db_host --add-drop-table --databases $db_name | gzip > $archivedir/$project/$tag/$db_name.sql.gz
        check_retcode ;;
      restore)
        zcat $archivedir/$project/$rollbackversion/$db_name.sql.gz | mysql -u $db_user -p$db_password -h $db_host $db_name
        check_retcode ;;
    esac
}

case "$db_type" in
      mysql)
        mysql_run
        ;;
      *)
        showhelp
        ;;
esac

#!/bin/bash
# delete.sh - Made for Puppi

# Sources common header for Puppi scripts
. $(dirname $0)/header || exit 10

# Manage script variables
if [ $1 ] ; then
    tobedeleted=$1
else
    echo "You must provide a file or directory to delete!"
    exit 2 
fi

if [ "$tobedeleted" = "/" ] ; then
    echo "Be Serious!"
    exit 2
fi

# Move file
move () {
    mkdir -p $workdir/$project/deleted
    mv $tobedeleted $workdir/$project/deleted
}

move
#!/bin/bash
# deploy.sh - Made for Puppi

# Sources common header for Puppi scripts
. $(dirname $0)/header || exit 10

# Show help
showhelp () {
    echo "This script deploys the files present in the \$predeploydir to the deploy destination dir"
    echo "It has the following options:"
    echo "\$1 (Required) - Destination directory where to deploy files"
    echo "\$2 (Optional) - Name of the variable that identifies a specific predeploydir"
    echo 
    echo "Examples:"
    echo "deploy.sh /var/www/html/my_app"
    echo "deploy.sh /var/www/html/my_app/conf config"
}

# Check arguments
if [ $1 ] ; then
    deploy_destdir=$1
# This breaks on projects::maven when using more than one deploy destinations
#    [ $deploy_root ] && deploy_destdir=$deploy_root
else
    showhelp
    exit 2 
fi

# Obtain the value of the variable with name passed as second argument
# If no one is given, we take all the files in $predeploydir
if [ $2 ] ; then
    deployfilevar=$2
    deploy_sourcedir="$(eval "echo \${$(echo ${deployfilevar})}")"
    if [ "$deploy_sourcedir" = "" ] ; then
        exit 0
    fi
else
    deploy_sourcedir="$predeploydir"
fi

# Copy files
deploy () {
    case "$debug" in
        yes)
            rsync -rlptDv $deploy_sourcedir/ $deploy_destdir/
            check_retcode
        ;;
        full)
            rsync -rlptDv $deploy_sourcedir/ $deploy_destdir/
            check_retcode
        ;;
        *)
            rsync -rlptD $deploy_sourcedir/ $deploy_destdir/
            check_retcode
        ;;
    esac
}

deploy
#!/bin/bash
# deploy_files.sh - Made for Puppi
# This is an extended version of the deploy script
# It accepts more options to better handle how files are deployed
# in the destination directory

# Sources common header for Puppi scripts
. $(dirname $0)/header || exit 10

# Show help
showhelp () {
    echo "This script deploys the files present in the \$predeploydir to the deploy destination dir"
    echo "It has the following options:"
    echo "-d <path> (Required) - Destination directory where to deploy files"
    echo "-p <name> (Optional) - Name of the variable that identifies a specific predeploydir"
    echo "-c <true|false> (Default: false) - If to enabled the --delete option to the rsync command"
    echo 
    echo "Examples:"
    echo "deploy_files.sh -d /var/www/html/my_app"
    echo "deploy_files.sh -d /var/www/html/my_app/conf -p config"
    echo "deploy_files.sh -d /var/www/html/my_app/conf -c true"
}

deploy_sourcedir="$predeploydir"
clean_destdir="false"

while [ $# -gt 0 ]; do
  case "$1" in
    -d)
      deploy_destdir=$2
      shift 2 ;;
    -p)
      deployfilevar=$2
      deploy_sourcedir="$(eval "echo \${$(echo ${deployfilevar})}")"
      shift 2 ;;
    -c)
      clean_destdir=$2
      shift 2 ;;
    *)
      showhelp
      exit
      ;;
  esac
done

rsync_delete=""
if [ x$clean_destdir == "xtrue" ] ; then
  rsync_delete="--delete"
fi

# Copy files
deploy () {
    case "$debug" in
        yes)
            rsync -rlptDv $rsync_delete $deploy_sourcedir/ $deploy_destdir/
            check_retcode
        ;;
        full)
            rsync -rlptDv $rsync_delete $deploy_sourcedir/ $deploy_destdir/
            check_retcode
        ;;
        *)
            rsync -rlptD $rsync_delete $deploy_sourcedir/ $deploy_destdir/
            check_retcode
        ;;
    esac
}

deploy
#!/bin/bash
# execute.sh - Made for Puppi
# This script just executes what is passed as argument

# Sources common header for Puppi scripts
. $(dirname $0)/header || exit 10

#parse variables
command=$(eval "echo "$*"")

#execute command
eval "${command}"
#!/bin/bash
# firewall.sh - Made for Puppi

# Sources common header for Puppi scripts
. $(dirname $0)/header || exit 10

# Show help
showhelp () {
    echo "This script places a temporary firewall (iptables) rule to block access from the IP defined"
    echo "It has the following options:"
    echo "\$1 (Required) - Remote Ip address to block (Generally a load balancer"
    echo "\$2 (Required) - Local port to block (0 for all ports"
    echo "\$3 (Required) - Set on or off to insert or remove the blocking rule"
    echo "\$4 (Required) - Number of seconds to sleep after having set the rule"
    echo 
    echo "Examples:"
    echo "firewall.sh 10.42.0.1 0 on"
    echo "firewall.sh 10.42.0.1 0 off"
}

# Check arguments
if [ $2 ] ; then
    ip=$1
    port=$2
else
    showhelp
    exit 2 
fi

if [ $3 ] ; then
    if [ "$3" = "on" ] ; then
        action="-I"
    elif [ "$3" = "off" ] ; then
        action="-D"
    else 
        showhelp
        exit 2
    fi
else
    showhelp
    exit 2
fi

if [ $4 ] ; then
    delay=$4
else
    delay="1"
fi

# Block
run_iptables () {
    if [ "$port" = "0" ] ; then
        iptables $action INPUT -s $ip -j DROP
    else
        iptables $action INPUT -s $ip -p tcp --dport $port -j DROP
    fi
}

run_iptables
echo "Sleeping for $delay seconds"
sleep $delay

# Sooner or later this script will have multiOS support
#!/bin/bash
# General Puppi functions

BOOTUP=color
RES_COL=75
MOVE_TO_COL="echo -en \\033[${RES_COL}G"
SETCOLOR_SUCCESS="echo -en \\033[0;32m"
SETCOLOR_FAILURE="echo -en \\033[0;31m"
SETCOLOR_WARNING="echo -en \\033[0;33m"
SETCOLOR_NORMAL="echo -en \\033[0;39m"
SETCOLOR_TITLE="echo -en \\033[0;35m"
SETCOLOR_BOLD="echo -en \\033[0;1m"

echo_success() {
  [ "$BOOTUP" = "color" ] && $MOVE_TO_COL
  echo -n "["
  [ "$BOOTUP" = "color" ] && $SETCOLOR_SUCCESS
  echo -n $"  OK  "
  [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
  echo -n "]"
  echo -ne "\r"
  return 0
}

echo_dontdeploy() {
  [ "$BOOTUP" = "color" ] && $MOVE_TO_COL
  echo -n "["
  [ "$BOOTUP" = "color" ] && $SETCOLOR_SUCCESS
  echo -n $" NO NEED TO DEPLOY "
  [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
  echo -n "]"
  echo -ne "\r"
  return 0
}

echo_failure() {
  [ "$BOOTUP" = "color" ] && $MOVE_TO_COL
  echo -n "["
  [ "$BOOTUP" = "color" ] && $SETCOLOR_FAILURE
  echo -n $"FAILED"
  [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
  echo -n "]"
  echo -ne "\r"
  return 1
}

echo_passed() {
  [ "$BOOTUP" = "color" ] && $MOVE_TO_COL
  echo -n "["
  [ "$BOOTUP" = "color" ] && $SETCOLOR_WARNING
  echo -n $"PASSED"
  [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
  echo -n "]"
  echo -ne "\r"
  return 1
}

echo_warning() {
  [ "$BOOTUP" = "color" ] && $MOVE_TO_COL
  echo -n "["
  [ "$BOOTUP" = "color" ] && $SETCOLOR_WARNING
  echo -n $"WARNING"
  [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
  echo -n "]"
  echo -ne "\r"
  return 1
}

echo_title () {
  echo
  echo
  [ "$BOOTUP" = "color" ] && $SETCOLOR_TITLE
  echo "$1"
  [ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
}

check_retcode () {
    if [ $? = "0" ] ; then
        true
    else
        exit 2
    fi
}

handle_result () {
        RETVAL=$?
        if [ "$RETVAL" = "0" ] ; then
            showresult="echo_success"
            result="OK"
        fi
        if [ "$RETVAL" = "1" ] ; then
            showresult="echo_warning"
            EXITWARN="1"
            result="WARNING"
        fi
        if [ "$RETVAL" = "2" ] ; then
            showresult="echo_failure"
            EXITCRIT="1"
            result="CRITICAL"
        fi
        if [ "$RETVAL" = "99" ] ; then
            showresult="echo_dontdeploy"
            DONTDEPLOY="1"
            result="OK"
        fi
        if [ x$show == "xyes" ] ; then
            $showresult
            echo
            echo -e "$output"
            echo
        elif [ x$show == "xfail" ] && [ x$RETVAL != "x0" ] ; then
            $showresult
            echo
            echo -e "$output"
            echo
        fi

        # Output to file
        if [ ! -d $logdir/$project/$tag ] ; then
            mkdir -p $logdir/$project/$tag
        fi
        let counter=counter+1
        echo $title > $logdir/$project/$tag/$counter-$command
        echo $code >> $logdir/$project/$tag/$counter-$command
        echo $result >> $logdir/$project/$tag/$counter-$command
        echo $output >> $logdir/$project/$tag/$counter-$command

}


# Function taken from http://www.threadstates.com/articles/parsing_xml_in_bash.html
xml_parse () {
    local tag=$1
    local xml=$2

    # Find tag in the xml, convert tabs to spaces, remove leading spaces, remove the tag.
    grep $tag $xml | \
        tr '\011' '\040' | \
        sed -e 's/^[ ]*//' \
            -e 's/^<.*>\([^<].*\)<.*>$/\1/'
}

# Stores the passed arguments in Project runtime config file
# Only if the parameter is not already defined
# Usage:
# save_runtime_config parameter=value # Sets or overrides parameter
# save_runtime_config parameter=value notforce # Sets parameters only if is not already set
save_runtime_config () {
    parameter=$(echo $1 | cut -d '=' -f1)
    value=$(echo $1 | cut -d '=' -f2-)
    force=$2

    if [[ ! $(grep $parameter $workdir/$project/config) ]] ; then
        echo  >> $workdir/$project/config
        echo "# Added by $0" >> $workdir/$project/config
        echo "$parameter=\"$value\"" >> $workdir/$project/config
    else
#        sed -i "/^$parameter=/d" $workdir/$project/config # No real need to remove lines with old configs
        if [[ x$force == xnotforce ]] ; then
            echo  >> $workdir/$project/config
            echo "# CHANGE NOT FORCED by $0" >> $workdir/$project/config
            echo "# $parameter=\"$value\"" >> $workdir/$project/config
        else
            echo  >> $workdir/$project/config
            echo "# CHANGED by $0" >> $workdir/$project/config
            echo "$parameter=\"$value\"" >> $workdir/$project/config
       fi
    fi
    
}

# Adds a runtime comment to Project runtime config file
save_runtime_comment () {
    echo  >> $workdir/$project/config
    echo "# Added by $0" >> $workdir/$project/config
    echo "  ## $1" >> $workdir/$project/config
}


# Stores the passed arguments in Project runtime config file
# Forces parameter overwrite if already defined
overwrite_runtime_config () {
    echo "$1" >> $workdir/$project/config
}

ask_interactive () {
    if [ x$show == "xyes" ] ; then
        echo -n $title
    fi

    if [ "$interactive" = "yes" ] ; then
        echo 
        echo "INTERACTIVE MODE: Press 'x' to exit or just return to go on" 
        read press
        case $press in 
            x) exit 2 ;;
            *) return
        esac
    fi
}

# Shows or executes a command
show_command () {
   echo
   $SETCOLOR_BOLD ; echo "$HOSTNAME: $*" ; $SETCOLOR_NORMAL

   bash -c "$*"

# Grep filter at show_command level
#   if [ ! -z "$greppattern" ] ; then
#       bash -c "$*" | grep $greppattern
#   else
#       bash -c "$*"
#   fi
}

# Filtering out only:  $ ; ` | < >
shell_filter () {
    echo $1 | sed 's/\$//g' | sed 's/;//g' | sed 's/`//g' | sed 's/|//g' | sed 's/<//g' | sed 's/>//g'
}

shell_filter_strict () {
# Filtering out:  $ ; ` | < > = ! { } [ ] / \ # &
    echo $1 | sed 's/\$//g' | sed 's/;//g' | sed 's/`//g' | sed 's/|//g' | sed 's/<//g' | sed 's/>//g'  | sed 's/=//g' | sed 's/!//g' | sed 's/{//g' | sed 's/}//g' | sed 's/\[//g' | sed 's/\]//g' | sed 's/\///g' | sed 's/\\//g' | sed 's/#//g' | sed 's/&//g'

# Filtering out: all but accepted chars
#     echo $1 | sed "s/[^a-Z0-9_\-]//Ig"
}

#!/bin/bash
# get_file.sh - Made for Puppi

# Sources common header for Puppi scripts
. $(dirname $0)/header || exit 10

# Show help
showhelp () {
    echo "This script is used to retrieve the file defined after the -s parameter"
    echo "The source specified  can be any of these:"
    echo "  file://local/file/path"
    echo "  http(s)://my.server/file/path"
    echo "  ssh://user@my.server/file/path"
    echo "  svn://user:password@my.server/file/path"
    echo "Note: Avoid using chars like : / and @ outside the Uri standards paths"
    echo
    echo "It has the following options:"
    echo "-s <source_file> - The URL of the file to get"
    echo "-t <file_type> - The type of file that is retrieved: list|tarball|maven-metadata|dir"
    echo "-d <local_dir> - An alternative destination directory (default is automatically chosen)"
    echo "-a <yes|no> - If 'no' return a special error code (99) if the download checksum is the same of the one previously downloaded"
    echo "-u <http_user> - in case of type http, specify a http_user for curl"
    echo "-p <http_password> - in case of type http, specifiy http_user for curl"
    echo "-k - tell curl not to validate ssl certs"
    echo "              This option can be used for automatic deploys (ie via cron) that actually deploy only new changes"
}

while [ $# -gt 0 ]; do
  case "$1" in
    -s)
      type=$(echo $2 | cut -d':' -f1)
      url=$2
      downloadfilename=$(basename $2)
      downloaddir=$predeploydir
      shift 2 ;;
    -t)
      case $2 in
      # This logic is applied:
      # In $predeploydir go ($workdir/$project/deploy) go file that have to be deployed
      # In $storedir go ($workdir/$project/store) go support files as tarballs or lists
          list)
          downloaddir=$storedir
          save_runtime_config "source_type=list"
          ;;
          tarball)
          downloaddir=$storedir
          save_runtime_config "source_type=tarball"
          ;;
          tar)
          downloaddir=$storedir
          save_runtime_config "source_type=tar"
          ;;
          zip)
          downloaddir=$storedir
          save_runtime_config "source_type=zip"
          ;;
          maven-metadata)
          downloaddir=$storedir
          save_runtime_config "source_type=maven"
          ;;
          dir)
          downloaddir=$predeploydir
          save_runtime_config "source_type=dir"
          ;;
          war)
          downloaddir=$predeploydir
          save_runtime_config "source_type=war"
          ;;
          mysql)
          downloaddir=$storedir
          save_runtime_config "source_type=mysql"
          ;;
          gz)
          downloaddir=$storedir
          save_runtime_config "source_type=gz"
          ;;
      esac
      shift 2 ;;
    -d)
      # Enforces and overrides and alternative downloaddir
      downloaddir=$2
      shift 2 ;;
    -a)
      alwaysdeploy=$2
      shift 2 ;;
    -u)
      http_user=$2
      shift 2 ;;
    -p)
      http_password=$2
      shift 2 ;;
    -k)
      ssl_arg=$1
      shift 1 ;;
    *)
      showhelp
      exit
      ;;
  esac
done

# Define what to use for downloads
cd $downloaddir

case $type in
    s3)
        s3cmd get $url
        check_retcode
        save_runtime_config "downloadedfile=$downloaddir/$downloadfilename"
    ;;
    ssh|scp) 
        # ssh://user@my.server/file/path
        scpuri=$(echo $url | cut -d'/' -f3-)
        scpconn=$(echo $scpuri | cut -d'/' -f1)
        scppath=/$(echo $scpuri | cut -d'/' -f2-)
        rsync -rlptD -e ssh $scpconn:$scppath .
        check_retcode
        save_runtime_config "downloadedfile=$downloaddir/$downloadfilename"
    ;;
    http|https)
        if [ -z "$http_password" ] ; then
          curl $ssl_arg -s -f -L "$url" -O
        else
          curl $ssl_arg -s -f -L --anyauth --user $http_user:$http_password "$url" -O
	fi
        check_retcode
        save_runtime_config "downloadedfile=$downloaddir/$downloadfilename"
    ;;
    svn)
        svnuri=$(echo $url | cut -d'/' -f3-)
        svnusername=$(echo $svnuri | cut -d':' -f1)
        svnpassword=$(echo $svnuri | cut -d':' -f2 | cut -d'@' -f1)
        svnserver=$(echo $svnuri | cut -d'@' -f2 | cut -d'/' -f1)
        svnpath=/$(echo $svnuri | cut -d'@' -f2 | cut -d'/' -f2-)
        mkdir -p $(dirname $svnpath)
        svn export --force --username="$svnusername" --password="$svnpassword" svn://$svnserver/$svnpath $downloaddir
        check_retcode
        save_runtime_config "downloadedfile=$downloaddir/$downloadfilename"
    ;;
    file)
        # file:///file/path
        filesrc=$(echo $url | cut -d '/' -f3-)
        rsync -rlptD $filesrc .
        check_retcode
        save_runtime_config "downloadedfile=$downloaddir/$downloadfilename"
    ;;
    rsync)
        rsync -a "$url" .
        # rsync -rlptD $url . # Why not preserving users/groups?
        check_retcode
        save_runtime_config "downloadedfile=$downloaddir/$downloadfilename"
    ;;

esac

if [ x$alwaysdeploy == "xno" ] ; then
    # Here is checked the md5sum of the downloaded file against a previously save one
    # If the sums are the same the scripts exits 99 and puppi will stop the deploy without any warning or notification
    [ -d $archivedir/$project ] || mkdir -p $archivedir/$project
    touch $archivedir/$project/md5sum
    md5sum $downloaddir/$downloadfilename > $workdir/$project/md5sum_downloaded
    cat $archivedir/$project/md5sum > $workdir/$project/md5sum_deployed
    diff $workdir/$project/md5sum_downloaded $workdir/$project/md5sum_deployed && exit 99
    md5sum $downloaddir/$downloadfilename > $archivedir/$project/md5sum
fi
#!/bin/bash
# get_filesfromlist.sh - Made for Puppi

# Sources common header for Puppi scripts
. $(dirname $0)/header || exit 10

# Show help
showhelp () {
    echo "This script is used to retrieve the files present in a text file list."
    echo "It has 1 required argument:"
    echo "First argument (\$1 - required) is the base url (in URI format) from where to retrieve the files defined in the list"
    echo "The list file is defined as \$downloadedfile , these variables are gathered from the Puppi runtime"
    echo "  config file."
    echo 
    echo "Examples: "
    echo "get_filesfromlist.sh http://svn.example42.com/myproject"
    echo "get_filesfromlist.sh file:///mount/wwwdata/myproject"
    echo "get_filesfromlist.sh ssh://user@server/var/www/myproject"
    echo "get_filesfromlist.sh svn://user:password@server/repo/myproject"
}


if [ $1 ] ; then
    baseurl=$1
    type=$(echo $1 | cut -d':' -f1)
else
    showhelp
    exit 2 
fi


# Download files
downloadfiles () {

    cd $predeploydir

    for file in $(cat $downloadedfile | grep -v "^#" | grep -v "^$" ) ; do
        filepath=$file
        filedir=$(dirname $filepath)
        mkdir -p $filedir
        check_retcode
        
        case $type in 
            ssh|scp) 
                scp "$baseurl:$filepath" $filepath
                check_retcode
            ;;
            http|https|file)
                curl -s -f "$baseurl/$filepath" -o $filepath
                check_retcode
            ;;
            svn)
                svnuri=$(echo $baseurl/$filepath | cut -d'/' -f3-)
                svnusername=$(echo $svnuri | cut -d':' -f1)
                svnpassword=$(echo $svnuri | cut -d':' -f2 | cut -d'@' -f1)
                svnserver=$(echo $svnuri | cut -d'@' -f2 | cut -d'/' -f1)
                svnpath=/$(echo $svnuri | cut -d'@' -f2 | cut -d'/' -f2-)
                mkdir -p $(dirname $svnpath)
                svn export --force --username="$svnusername" --password="$svnpassword" http://$svnserver/$svnpath $(dirname $svnpath)
                check_retcode
            ;;
        esac

    done
}

downloadfiles
#!/bin/bash
# get_maven_files.sh - Made for Puppi
# This script retrieves the files to deploy from a Maven repository.
# It uses variables defined in the general and project runtime configuration files.
# It uses curl to retrieve files so the $1 argument (base url of the maven repository) 
# has to be in curl friendly format
#   It has the following options:
#   -u <http_user> - in case of type http, specify a http_user for curl
#   -p <http_password> - in case of type http, specifiy http_user for curl

# Sources common header for Puppi scripts
. $(dirname $0)/header || exit 10

while [ $# -gt 0 ]; do
  case "$1" in
    -u)
      http_user=$2
      shift 2 ;;
    -p)
      http_password=$2
      shift 2 ;;
    *)
      url=$1
      ftype=$2
      shift 2 ;;
  esac
done

# Obtain the value of the variable with name passed as second argument
# If no one is given, we take all the files in storedir

#echo "Download and deploy $2 ? (Y/n)" 
#read press
#case $press in 
#    Y|y) true ;;
#    N|n) save_runtime_config "predeploydir_$2=" ; exit 0
#esac

if [ $debug ] ; then
    tarcommand="tar -xvf"
else
    tarcommand="tar -xf"
fi

if [ $debug ] ; then
    zipcommand="unzip"
else
    zipcommand="unzip -q"
fi

cd $storedir

if [ -z "$http_password" ] ; then
    authparam=""
else
    authparam="--anyauth --user $http_user:$http_password"
fi

case $ftype in
    warfile)
        curl -s -f $authparam "$url/$version/$warfile" -O
        check_retcode
        cp -a $warfile $predeploydir/$artifact.war
        save_runtime_config "deploy_warpath=$deploy_root/$artifact.war"
    ;;
    jarfile)
        curl -s -f $authparam "$url/$version/$jarfile" -O
        check_retcode
        cp -a $jarfile $predeploydir/$artifact.jar
        save_runtime_config "deploy_jarpath=$deploy_root/$artifact.jar"
    ;;
    configfile)
        curl -s -f $authparam "$url/$version/$configfile" -O
        check_retcode
        mkdir $workdir/$project/deploy_configfile
        cd $workdir/$project/deploy_configfile
        $tarcommand $storedir/$configfile
        check_retcode
        save_runtime_config "predeploydir_configfile=$workdir/$project/deploy_configfile"
    ;;
    srcfile)
        curl -s -f $authparam "$url/$version/$srcfile" -O
        check_retcode
        mkdir $workdir/$project/deploy_srcfile
        cd $workdir/$project/deploy_srcfile
        $tarcommand $storedir/$srcfile
        check_retcode
        save_runtime_config "predeploydir_srcfile=$workdir/$project/deploy_srcfile"
    ;;
    zipfile)
        curl -s -f $authparam "$url/$version/$zipfile" -O
        check_retcode
        mkdir $workdir/$project/deploy_zipfile
        cd $workdir/$project/deploy_zipfile
        $zipcommand $storedir/$zipfile
        check_retcode
        save_runtime_config "predeploydir_zipfile=$workdir/$project/deploy_zipfile"
    ;;
esac
#!/bin/bash
# get_metadata.sh - Made for Puppi

# Sources common header for Puppi scripts
. $(dirname $0)/header || exit 10

# Show help
showhelp () {
    echo "This script retrieves some metadata from the downwloaded files "
    echo "The metadatasource is automatically detected from the \$source_type runtime config"
    echo
    echo "It has some, not required, options:"
    echo "-m <magicstring> - The string to use as *fix in custom metadata info provided "
    echo "-mc <anotherstring> - The string to use as qualifier for Maven metadata config tars"
    echo "-mj <anotherstring> - The string to use as qualifier for Maven metadata jars"
    echo "-mw <anotherstring> - The string to use as qualifier for Maven metadata wars"
    echo "-mz <anotherstring> - The string to use as qualifier for Maven metadata zips"
    echo "-at <anotherstring> - The type to obtain the artifact, should be \"release\", "
    echo "                      \"latest\", \"snapshot\" or a specific version (e.g. \"2.5.0\")"
}

while [ $# -gt 0 ]; do
  case "$1" in
    -m)
      suffix=$2
      shift 2 ;;
    -mc)
      config_suffix=$2
      shift 2 ;;
    -mj)
      jar_suffix=$2
      shift 2 ;;
    -mw)
      war_suffix=$2
      shift 2 ;;
    -mz)
      zip_suffix=$2
      shift 2 ;;
    -at)
      artifact_type=$2
      shift 2 ;;
    -h)
      showhelp ;;
  esac
done

# validating input
# see http://docs.codehaus.org/display/MAVEN/Repository+Metadata for specs
case $artifact_type in
    release)
    ;;
    latest)
    ;;
    snapshot)
    ;;
    *)
    # defaulting to version 
    version=$artifact_type
    ;;
esac

case $source_type in
    list)
    if [ -z $suffix ] ; then
        suffix="####"
    fi
    # TODO Make this more secure, for God's sake!
    for param in $(cat $downloadedfile | grep "^$suffix" ) ; do
        save_runtime_comment $param
    done
    ;;
    tarball)
    ;;
    maven)
    [ ${#version} -eq 0 ] && version=$(xml_parse $artifact_type $downloadedfile )
    artifact=$(xml_parse artifactId $downloadedfile )

    # Definition of qualifiers for Maven has changed from the (wrong) assumption
    # of having cfg-$suffix and src-$suffix for staticfiles and config tarballs
    # to a more flexible management of qualifiers names with two different params (-m and -mc)
    # The "suffixnotset" string is passed by default by the Puppi maven define
    # YES, it's crap. 
    if [[ x$suffix != "xsuffixnotset" ]] ; then
        srcfile=$artifact-$version-$suffix.tar
    else 
        srcfile=$artifact-$version.tar
    fi

    if [[ x$config_suffix != "xsuffixnotset" ]] ; then
        configfile=$artifact-$version-$config_suffix.tar
    else
        configfile=$artifact-$version.tar
    fi

    if [[ x$jar_suffix != "xsuffixnotset" ]] ; then
        jarfile=$artifact-$version-$jar_suffix.jar
    else
        jarfile=$artifact-$version.jar
    fi

    if [[ x$war_suffix != "xsuffixnotset" ]] ; then
        warfile=$artifact-$version-$war_suffix.war
    else
        warfile=$artifact-$version.war
    fi

    if [[ x$zip_suffix != "xsuffixnotset" ]] ; then
        zipfile=$artifact-$version-$zip_suffix.zip
    else
        zipfile=$artifact-$version.zip
    fi

    # Store metadata
    save_runtime_config "version=$version" 
    save_runtime_config "artifact=$artifact"
    # Store filenames
    save_runtime_config "zipfile=$zipfile"
    save_runtime_config "warfile=$warfile"
    save_runtime_config "jarfile=$jarfile"
    save_runtime_config "srcfile=$srcfile" 
    save_runtime_config "configfile=$configfile" 
    ;;
esac

#!/bin/bash
# git.sh - Made for Puppi

# All variables are exported
set -a 

# Sources common header for Puppi scripts
. $(dirname $0)/header || exit 10

# Show help
showhelp () {
    echo "This script performs the git operations required by puppi::project::git"
    echo "It integrates and uses variables provided by other core Puppi scripts"
    echo "It has the following options:"
    echo "-a <action> (Optional) What action to perform. Available options: deploy (default), rollback"
    echo "-s <source> (Required) Git source repo to use"
    echo "-d <destination> (Required) Directory where files are deployed"
    echo "-u <user> (Optional) User that performs the deploy operations. Default root"
    echo "-gs <git_subdir> (Optional) If only a specific subdir of the gitrepo has to be copied to the install destination"
    echo "-t <tag> (Optional) Tag to deploy"
    echo "-b <branch> (Optional) Branch to deploy"
    echo "-c <commit> (Optional) Commit to deploy"
    echo "-v <true|false> (Optional) If verbose"
    echo "-k <true|false> (Optional) If .git dir is kept on deploy_root"
    echo 
    echo "Examples:"
    echo "git.sh -a deploy -s $source -d $deploy_root -u $user -gs $git_subdir -t $tag -b $branch -c $commit -v $bool_verbose -k $bool_keep_gitdata"
}

verbose="true"

# Check Arguments
while [ $# -gt 0 ]; do
  case "$1" in
    -a)
      case $2 in
          rollback)
          action="rollback"
          ;;
          *)
          action="install"
          ;;
      esac 
      shift 2 ;;
    -s)
      if [ $source ] ; then
        source=$source
      else
        source=$2
      fi
      shift 2 ;;
    -d)
      if [ $deploy_root ] ; then
        deploy_root=$deploy_root
      else
        deploy_root=$2
      fi
      shift 2 ;;
    -u)
      if [ $user ] ; then
        deploy_user=$user
      else
        deploy_user=$2
      fi
      shift 2 ;;
    -gs)
      if [ $git_subdir ] ; then
        git_subdir=$git_subdir
      else
        git_subdir=$2
      fi
      shift 2 ;;
    -t)
      if [ $git_tag ] ; then
        git_tag=$git_tag
      else
        git_tag=$2
      fi
      shift 2 ;;
    -b)
      if [ $branch ] ; then
        branch=$branch
      else
        branch=$2
      fi
      shift 2 ;;
    -c)
      if [ $commit ] ; then
        commit=$commit
      else
        commit=$2
      fi
      shift 2 ;;
    -v)
      if [ $verbose ] ; then
        verbose=$verbose
      else
        verbose=$2
      fi
      shift 2 ;;
    -k)
      if [ $keep_gitdata ] ; then
        keep_gitdata=$keep_gitdata
      else
        keep_gitdata=$2
      fi
      shift 2 ;;
    *)
      showhelp
      exit ;;
  esac
done

if [ "x$verbose" == "xtrue" ] ; then
  verbosity=""
else
  verbosity="--quiet"
fi

cd /

gitsubdir=""
gitdir=$deploy_root
if [ "x$keep_gitdata" != "xtrue" ] ; then
  if [ ! -d $archivedir/$project-git ] ; then
    mkdir $archivedir/$project-git
    chown -R $deploy_user:$deploy_user $archivedir/$project-git
  fi
  gitdir=$archivedir/$project-git/gitrepo
fi
if [ "x$git_subdir" != "xundefined" ] ; then
  if [ ! -d $archivedir/$project-git ] ; then
    mkdir $archivedir/$project-git
    chown -R $deploy_user:$deploy_user $archivedir/$project-git
  fi
  gitdir=$archivedir/$project-git
  gitsubdir="$git_subdir/"
fi

do_install () {
  if [ -d $gitdir/.git ] ; then
    cd $gitdir
    git pull $verbosity origin $branch
    git checkout $verbosity $branch
    if [ "x$?" != "x0" ] ; then
      git checkout -b $verbosity $branch
    fi
  else
    git clone $verbosity --branch $branch --recursive $source $gitdir
    cd $gitdir
  fi

  if [ "x$git_tag" != "xundefined" ] ; then
    git checkout $verbosity $git_tag
  fi

  if [ "x$commit" != "xundefined" ] ; then
    git checkout $verbosity $commit
  fi

  if [ "x$gitdir" == "x$archivedir/$project-git" ] ; then
    rsync -a --exclude=".git" $gitdir/$gitsubdir $deploy_root/
  fi

}

do_rollback () {

  echo "Rollback not yet supported"
}

# Action!
case "$action" in
    install) export -f do_install ; su $deploy_user -c do_install ;;
    rollback) do_rollback ;;
esac
configfile="/etc/puppi/puppi.conf"

# Load general configurations
if [ ! -f $configfile ] ; then
    echo "Config file: $configfile not found"
    exit 2
else
    . $configfile
    . $scriptsdir/functions
fi

# Load project runtime configuration
projectconfigfile="$workdir/$project/config"
if [ ! -f $projectconfigfile ] ; then
    echo "Project runtime config file: $projectconfigfile not found"
    exit 2
else
    . $projectconfigfile
fi

# Activate debug 
case "$debug" in
    yes) set -x  ;;
    full) set -xv  ;;
esac
#!/bin/bash
# predeploy.sh - Made for Puppi

# Sources common header for Puppi scripts
. $(dirname $0)/header || exit 10

# Show help
showhelp () {
    echo "This script prepares the contents of the predeploy directory"
    echo "It integrates and uses variables provided by other core Puppi scripts"
    echo "It has the following options:"
    echo "-v <variable_name> (optional) Name of the variable that identifies the file to untar/unzip"
    echo "                              By default is used $downloadedfile"
    echo "-t <file_type> (optional) The type of file that is retrieved: zip|tarball"
    echo "                          By default is used $source_type "
    echo "-m <magicfix> (optional) The prefix (directory) you may not want to put in the deploy"
    echo "                       Use this if the zip or tar contain a base dir (as often) and you want to copy"
    echo "                       to the deploy dir only its contents and not the whole directory"
    echo 
    echo "Examples:"
    echo "predeploy.sh "
    echo "predeploy.sh -t zip"
    echo "predeploy.sh -t zip -v myz"
}


# Check Arguments
while [ $# -gt 0 ]; do
  case "$1" in
    -v)
      downloadedfile="$(eval "echo \${$(echo ${2})}")"
      shift 2 ;;
    -t)
      source_type=$2
      shift 2 ;;
    -m)
      predeploy_dirprefix=$2
      shift 2 ;;
  esac
done



predeploy () {
    cd $predeploydir
    case "$source_type" in
      tarball)
        case "$debug" in
          yes|full)
            tar -zxvf $downloadedfile
            check_retcode
          ;;
          *)
            tar -zxf $downloadedfile
            check_retcode
          ;;
        esac
        ;;
      zip)
        case "$debug" in
          yes|full)
            unzip $downloadedfile
            check_retcode
          ;;
          *)
            unzip -qq $downloadedfile
            check_retcode
          ;;
        esac
        ;;
      gz)
        case "$debug" in
          yes|full)
            gzip -d $downloadedfile
            check_retcode
          ;;
          *)
            gzip -d -q $downloadedfile
            check_retcode
          ;;
        esac
        ;;
      war)
        cp $downloadedfile .
        check_retcode
        ;;
    esac
}

predeploy

# Updates predeploydir if a directory prefix exists
if [[ x$predeploy_dirprefix != "x" ]] ; then
   save_runtime_config "predeploydir=$predeploydir/$predeploy_dirprefix"
fi
#!/bin/bash
# predeploy_tar.sh - Made for Puppi

# Sources common header for Puppi scripts
. $(dirname $0)/header || exit 10

# Show help
showhelp () {
    echo "This script unpacks (tar) file from the download dir (storedir) to the predeploydir"
    echo "It has the following options:"
    echo "\$1 (Required) - Name of the variable that identifies the tar to predeploy"
    echo 
    echo "Examples:"
    echo "predeploy_tar.sh tarfile"
}

# Check Arguments
if [ $1 ] ; then
    deployfilevar=$1
    deployfile="$(eval "echo \${$(echo ${deployfilevar})}")"
else
    showhelp
    exit 2 
fi

# Untar  file
untar () {
    cd $predeploydir
#    file $deployfile | grep gzip 2>&1>/dev/null
#    if [ $? == "0"] ; then
        tar -zxf $deployfile
#    else
#        tar -xvf $deployfile
#    fi
}

untar
#!/bin/bash
# report_mail.sh - Made for Puppi
# This script sends a summary mail to the recipients defined in $1
# Use a comma separated list for multiple emails

# Sources common header for Puppi scripts
. $(dirname $0)/header || exit 10

# Check arguments & eventually apply runtimeconfig overwrite
recipients=$1
[ $report_email ] && recipients=$report_email

# Main functions
mail_send () {
    result=$(grep result $logdir/$project/$tag/summary | awk '{ print $NF }')
    cat $logdir/$project/$tag/summary | mail -s "[puppi] $result $action of $project on $(hostname)" $recipients
}

mail_send

if [ "$EXITCRIT" = "1" ] ; then
    exit 2
fi

if [ "$EXITWARN" = "1" ] ; then
    exit 1
fi
#!/bin/bash

# report_mongodb.sh - Made for Puppi
# e.g. somemongohost/dbname

# Sources common header for Puppi scripts
. $(dirname $0)/header || exit 10


# Show help
showhelp () {
    echo "This script reports deployments to a mongo DB."
    echo "It has the following options:"
    echo "-e <env_key> - Facter key to identify server environment (default: env)."
    echo "If no facter key can be found, the fallback is ''environment''."
    echo 
    echo "Examples:"
    echo "deploy_files.sh mongodb://someuser:hispassword@somehost/somedb"
    echo "deploy_files.sh -e env mongodb://someuser:hispassword@somehost/somedb"
}


env_key="env"
fallback_key="environment"

while [ $# -gt 0 ]; do
  case "$1" in
    -e)
      env_key=$2
      echo "env_key"
      shift 2 ;;
    *)
      mongourl=$1
      shift 1
      ;;
  esac
done

if [ "$EXITCRIT" = "1" ] ; then
    proposed_exit=2
fi

if [ "$EXITWARN" = "1" ] ; then
    proposed_exit=1
fi

# check prerequisites
mongo -version > /dev/null
if [ $? -ne 0 ]; then
        echo "mongo-client is not installed, aborting"
        exit $proposed_exit
fi

fqdn=$(facter fqdn)

environment=$(facter ${env_key} -p)

if [ -z "${environment} ]
then
    environment=$(facter ${fallback_key} -p)
fi


# something like mongodb://someuser:hispassword@somehost/somedb


if [[ ! $mongourl =~ "mongodb://" ]]; then
  echo "WARNING: mongourl invalid! Please use a valid monurl!"
  showhelp
  exit $proposed_exit
fi

if [[ $mongourl =~ @ ]]; then
  # ok we have to deal with passwords
  # you HAVE to provide a password if you provide a user
  mongodb=`echo $mongourl | sed 's/.*@//'`
  mongouser=`echo $mongourl | sed 's/mongodb:\/\///' | sed 's/:.*//' `
  mongopassword=`echo $mongourl | sed 's/mongodb:\/\///' | sed 's/[^:]*://' | sed 's/@.*//' `
  mongoarguments="--username $mongouser --password $mongopassword"
else
  mongodb=`echo $mongourl | sed 's/mongodb:\/\///'` 	
fi

result=$(grep result $logdir/$project/$tag/summary | awk '{ print $NF }')
summary=$(cat $logdir/$project/$tag/summary)

mcmd="db.deployments.insert({ts:new Date(),result:\"${result}\",fqdn:\"${fqdn}\",project:\"${project}\",source:\"${source}\",tag:\"${tag}\",version:\"${version}\",artifact:\"${artifact}\",testmode:\"${testmode}\",warfile:\"${warfile}\",environment:\"${environment}\"}); quit(0)"


mongo $mongoarguments $mongodb --eval "$mcmd"

# Now do a reporting to enable "most-recent-versions on all servers"

read -r -d '' mcmd <<'EOF'
var map = function() {
  project=this.project ;
  emit( this.fqdn +":"+ this.project,  {project:this.project, fqdn:this.fqdn, ts:this.ts,version:this.version,environment:this.environment}  );
};
var reduce = function(k,vals) {
  result = vals[0];
  vals.forEach(function(val) { if (val.ts > result.ts) result=val } ) ;
  return result;
};
db.deployments.mapReduce(
  map,
  reduce,
  {out:{replace:"versions"}})
EOF

mongo $mongoarguments $mongodb --eval "$mcmd"

exit $proposed_exit
#!/bin/bash
# service.sh - Made for Puppi

# Sources common header for Puppi scripts
. $(dirname $0)/header || exit 10

# Show help
showhelp () {
    echo "This script is used to manage one or more services"
    echo "It requires AT LEAST 2 arguments:"
    echo "First argument (\$1 - required) is the script command (stop|start|restart|reload)"
    echo "Second argument and following (\$2 - required) is the space separated list of sevices to manage"
    echo
    echo "Examples:"
    echo "service.sh stop monit puppet"
}

# Check arguments
if [ $1 ] ; then
    servicecommand=$1
else
    showhelp
    exit 2
fi


if [ $# -ge 2 ] ; then
    shift
    services=$@
else
    showhelp
    exit 2
fi

# Manage service
service () {
    for serv in $services ; do
        /etc/init.d/$serv $servicecommand
    done
}

service
#!/bin/bash
# svn.sh - Made for Puppi

# All variables are exported
set -a 

# Sources common header for Puppi scripts
. $(dirname $0)/header || exit 10

# Show help
showhelp () {
    echo "This script performs the svn operations required by puppi::project::svn"
    echo "It integrates and uses variables provided by other core Puppi scripts"
    echo "It has the following options:"
    echo "-a <action> (Optional) What action to perform. Available options: deploy (default), rollback"
    echo "-s <source> (Required) Subversion source repo to use"
    echo "-d <destination> (Required) Directory where files are deployed"
    echo "-u <user> (Optional) User that performs the deploy operations. Default root"
    echo "-su <user> (Optional) Username for access to private svn repo"
    echo "-sp <password> (Optional) Password for access to private svn repo"
    echo "-gs <svn_subdir> (Optional) If only a specific subdir of the svnrepo has to be copied to the install destination"
    echo "-t <tag> (Optional) Tag to deploy"
    echo "-b <branch> (Optional) Branch to deploy"
    echo "-c <commit> (Optional) Commit to deploy"
    echo "-v <true|false> (Optional) If verbose"
    echo "-k <true|false> (Optional) If .svn dir is kept on deploy_root"
    echo "-e <true|false> (Optional) If use export instead of checkout for svn operations"
    echo 
    echo "Examples:"
    echo "svn.sh -a deploy -s $source -d $deploy_root -u $user -gs $svn_subdir -t $tag -b $branch -c $commit -v $bool_verbose -k $bool_keep_svndata"
}

verbose="true"

# Check Arguments
while [ $# -gt 0 ]; do
  case "$1" in
    -a)
      case $2 in
          rollback)
          action="rollback"
          ;;
          *)
          action="install"
          ;;
      esac 
      shift 2 ;;
    -s)
      if [ $source ] ; then
        source=$source
      else
        source=$2
      fi
      shift 2 ;;
    -d)
      if [ $deploy_root ] ; then
        deploy_root=$deploy_root
      else
        deploy_root=$2
      fi
      shift 2 ;;
    -u)
      if [ $user ] ; then
        deploy_user=$user
      else
        deploy_user=$2
      fi
      shift 2 ;;
    -gs)
      if [ $svn_subdir ] ; then
        svn_subdir=$svn_subdir
      else
        svn_subdir=$2
      fi
      shift 2 ;;
    -su)
      if [ $svn_user ] ; then
        svn_user=$svn_user
      else
        svn_user=$2
      fi
      shift 2 ;;
    -sp)
      if [ $svn_password ] ; then
        svn_password=$svn_password
      else
        svn_password=$2
      fi
      shift 2 ;;
    -t)
      if [ $svn_tag ] ; then
        svn_tag=$svn_tag
      else
        svn_tag=$2
      fi
      shift 2 ;;
    -b)
      if [ $branch ] ; then
        branch=$branch
      else
        branch=$2
      fi
      shift 2 ;;
    -c)
      if [ $commit ] ; then
        commit=$commit
      else
        commit=$2
      fi
      shift 2 ;;
    -v)
      if [ $verbose ] ; then
        verbose=$verbose
      else
        verbose=$2
      fi
      shift 2 ;;
    -k)
      if [ $keep_svndata ] ; then
        keep_svndata=$keep_svndata
      else
        keep_svndata=$2
      fi
      shift 2 ;;
    -e)
      if [ $svn_export ] ; then
        svn_export=$svn_export
      else
        svn_export=$2
      fi
      shift 2 ;;
    *)
      showhelp
      exit ;;
  esac
done

if [ "x$verbose" == "xtrue" ] ; then
  verbosity=""
else
  verbosity="--quiet"
fi

cd /

if [ "x$branch" == "xundefined" ] ; then
  branch="trunk"
fi

real_source="$source/$branch"

if [ "x$svn_tag" != "xundefined" ] ; then
  real_source="$source/$svn_tag"
fi

if [ "x$svn_user" != "xundefined" ] && [ "x$svn_password" != "xundefined" ] ; then
  svn_auth="--username=$svn_user --password=$svn_password"
else
  svn_auth=""
fi

svnsubdir=""
svndir=$deploy_root


do_install () {
  if [ "x$keep_svndata" != "xtrue" ] ; then
    if [ ! -d $archivedir/$project-svn ] ; then
      mkdir $archivedir/$project-svn
      chown -R $user:$user $archivedir/$project-svn
    fi
    svndir=$archivedir/$project-svn/svnrepo
  fi
  if [ "x$svn_subdir" != "xundefined" ] ; then
    if [ ! -d $archivedir/$project-svn ] ; then
      mkdir $archivedir/$project-svn
      chown -R $user:$user $archivedir/$project-svn
    fi
    svndir=$archivedir/$project-svn
    svnsubdir="$svn_subdir/"
  fi

  if [ -d $svndir/.svn ] ; then
    cd $svndir
    svn up $verbosity $svn_auth --non-interactive
  else
    svn co $verbosity $real_source $svndir $svn_auth --non-interactive
    cd $svndir
  fi

  if [ "x$svndir" == "x$archivedir/$project-svn" ] ; then
    rsync -a --exclude=".svn" $svndir/$svnsubdir $deploy_root/
  fi
}

do_export () {
  svn export $verbosity $svn_auth --force --non-interactive $real_source/$svn_subdir $deploy_root
}

do_rollback () {
  echo "Rollback not yet supported"
}

# Action!
case "$action" in
    install) 
      if [ "x$svn_export" == "xtrue" ] ; then
        export -f do_export ; su $user -c do_export
      else
        export -f do_install ; su $user -c do_install
      fi
      ;;
    rollback) do_rollback ;;
esac

#!/bin/bash
# wait.sh - Made for Puppi

# Sources common header for Puppi scripts
. $(dirname $0)/header || exit 10

# Show help
showhelp () {
    echo "This script is used to introduce pauses during the deploy workflow"
    echo
    echo "It has the following options:"
    echo "-s <seconds> - The number of seconds to wait"
    echo "-p <filename> - Wait until filename is present"
    echo "-a <filename> - Wait until filename is absent"
    echo "-f <pattern> <filename> - Wait until is found the pattern in the filename"
}

while [ $# -gt 0 ]; do
  case "$1" in
    -s)
      sleep $2
      exit 0
      ;;
    -p)
      while true
         do
            [ -e $2 ] && break
         sleep 1
      done
      exit 0
      ;;
    -a)
      while true
         do
            [ ! -e $2 ] && break
         sleep 1
      done
      exit 0
      ;;
    -f)
      while true
         do
            grep $2 $3 && break
         sleep 1
      done
      exit 0
      ;;
    *)
      showhelp
      exit
      ;;
  esac
done

#!/bin/bash
# yant.sh - Made for Puppi
# Sources common header for Puppi scripts
. $(dirname $0)/header || exit 10

# Show help
showhelp () {
    echo "This script is used to call ant in a hybris-system"
    echo "It requires AT LEAST 2 arguments:"
    echo "First the \${hybris_parent_dir} where it can find a hybris-directory"
    echo "Second argument: Everything you want to pass through to ant"
    echo "The script assumes that hybris is located in \${hybris_parent_dir}/hybris"
    echo
    echo "Examples:"
    echo "yant.sh /home/hybris clean all"
}

# Unfortunately, showhelp will never be called

cd $1/hybris/bin/platform
. ./setantenv.sh

# somehow dirty ...
shift

if [ -d /opt/hybris/config ]; then
	template=""
else
	template=-Dinput.template=develop 
fi

if [ $debug ] ; then
    ant -Dinput.template=develop $* 
else
    ant $* > /dev/null
fi

handle_result
#!/bin/bash
# yum.sh - Made for Puppi

# Sources common header for Puppi scripts
. $(dirname $0)/header || exit 10

# Show help
showhelp () {
    echo "This script performs the yum operations required by puppi::project::yum"
    echo "It integrates and uses variables provided by other core Puppi scripts"
    echo "It has the following options:"
    echo "-a <action> (Optional) What action to perform. Available options: deploy (default), rollback, remove"
    echo "-n <rpm_name> (Required) Name of the package to handle"
    echo "-v <rpm_version> (Optional) The version of the rpm to manage. Default: latest"
    echo "-r <install_root> (Optional) The Instll root path. Default: /"
    echo 
    echo "Examples:"
    echo "yum.sh -a deploy -n ${rpm} -r ${install_root} -v ${rpm_version}"
}

rpm_version="latest"
install_root="/"

# Check Arguments
while [ $# -gt 0 ]; do
  case "$1" in
    -a)
      case $2 in
          rollback)
          action="rollback"
          ;;
          remove)
          action="remove"
          ;;
          *)
          action="install"
          ;;
      esac 
      shift 2 ;;
    -n)
      rpm_name=$2
      shift 2 ;;
    -v)
      rpm_version=$2
      shift 2 ;;
    -r)
      install_root=$2
      shift 2 ;;
    *)
      showhelp
      exit ;;
  esac
done


do_install () {
    if [ x$rpm_version == "xlatest" ] ; then
        full_rpm_name=$rpm_name
    else
        full_rpm_name=$rpm_name-$rpm_version
    fi

    # Archives version of the rpm to update
    oldversion=$(rpm -q $rpm_name --qf  "%{VERSION}-%{RELEASE}\n")
    if [ "$?" = "0" ]; then
        mkdir -p $archivedir/$project/$oldversion
        if [ $archivedir/$project/latest ] ; then
            rm -f $archivedir/$project/latest
        fi
        ln -sf $archivedir/$project/$oldversion $archivedir/$project/latest
    fi

    if [ x$install_root != "x/" ] ; then
        yum install -y -q --installroot=$install_root $full_rpm_name
    else
        yum install -y -q $full_rpm_name
    fi
}

do_rollback () {
    yum downgrade -y -q $rpm_name-$rollbackversion
}

do_remove () {
    yum remove -y -q $rpm_name
}

# Action!
case "$action" in
    install) do_install ;;
    rollback) do_rollback ;;
    remove) do_remove ;;
esac
require 'facter'
Facter.add("last_run") do
  confine :kernel => [ 'Linux' , 'SunOS' , 'FreeBSD' , 'Darwin' ]
  setcode do
    Facter::Util::Resolution.exec('date')
  end
end
require 'facter'
Facter.add("puppi_projects") do
  confine :kernel => [ 'Linux' , 'SunOS' , 'FreeBSD' , 'Darwin' ]
  setcode do
    Facter::Util::Resolution.exec('ls `grep projectsdir  /etc/puppi/puppi.conf | sed \'s/projectsdir="\([^"]*\)"/\1/\'` | tr \'\n\' \',\' | sed \'s/,$//\'') if File.exists?("/etc/puppi/puppi.conf")
  end
end
require 'facter'
Facter.add(:windows_common_appdata) do
  confine :operatingsystem => :windows
  if Facter.value(:osfamily) == "windows"
    require 'win32/dir'
  end
  setcode do
    Dir::COMMON_APPDATA
  end
end
#
# any2bool.rb
#
# This define is heavily based on PuppetLabs' stdlib str2bool
#
module Puppet::Parser::Functions
  newfunction(:any2bool, :type => :rvalue, :doc => <<-EOS
This converts any input to a boolean. This attempt to convert strings that 
contain things like: y, 1, t, true to 'true' and strings that contain things
like: 0, f, n, false, no to 'false'.
    EOS
  ) do |arguments|

    raise(Puppet::ParseError, "any2bool(): Wrong number of arguments " +
      "given (#{arguments.size} for 1)") if arguments.size < 1

    string = arguments[0]

#    unless string.is_a?(String)
#      raise(Puppet::ParseError, 'str2bool(): Requires either ' +
#        'string to work with')
#    end

    # We consider all the yes, no, y, n and so on too ...
    result = case string
      #
      # This is how undef looks like in Puppet ...
      # We yield false in this case.
      #
      when false then false
      when true then true
      when /^$/, '' then false # Empty string will be false ...
      when /^(1|t|y|true|yes)$/  then true
      when /^(0|f|n|false|no)$/  then false
      when /^(undef|undefined)$/ then false # This is not likely to happen ...
      else
        raise(Puppet::ParseError, 'any2bool(): Unknown type of boolean given')
    end

    return result
  end
end

# vim: set ts=2 sw=2 et :
#
# bool2ensure.rb
#
# This define return present/absent accroding to the boolean value passed
#
module Puppet::Parser::Functions
  newfunction(:bool2ensure, :type => :rvalue, :doc => <<-EOS
This converts any input similar to a boolean to the stringpresent or absent
    EOS
  ) do |arguments|

    raise(Puppet::ParseError, "bool2ensure(): Wrong number of arguments " +
      "given (#{arguments.size} for 1)") if arguments.size < 1

    string = arguments[0]

    result = case string
      when false then "absent"
      when true then "present"
      when /^$/, '' then "present" 
      when /^(1|t|y|true|yes)$/  then "present"
      when /^(0|f|n|false|no)$/  then "absent"
      when /^(undef|undefined)$/ then "present"
      else
        raise(Puppet::ParseError, 'bool2ensure(): Unknown type of boolean given')
    end

    return result
  end
end

# vim: set ts=2 sw=2 et :
# This function is based on Ken Barber's get_scope_args
# It has been slightly changed and renamed to avoid naming clash

module Puppet::Parser::Functions
  newfunction(:get_class_args, :type => :rvalue, :doc => <<-EOS
This function will return all arguments passed to the current scope. This could
be a class or defined resource.
    EOS
  ) do |arguments|
 
    if (arguments.size != 0) then
      raise(Puppet::ParseError, "validate_resource(): Wrong number of arguments "+
        "given #{arguments.size} for 0")
    end

    # Grab the current scope, turn it to a hash but do not be recursive 
    # about it.
    classhash = to_hash(recursive=false)

    # Strip bits that do not matter for validation
#    classhash.delete("name")
#    classhash.delete("title")
#    classhash.delete("caller_module_name")
#    classhash.delete("module_name")

    # Return munged classhash
    classhash
  end
end

# vim: set ts=2 sw=2 et :

#
# get_magicvar.rb
#
# This define return the value of the the provided var name
#
module Puppet::Parser::Functions
  newfunction(:get_magicvar, :type => :rvalue, :doc => <<-EOS
This returns the value of the input variable. For example if you input role
it returns the value of $role'.
    EOS
  ) do |arguments|

    raise(Puppet::ParseError, "get_magicvar(): Wrong number of arguments " +
      "given (#{arguments.size} for 1)") if arguments.size < 1

    my_var = arguments[0]
    result = lookupvar("#{my_var}")
    result = 'all' if ( result == :undefined || result == '' )
    return result
  end
end

# vim: set ts=2 sw=2 et :
module Puppet::Parser::Functions
  newfunction(:get_module_path, :type =>:rvalue, :doc => <<-EOT
    Returns the absolute path of the specified module for the current
    environment.

    Example:
      $module_path = get_module_path('stdlib')
  EOT
  ) do |args|
    raise(Puppet::ParseError, "get_module_path(): Wrong number of arguments, expects one") unless args.size == 1
    if module_path = Puppet::Module.find(args[0], compiler.environment.to_s)
      module_path.path
    else
      raise(Puppet::ParseError, "Could not find module #{args[0]} in environment #{compiler.environment}")
    end
  end
end
#
# nslookup.rb
#
# This fuction looks up the ip address of a hostname.
#
# Params:
#  * Hostname: (string) The hostname to lookup
#  * Type: (string) The DNS type to lookup. Optional. Default: 'AAAA'
#
# Returns: an array with the ip addresses that belong to this hostname
#
# Dolf Schimmel - Freeaqingme <dolf@dolfschimmel.nl>
# 
module Puppet::Parser::Functions
  newfunction(:nslookup, :type => :rvalue, :doc => <<-EOS
Lookup a hostname and return its ip addresses
    EOS
  ) do |vals|
    hostname, type = vals
    raise(ArgumentError, 'Must specify a hostname') unless hostname
    type = 'AAAA' unless type
    
    require 'ipaddr'
    
    if (ip = IPAddr.new(hostname) rescue nil)
      if (ip.ipv6? and type == 'AAAA') or (ip.ipv4? and type != 'AAAA')
        return hostname
      else
        return []
      end
    end

    typeConst = Resolv::DNS::Resource::IN.const_get "#{type.upcase}"
    out = []
    
    Resolv::DNS.open do |dns|
      dns.getresources(hostname, typeConst).collect {|r| 
        out << IPAddr::new_ntoh(r.address.address).to_s
      }
    end

    return out
  end
end
#
# options_lookup.rb
#
# This fuction takes two arguments (option, and default value) and looks for the given
# option key in the calling modules options hash, and returns the value.
# The function is intended to be used in templates.
# If no option is found in the options hash, default value (second argument), is returned.
#
# Example usages:
#
# Default value of no
#   <%= scope.function_options_lookup(['PasswordAuthentication', 'no']) %>
# Empty default value
#   <%= scope.function_options_lookup(['PasswordAuthentication', '']) %>
# Fact or param based default value
#   <%= scope.function_options_lookup(['Listen', ipaddress]) %>
# Lookup inside a custom hash - in this case client_options
#   <%= scope.function_options_lookup(['PasswordAuthentication', 'no', 'client_options']) %>
#
#
# Michal Nowak <mailto:michal@casanowak.com>
# 
module Puppet::Parser::Functions
  newfunction(:options_lookup, :type => :rvalue, :doc => <<-EOS
This fuction takes two arguments (option, and default value) and looks for the given
option key in the calling modules options hash, and returns the value.
The function is intended to be used in templates.
If no option is found in the options hash, default value (second argument), is returned.

Default value of no
  <%= scope.function_options_lookup(['PasswordAuthentication', 'no']) %>
Empty default value
  <%= scope.function_options_lookup(['PasswordAuthentication', '']) %>
Fact or param based default value
   <%= scope.function_options_lookup(['Listen', ipaddress]) %>
Lookup inside a custom hash - in this case client_options
   <%= scope.function_options_lookup(['PasswordAuthentication', 'no', 'client_options']) %>

EOS
  ) do |args|

    raise ArgumentError, ("options_lookup(): wrong number of arguments (#{args.length}; must be 2 or 3)") if (args.length != 2 and args.length != 3)

    value = ''
    option_name = args[0]
    default_val = args[1]
    hash_name = args[2]
    module_name = parent_module_name

    hash_name = "options" if (hash_name == :undefined || hash_name == '' || hash_name == nil)
    value = lookupvar("#{module_name}::#{hash_name}")["#{option_name}"] if (lookupvar("#{module_name}::#{hash_name}").size > 0)
    value = "#{default_val}" if (value == :undefined || value == '' || value == nil)

    return value
  end
end
#
# params_lookup.rb
#
# This function lookups for a variable value in various locations
# following this order (first match is returned)
# - Hiera backend (if present) for modulename_varname
# - Hiera backend (if present) for varname (if second argument is 'global')
# - Top Scope Variable ::modulename_varname
# - Top Scope Variable ::varname (if second argument is 'global')
# - Module default: ::modulename::params::varname
#
# It's based on a suggestion of Dan Bode on how to better manage
# Example42 NextGen modules params lookups.
# Major help has been given by  Brice Figureau, Peter Meier
# and Ohad Levy during the Fosdem 2012 days (thanks guys)
#
# Tested and adapted to Puppet 2.6.x and later
#
# Alessandro Franceschi al@lab42.it
#
module Puppet::Parser::Functions
  newfunction(:params_lookup, :type => :rvalue, :doc => <<-EOS
This fuction looks for the given variable name in a set of different sources:
- Hiera, if available ('modulename_varname')
- Hiera, if available (if second argument is 'global')
- ::modulename_varname
- ::varname (if second argument is 'global')
- ::modulename::params::varname
If no value is found in the defined sources, it returns an empty string ('')
    EOS
  ) do |arguments|

    raise(Puppet::ParseError, "params_lookup(): Define at least the variable name " +
      "given (#{arguments.size} for 1)") if arguments.size < 1

    value = ''
    var_name = arguments[0]
    module_name = parent_module_name

    # Hiera Lookup
    if Puppet::Parser::Functions.function('hiera')
      value = function_hiera(["#{module_name}_#{var_name}", ''])
      return value if (not value.nil?) && (value != :undefined) && (value != '')

      value = function_hiera(["#{var_name}", '']) if arguments[1] == 'global'
      return value if (not value.nil?) && (value != :undefined) && (value != '')
    end

    # Top Scope Variable Lookup (::modulename_varname)
    value = lookupvar("::#{module_name}_#{var_name}")
    return value if (not value.nil?) && (value != :undefined) && (value != '')

    # Look up ::varname (only if second argument is 'global')
    if arguments[1] == 'global'
      value = lookupvar("::#{var_name}")
      return value if (not value.nil?) && (value != :undefined) && (value != '')
    end

    # needed for the next two lookups
    classname = self.resource.name.downcase
    loaded_classes = catalog.classes

    # self::params class lookup for default value
    if loaded_classes.include?("#{classname}::params")
      value = lookupvar("::#{classname}::params::#{var_name}")
      return value if (not value.nil?) && (value != :undefined) && (value != '')
    end

    # Params class lookup for default value
    if loaded_classes.include?("#{module_name}::params")
      value = lookupvar("::#{module_name}::params::#{var_name}")
      return value if (not value.nil?) && (value != :undefined) && (value != '')
    end

    return ''
  end
end
require 'uri'

Puppet::Parser::Functions::newfunction(:url_parse, :type => :rvalue, :doc => <<-'ENDHEREDOC') do |args|
    Returns information about an url
    
    This function expects two arguments, an URL and the part of the url you want to retrieve. 

    Example:
    $source_filename = url_parse($source_url,path)

    Given an url like: https://my_user:my_pass@www.example.com:8080/path/to/file.php?id=1&ret=0
    You obtain the following results according to the second argument:
    scheme   : https
    userinfo : my_user:my_pass
    user     : my_user
    password : my_pass
    host     : www.example.com
    port     : 8080
    path     : /path/to/file.php
    query    : id=1&ret=0
    filename : file.php
    filetype : php
    filedir  : file
   
 
  ENDHEREDOC
  raise ArgumentError, ("url_parse(): wrong number of arguments (#{args.length}; must be 2)") if args.length != 2
  url=URI.parse args[0]
  case args[1]
    when 'scheme' then url.scheme
    when 'userinfo' then url.userinfo
    when 'user' then url.user
    when 'password' then url.password
    when 'host' then url.host
    when 'port' then url.port
    when 'path' then url.path
    when 'query' then url.query
    when 'filename' then File.basename url.path
    when 'filetype' then File.extname url.path
    when 'filedir' then (File.basename url.path).chomp(File.extname(url.path))
    else url
  end
end

# Define puppi::check
#
# This define creates a file with a check command that can be used locally.
# It uses Nagios plugins for all checks so that $command is just the
# plugin name with its arguments
#
# == Usage
# Basic Usage:
# puppi::check { "checkname":
#   command => "check_tcp -H localhost -p 80"
# }
#
# :include:../README.check
#
define puppi::check (
  $command,
  $base_dir = '',
  $hostwide = 'no',
  $priority = '50',
  $project  = 'default',
  $enable   = true ) {

  require puppi
  require puppi::params

  $ensure = bool2ensure($enable)
  $bool_hostwide = any2bool($hostwide)

  $real_base_dir = $base_dir ? {
    ''      => $puppi::params::checkpluginsdir,
    default => $base_dir,
  }

  $path = $bool_hostwide ? {
    true  => "${puppi::params::checksdir}/${priority}-${name}" ,
    false => "${puppi::params::projectsdir}/${project}/check/${priority}-${name}",
  }

  file { "Puppi_check_${project}_${priority}_${name}":
    ensure  => $ensure,
    path    => $path,
    mode    => '0755',
    owner   => $puppi::params::configfile_owner,
    group   => $puppi::params::configfile_group,
    require => Class['puppi'],
    content => "${real_base_dir}/${command}\n",
    tag     => 'puppi_check',
  }

}
# Define puppi::deploy
#
# This define creates a file with a deploy command that can be used locally.
#
# == Usage:
# puppi::configure { "Retrieve files":
#   command  => "get_file.sh",
#   argument => "/remote/dir/file",
#   priority => "10",
#   user   => "root",
#   project  => "spysite",
# }
#
# :include:../README.deploy
#
define puppi::configure (
  $command,
  $project,
  $arguments = '',
  $priority  = '50',
  $user      = 'root',
  $enable    = true ) {

  require puppi
  require puppi::params

  $ensure = bool2ensure($enable)

  file { "${puppi::params::projectsdir}/${project}/configure/${priority}-${name}":
    ensure  => $ensure,
    mode    => '0750',
    owner   => $puppi::params::configfile_owner,
    group   => $puppi::params::configfile_group,
    require => Class['puppi'],
    content => "su - ${user} -c \"export project=${project} && ${puppi::params::scriptsdir}/${command} ${arguments}\"\n",
    tag     => 'puppi_deploy',
  }

}

# Class puppi::dependencies
#
# This class provides commands and tools needed for full Puppi
# functionality. Since you might already have these package
# resources in your modules, to avoid conflicts you may decide
# to include the needed packages somewhere else and avoid the
# direct inclusion of puppi::dependencies with the parameter:
#   install_dependencies => false
#
class puppi::dependencies {

  require puppi::params

  if ! defined(Package['curl']) {
    package { 'curl' : ensure => present }
  }

  if ! defined(Package['wget']) {
    package { 'wget' : ensure => present }
  }

  if ! defined(Package['unzip']) {
    package { 'unzip' : ensure => present }
  }

  if ! defined(Package['rsync']) {
    package { 'rsync' : ensure => present }
  }

  if ! defined(Package[$puppi::params::package_nagiosplugins]) {
    package { $puppi::params::package_nagiosplugins : ensure => present }
  }

  if ! defined(Package[$puppi::params::package_mail]) {
    package { $puppi::params::package_mail : ensure => present }
  }

}
# Define puppi::deploy
#
# This define creates a file with a deploy command that can be used locally.
#
# == Usage:
# puppi::deploy { "Retrieve files":
#   command  => "get_file.sh",
#   argument => "/remote/dir/file",
#   priority => "10",
#   user   => "root",
#   project  => "spysite",
# }
#
# :include:../README.deploy
#
define puppi::deploy (
  $command,
  $project,
  $arguments = '',
  $priority  = '50',
  $user      = 'root',
  $enable    = true ) {

  require puppi
  require puppi::params

  $ensure = bool2ensure($enable)

  file { "${puppi::params::projectsdir}/${project}/deploy/${priority}-${name}":
    ensure  => $ensure,
    mode    => '0750',
    owner   => $puppi::params::configfile_owner,
    group   => $puppi::params::configfile_group,
    require => Class['puppi'],
    content => "su - ${user} -c \"export project=${project} && ${puppi::params::scriptsdir}/${command} ${arguments}\"\n",
    tag     => 'puppi_deploy',
  }

}

# Class puppi::extras
#
# Default extras class with predefined puppi
# check, log , info content.
# You can provide a custom extra class to use instead of this
# with a parameter like:
#   extra_class=> 'example42::puppi::extras',
#
class puppi::extras {

  # Default Checks

  puppi::check { 'NTP_Sync':
    command  => "check_ntp -H ${puppi::params::ntp}" ,
    priority => '99' ,
    hostwide => 'yes' ,
  }

  puppi::check { 'Disks_Usage':
    command  => 'check_disk -w 20% -c 10% -L -X tmpfs' ,
    priority => '10' ,
    hostwide => 'yes' ,
  }

  puppi::check { 'System_Load':
    command  => 'check_load -w 15,10,5 -c 30,25,20' ,
    priority => '10' ,
    hostwide => 'yes' ,
  }

  puppi::check { 'Zombie_Processes':
    command  => 'check_procs -w 5 -c 10 -s Z' ,
    priority => '10' ,
    hostwide => 'yes' ,
  }

  puppi::check { 'Local_Mail_Queue':
    command  => 'check_mailq -w 2 -c 5' ,
    priority => '10' ,
    hostwide => 'yes' ,
  }

  puppi::check { 'Connected_Users':
    command  => 'check_users -w 5 -c 10' ,
    priority => '10' ,
    hostwide => 'yes' ,
  }

  puppi::check { 'DNS_Resolution':
    command  => 'check_dns -H example.com' ,
    priority => '15' ,
    hostwide => 'yes' ,
  }


  # Info Pages
  $network_run = $::operatingsystem ? {
    Solaris => [ 'ifconfig -a' , 'netstat -nr' , 'cat /etc/resolv.conf' , 'arp -an' , 'netstat -na' ],
    default => [ 'ifconfig' , 'route -n' , 'cat /etc/resolv.conf' , 'arp -an' , 'netstat -natup | grep LISTEN' ],
  }

  puppi::info { 'network':
    description => 'Network settings and stats' ,
    run         => $network_run,
  }

  $users_run = $::operatingsystem ? {
    Solaris => [ 'who' , 'last' ],
    default => [ 'who' , 'last' , 'LANG=C lastlog | grep -v \'Never logged in\'' ],
  }

  puppi::info { 'users':
    description => 'Users and logins information' ,
    run         => $users_run,
  }

  $perf_run = $::operatingsystem ? {
    Solaris => [ 'uptime' , 'vmstat 1 5' ],
    default => [ 'uptime' , 'free' , 'vmstat 1 5' ],
  }

  puppi::info { 'perf':
    description => 'System performances and resources utilization' ,
    run         => $perf_run,
  }

  $disks_run = $::operatingsystem ? {
    Solaris => [ 'df -h' , 'mount' ],
    default => [ 'df -h' , 'mount' , 'blkid' , 'fdisk -l' ],
  }

  puppi::info { 'disks':
    description => 'Disks and filesystem information' ,
    run         => $disks_run,
  }

  $hardware_run = $::operatingsystem ? {
    Solaris => [ 'find /devices/' ],
    default => [ 'lspci' , 'cat /proc/cpuinfo' ],
  }

  puppi::info { 'hardware':
    description => 'Hardware information' ,
    run         => $hardware_run,
  }

  $packages_run = $::operatingsystem ? {
    /(?i:RedHat|CentOS|Scientific|Amazon|Linux)/ => [ 'yum repolist' , 'rpm -qa' ] ,
    /(?i:Debian|Ubuntu|Mint)/                    => [ 'apt-config dump' , 'apt-cache stats' , 'apt-key list' , 'dpkg -l' ],
    /(Solaris)/                                  => [ 'pkginfo' ],
    /(Archlinux)/                                => [ 'pacman -Qet' ],
    default                                      => [ 'echo' ],
  }

  puppi::info { 'packages':
    description => 'Packages information' ,
    run         => $packages_run,
  }

  puppi::info::module { 'puppi':
    configfile  => ["${puppi::params::basedir}/puppi.conf"],
    configdir   => [$puppi::params::basedir],
    datadir     => [$puppi::params::archivedir],
    logdir      => [$puppi::params::logdir],
    description => 'What Puppet knows about puppi' ,
    verbose     => 'yes',
#   run         => "ls -lR ${puppi::params::logdir}/puppi-data/",
  }

  ### Default Logs
  case $::operatingsystem {

    Debian,Ubuntu: {
      puppi::log { 'system':
        description => 'General System Messages',
        log         => ['/var/log/syslog'],
      }
      puppi::log { 'auth':
        description => 'Users and authentication',
        log         => ['/var/log/user.log','/var/log/auth.log'],
      }
      puppi::log { 'mail':
        description => 'Mail messages',
        log         => ['/var/log/mail.log'],
      }
    }

    RedHat,CentOS,Scientific,Amazon,Linux: {
      puppi::log { 'system':
        description => 'General System Messages',
        log         => ['/var/log/messages'],
      }
      puppi::log { 'auth':
        description => 'Users and authentication',
        log         => ['/var/log/secure'],
      }
      puppi::log { 'mail':
        description => 'Mail messages',
        log         => ['/var/log/maillog'],
      }
    }

    SLES,OpenSuSE: {
      puppi::log { 'system':
        description => 'General System Messages',
        log         => ['/var/log/messages'],
      }
      puppi::log { 'mail':
        description => 'Mail messages',
        log         => ['/var/log/mail'],
      }
      puppi::log { 'zypper':
        description => 'Zypper messages',
        log         => ['/var/log/zypper.log'],
      }
    }

    Solaris: {
      puppi::log { 'system':
        description => 'General System Messages',
        log         => ['/var/adm/messages'],
      }
      puppi::log { 'auth':
        description => 'Users and authentication',
        log         => ['/var/log/authlog'],
      }
    }

    Archlinux: {
      puppi::log { 'system':
        description => 'General System Messages',
        log         => ['/var/log/messages.log','/var/log/syslog.log'],
      }
      puppi::log { 'auth':
        description => 'Users and authentication',
        log         => ['/var/log/user.log','/var/log/auth.log'],
      }
      puppi::log { 'mail':
        description => 'Mail messages',
        log         => ['/var/log/mail.log'],
      }
    }

    default: { }

  }

}
# Define puppi::helper
#
# The Puppi 2.0 define that creates an helper file that contains
# the commands to execute, for the different puppi actions, using
# the variables present in the datafile
#
# == Usage
# Basic Usage:
# puppi::helper { "myhelper":
#   template => 'myproject/puppi/helpers/myhelper.erb',
# }
#
define puppi::helper (
  $template,
  $ensure = 'present' ) {

  require puppi
  require puppi::params

  file { "puppi_helper_${name}":
    ensure  => $ensure,
    path    => "${puppi::params::helpersdir}/${name}.yml",
    mode    => '0644',
    owner   => $puppi::params::configfile_owner,
    group   => $puppi::params::configfile_group,
    content => template($template),
  }

}
# Class puppi::helpers
#
# A class that defines all the default helpers used by Example42
#  modules
#
# == Usage
# Automatically included by Puppi
#
class puppi::helpers {

  # Standard helper for Example42 modules
  puppi::helper { 'standard':
    template => 'puppi/helpers/standard.yml.erb',
  }

}
# Define puppi::info
#
# This define creates a basic info file that simply contains a set
# of commands that show infos about custom topics.
# To be used by the puppi info command.
# By default it builds the info script based on the minimal puppi/info.erb
# template but you can choose a custom template.
# Other info defines are used to gather and create puppi info scripts with
# different arguments and contents.
# Check puppi/manifests/info/ for alternative puppi::info::  plugins
#
# == Usage:
# puppi::info { "network":
#   description => "Network status and information" ,
#   run  => [ "ifconfig" , "route -n" ],
# }
#
# :include:../README.info
#
define puppi::info (
  $description  = '',
  $templatefile = 'puppi/info.erb',
  $run          = '' ) {

  require puppi
  require puppi::params

  $array_run = is_array($run) ? {
    false     => $run ? {
      ''      => [],
      default => split($run, ','),
    },
    default   => $run,
  }

  file { "${puppi::params::infodir}/${name}":
    ensure  => present,
    mode    => '0750',
    owner   => $puppi::params::configfile_owner,
    group   => $puppi::params::configfile_group,
    require => Class['puppi'],
    content => template($templatefile),
    tag     => 'puppi_info',
  }

}
# Define puppi::info::instance
#
# This is a puppi info plugin specific for the tomcat::instance define
#
define puppi::info::instance (
  $servicename  = '',
  $processname  = '',
  $configdir    = '',
  $bindir       = '',
  $pidfile      = '',
  $datadir      = '',
  $logdir       = '',
  $httpport     = '',
  $controlport  = '',
  $ajpport      = '',
  $description  = '',
  $run          = '',
  $verbose      = 'no',
  $templatefile = 'puppi/info/instance.erb' ) {

  require puppi
  require puppi::params

  file { "${puppi::params::infodir}/${name}":
    ensure  => present,
    mode    => '0750',
    owner   => $puppi::params::configfile_owner,
    group   => $puppi::params::configfile_group,
    content => template($templatefile),
    tag     => 'puppi_info',
  }

}
# Define puppi::info::module
#
# This is a puppi info plugin that provides automatic info to modules
# It uses a default template puppi/info/module.erb that can be changed
# and adapted
#
# == Usage
# (Sample from Example42 apache module where there's wide use of
# qualified variables, note that you can provide direct values to it
# without using variables):
#
#  puppi::info::module { "apache":
#    packagename => "${apache::params::packagename}",
#    servicename => "${apache::params::servicename}",
#    processname => "${apache::params::processname}",
#    configfile  => "${apache::params::configfile}",
#    configdir   => "${apache::params::configdir}",
#    pidfile     => "${apache::params::pidfile}",
#    datadir     => "${apache::params::datadir}",
#    logfile     => "${apache::params::logfile}",
#    logdir      => "${apache::params::logdir}",
#    protocol    => "${apache::params::protocol}",
#    port        => "${apache::params::port}",
#    description => "What Puppet knows about apache" ,
#    run         => "httpd -V",
#  }
#
define puppi::info::module (
  $packagename    = '',
  $servicename    = '',
  $processname    = '',
  $configfile     = '',
  $configdir      = '',
  $initconfigfile = '',
  $pidfile        = '',
  $datadir        = '',
  $logfile        = '',
  $logdir         = '',
  $protocol       = '',
  $port           = '',
  $description    = '',
  $run            = '',
  $verbose        = 'no',
  $templatefile   = 'puppi/info/module.erb' ) {

  require puppi
  require puppi::params

  file { "${puppi::params::infodir}/${name}":
    ensure  => present,
    mode    => '0750',
    owner   => $puppi::params::configfile_owner,
    group   => $puppi::params::configfile_group,
    require => Class['puppi'],
    content => template($templatefile),
    tag     => 'puppi_info',
  }

}
# Define puppi::info::readme
#
# This is a puppi info plugin that provides a Readme text which can be
# used to show local info on the managed server and eventually run custom commands.
#
#  puppi::info::readme { "myapp":
#    description => "Guidelines for myapp setup",
#    readme => "myapp/readme.txt" ,
#    run     => "myapp -V",
#  }
#
define puppi::info::readme (
  $description       = '',
  $readme            = '',
  $autoreadme        = 'no',
  $run               = '',
  $source_module     = 'undefined',
  $templatefile      = 'puppi/info/readme.erb' ) {

  require puppi
  require puppi::params

  $bool_autoreadme = any2bool($autoreadme)

  file { "${puppi::params::infodir}/${name}":
    ensure  => present,
    mode    => '0750',
    owner   => $puppi::params::configfile_owner,
    group   => $puppi::params::configfile_group,
    require => Class['puppi'],
    content => template($templatefile),
    tag     => 'puppi_info',
  }

  $readme_source = $readme ? {
    ''      => 'puppet:///modules/puppi/info/readme/readme',
    default => $readme,
  }

  file { "${puppi::params::readmedir}/${name}":
    ensure  => present,
    mode    => '0644',
    owner   => $puppi::params::configfile_owner,
    group   => $puppi::params::configfile_group,
    require => File['puppi_readmedir'],
    source  => $readme_source,
    tag     => 'puppi_info',
  }

  if $bool_autoreadme == true {
  file { "${puppi::params::readmedir}/${name}-custom":
    ensure  => present,
    mode    => '0644',
    owner   => $puppi::params::configfile_owner,
    group   => $puppi::params::configfile_group,
    require => File['puppi_readmedir'],
    source  => [
      "puppet:///modules/${source_module}/puppi/info/readme/readme-${::hostname}" ,
      "puppet:///modules/${source_module}/puppi/info/readme/readme-${::role}" ,
      "puppet:///modules/${source_module}/puppi/info/readme/readme-default" ,
      "puppet:///modules/puppi/info/readme/readme-${::hostname}" ,
      "puppet:///modules/puppi/info/readme/readme-${::role}" ,
      'puppet:///modules/puppi/info/readme/readme-default'
    ],
    tag     => 'puppi_info',
    }
  }

}
# = Class: puppi
#
# This is Puppi NextGen
# Includes both first generation of Puppi and the
# NextGen developments and modules integration
#
# == Parameters
#
# [*version*]
#   Define the Puppi version to use:
#   1 - First generation of Puppi, compatible with old modules
#   2 - NextGen version. Intended to work with NextGen modules
#   Default: 1 , for the moment
#
# [*install_dependencies*]
#   Set to false if you want to manage the sofware puppi needs
#   with your local modules.
#
# [*template*]
#   Sets the path to a custom template for /etc/puppi/puppi.conf
#
# [*helpers_class*]
#   Name of the class there default helpers are defined
#   (Used on in Puppi 2)
#
# [*logs_retention_days*]
#   Number of days for retenton of puppi logs. Default 30
#   This option creates a script in /etc/cron.daily that purges
#   all the old logs. Set to false or to 0 to remove the purge script.
#
# [*extra_class*]
#   Name of the class where extra puppi resources are added
#   Here, by default are placed general system commands for
#   puppi info, check and log
#
class puppi (
  $version              = params_lookup( 'version' ),
  $install_dependencies = params_lookup( 'install_dependencies' ),
  $template             = params_lookup( 'template' ),
  $helpers_class        = params_lookup( 'helpers_class' ),
  $logs_retention_days  = params_lookup( 'logs_retention_days' ),
  $extra_class          = params_lookup( 'extra_class' )
  ) inherits puppi::params {

  $bool_install_dependencies=any2bool($install_dependencies)

  # Manage Version
  $puppi_ensure = $puppi::version ? {
    1 => '/usr/sbin/puppi.one',
    2 => '/usr/local/bin/puppi',
  }

  file { 'puppi.link':
    ensure => $puppi_ensure,
    path   => '/usr/sbin/puppi',
  }

  # Puppi version one is always installed
  include puppi::one

  # Puppi 2 gem (still experimental) is installed only when forced
  if $puppi::version == '2' {
    include puppi::two
  }

  # Create Puppi common dirs and scripts
  include puppi::skel

  # Include extra resources
  include $puppi::extra_class

  # Include some packages needed by Puppi
  if $bool_install_dependencies {
    include puppi::dependencies
  }

}
# Define puppi::initialize
#
# This define creates a file with a initialize command that can be used locally.
#
# Usage:
# puppi::initialize { "Retrieve files":
#   command  => "get_file.sh",
#   argument => "/remote/dir/file",
#   priority => "10",
#   user   => "root",
#   project  => "spysite",
# }
#
define puppi::initialize (
  $command,
  $project,
  $arguments = '',
  $priority  = '50',
  $user      = 'root',
  $enable    = true ) {

  require puppi
  require puppi::params

  $ensure = bool2ensure($enable)

  file { "${puppi::params::projectsdir}/${project}/initialize/${priority}-${name}":
    ensure  => $ensure,
    mode    => '0750',
    owner   => $puppi::params::configfile_owner,
    group   => $puppi::params::configfile_group,
    require => Class['puppi'],
    content => "su - ${user} -c \"export project=${project} && ${puppi::params::scriptsdir}/${command} ${arguments}\"\n",
    tag     => 'puppi_initialize',
  }

}
# = Define: puppi::install_packages
#
# This define installs a list of packages without manging them as Puppet
# resources. It's useful when you need a set of packages installed,
# for example as prerequisites to build code from source, but you don't want
# to create Puppet package resources for them (since they may conflict with
# existing classes that provide the same packages.
#
# == Parameters:
#
# [*packages*]
#   String. Required.
#   A space separated list of of the packages to install
#
# [*template*]
#   String. Optional. Default: 'puppi/install_packages.erb'
#   The template to use to generate the script that installs the packages
#
# [*scrips_dir*]
#   String. Optional. Default: '/root/puppi_install_packages'
#    The directory where you place the scripts created by the define.
#
# [*autorun*]
#   Boolean. Default: true.
#   Define if to automatically execute the script when Puppet runs.
#
# [*refreshonly*]
#   Boolean. Optional. Default: true
#   Defines the logic of execution of the script when Puppet runs.
#   Maps to the omonymous Exec type argument.
#
# [*timeout*]
#   String. Optional. Default: '600'
#   Exec timeout in seconds.
#
# [*ensure*]
#   Define if the runscript script and eventual cron job
#   must be present or absent. Default: present.
#
# == Examples
#
# - Minimal setup
# puppi::install_packages { 'build_tools':
#   source           => 'build-essential vim git-core curl bison',
# }
#
define puppi::install_packages (
  $packages,
  $template         = 'puppi/install_packages.erb',
  $scripts_dir      = '/root/puppi_install_packages',
  $autorun          = true,
  $refreshonly      = true,
  $timeout          = '600',
  $ensure           = 'present' ) {

  if ! defined(File[$scripts_dir]) {
    file { $scripts_dir:
      ensure => directory,
      mode   => '0755',
      owner  => 'root',
      group  => 'root',
    }
  }

  file { "install_packages_${name}":
    ensure  => $ensure,
    path    => "${scripts_dir}/${name}",
    mode    => '0755',
    owner   => 'root',
    group   => 'root',
    content => template($template),
  }

  if $autorun == true {
    exec { "install_packages_${name}":
      command     => "${scripts_dir}/${name}",
      refreshonly => $refreshonly,
      subscribe   => File["install_packages_${name}"],
      timeout     => $timeout,
    }
  }

}
# Define puppi::log
#
# This define creates a basic log file that simply contains
# the list of logs to show when issuing the puppi log command.
#
# == Usage:
# puppi::log { "system":
#   description => "General System Logs" ,
#   log  => [ "/var/log/syslog" , "/var/log/messages" ],
# }
#
# :include:../README.log
#
define puppi::log (
  $log,
  $description = '' ) {

  require puppi
  require puppi::params

  $array_log = is_array($log) ? {
    false     => split($log, ','),
    default   => $log,
  }

  file { "${puppi::params::logsdir}/${name}":
    ensure  => 'present',
    mode    => '0644',
    owner   => $puppi::params::configfile_owner,
    group   => $puppi::params::configfile_group,
    require => Class['puppi'],
    content => template('puppi/log.erb'),
    tag     => 'puppi_log',
  }

}
# = Class puppi::mcollective::client
#
# This class installs the mc puppi command for mcollective clients
# (Note that in mcollective terminology a client is an host from
# where you can manage mcollective servers)
#
# The class installs also the puppideploy and puppicheck commands
# that are simple wrappers about mco puppi that correctly trap
# remote errors and can be used in automatic procedures or
# to give limited access (typically via sudo) to mc puppi commands
#
# They can be integrated, for example, in Jenkins as remote ssh
# commands to manage deployments or tests
#
# == Usage:
# include puppi::mcollective::client
#
# :include:../README.mcollective
#
class puppi::mcollective::client {

  require puppi::params
  require puppi::mcollective::server

# OLD STYLE mc-puppi command
  file { '/usr/local/bin/mc-puppi':
    ensure  => 'present',
    mode    => '0755',
    owner   => 'root',
    group   => 'root',
    source  => 'puppet:///modules/puppi/mcollective/mc-puppi',
    require => Class['mcollective'],
    }

# mco application TODO
#  file { "${puppi::params::mcollective}/application/puppi.rb":
#    ensure  => 'present',
#    mode    => '0644',
#    owner   => 'root',
#    group   => 'root',
#    source  => 'puppet:///modules/puppi/mcollective/mcpuppi.rb',
#  }

  file { '/usr/bin/puppicheck':
    ensure  => 'present',
    mode    => '0750',
    owner   => $puppi::params::mcollective_user,
    group   => $puppi::params::mcollective_group,
    source  => 'puppet:///modules/puppi/mcollective/puppicheck',
  }

  file { '/usr/bin/puppideploy':
    ensure  => 'present',
    mode    => '0750',
    owner   => $puppi::params::mcollective_user,
    group   => $puppi::params::mcollective_group,
    source  => 'puppet:///modules/puppi/mcollective/puppideploy',
  }

}
# = Class puppi::mcollective::server
#
# This class installs the puppi agent on mcollective servers
# (Note that in mcollective terminology a server is an host
# managed by a mcollective client)
#
# == Usage:
# include puppi::mcollective::server
#
# :include:../README.mcollective
#
class puppi::mcollective::server {

  require puppi::params

  file { "${puppi::params::mcollective}/agent/puppi.ddl":
    ensure  => 'present',
    mode    => '0644',
    owner   => 'root',
    group   => 'root',
    source  => 'puppet:///modules/puppi/mcollective/puppi.ddl',
    require => Class['mcollective'],
  }

  file { "${puppi::params::mcollective}/agent/puppi.rb":
    ensure  => 'present',
    mode    => '0644',
    owner   => 'root',
    group   => 'root',
    source  => 'puppet:///modules/puppi/mcollective/puppi.rb',
    require => Class['mcollective'],
  }

}
# Define: puppi::netinstall
#
# This defines simplifies the installation of a file
# downloaded from the web. It provides arguments to manage
# different kind of downloads and custom commands.
# It's used, among the others, by NextGen modules of webapps
# when the argument install is set to => source
#
# == Variables
#
# [*url*]
#   The Url of the file to retrieve. Required.
#   Example: http://www.example42.com/file.tar.gz
#
# [*destination_dir*]
#   The final destination where to unpack or copy what has been
#   downloaded. Required.
#   Example: /var/www/html
#
# [*retrieve_args*]
#   A string of arguments to pass to wget.
#
# [*extracted_dir*]
#   The name of a directory or file created after the extraction
#   Needed only if its name is different from the downloaded file name
#   (without suffixes). Optional.
#
# [*owner*]
#   The user owner of the directory / file created. Default: root
#
# [*group*]
#   The group owner of the directory / file created. Default: root
#
# [*timeout*]
#   The timeout in seconds for each command executed
#
# [*work_dir*]
#   A temporary work dir where file is downloaded. Default: /var/tmp
#
# [*path*]
#  Define the path for the exec commands.
#  Default: /bin:/sbin:/usr/bin:/usr/sbin
#
# [*exec_env*]
#   Define any additional environment variables to be used with the
#   exec commands. Note that if you use this to set PATH, it will
#   override the path attribute. Multiple environment variables
#   should be specified as an array.
#
# [*extract_command*]
#   The command used to extract the downloaded file.
#   By default is autocalculated accoring to the file extension
#   Set 'rsync' if the file has to be placed in the destination_dir
#   as is (for example for war files)
#
# [*preextract_command*]
#   An optional custom command to run before extracting the file.
#
# [*postextract_command*]
#   An optional custom command to run after having extracted the file.
#
define puppi::netinstall (
  $url,
  $destination_dir,
  $extracted_dir       = '',
  $retrieve_command    = 'wget',
  $retrieve_args       = '',
  $owner               = 'root',
  $group               = 'root',
  $timeout             = '3600',
  $work_dir            = '/var/tmp',
  $path                = '/bin:/sbin:/usr/bin:/usr/sbin',
  $extract_command     = '',
  $preextract_command  = '',
  $postextract_command = '',
  $postextract_cwd     = '',
  $exec_env            = []
  ) {

  $source_filename = url_parse($url,'filename')
  $source_filetype = url_parse($url,'filetype')
  $source_dirname = url_parse($url,'filedir')

  $real_extract_command = $extract_command ? {
    ''      => $source_filetype ? {
      '.tgz'     => 'tar -zxf',
      '.gz'      => 'tar -zxf',
      '.bz2'     => 'tar -jxf',
      '.tar'     => 'tar -xf',
      '.zip'     => 'unzip',
      default    => 'tar -zxf',
    },
    default => $extract_command,
  }

  $extract_command_second_arg = $real_extract_command ? {
    /^cp.*/    => '.',
    /^rsync.*/ => '.',
    default    => '',
  }

  $real_extracted_dir = $extracted_dir ? {
    ''      => $real_extract_command ? {
      /(^cp.*|^rsync.*)/         => $source_filename,
      /(^tar -zxf*|^tar -jxf*)/  => regsubst($source_dirname,'.tar',''),
      default                    => $source_dirname,
    },
    default => $extracted_dir,
  }

  $real_postextract_cwd = $postextract_cwd ? {
    ''      => "${destination_dir}/${real_extracted_dir}",
    default => $postextract_cwd,
  }

  if $preextract_command {
    exec { "PreExtract ${source_filename} in ${destination_dir}":
      command     => $preextract_command,
      subscribe   => Exec["Retrieve ${url} in ${work_dir}"],
      refreshonly => true,
      path        => $path,
      environment => $exec_env,
      timeout     => $timeout,
    }
  }

  exec { "Retrieve ${url} in ${work_dir}":
    cwd         => $work_dir,
    command     => "${retrieve_command} ${retrieve_args} ${url}",
    creates     => "${work_dir}/${source_filename}",
    timeout     => $timeout,
    path        => $path,
    environment => $exec_env,
  }

  exec { "Extract ${source_filename} from ${work_dir}":
    command     => "mkdir -p ${destination_dir} && cd ${destination_dir} && ${real_extract_command} ${work_dir}/${source_filename} ${extract_command_second_arg}",
    unless      => "ls ${destination_dir}/${real_extracted_dir}",
    creates     => "${destination_dir}/${real_extracted_dir}",
    timeout     => $timeout,
    require     => Exec["Retrieve ${url} in ${work_dir}"],
    path        => $path,
    environment => $exec_env,
    notify      => Exec["Chown ${source_filename} in ${destination_dir}"],
  }

  exec { "Chown ${source_filename} in ${destination_dir}":
    command     => "chown -R ${owner}:${group} ${destination_dir}/${real_extracted_dir}",
    refreshonly => true,
    timeout     => $timeout,
    require     => Exec["Extract ${source_filename} from ${work_dir}"],
    path        => $path,
    environment => $exec_env,
  }

  if $postextract_command {
    exec { "PostExtract ${source_filename} in ${destination_dir}":
      command     => $postextract_command,
      cwd         => $real_postextract_cwd,
      subscribe   => Exec["Extract ${source_filename} from ${work_dir}"],
      refreshonly => true,
      timeout     => $timeout,
      require     => [Exec["Retrieve ${url} in ${work_dir}"],Exec["Chown ${source_filename} in ${destination_dir}"]],
      path        => $path,
      environment => $exec_env,
    }
  }
}

# Class: puppi::one
#
# Installs Puppi 1.0
#
class puppi::one {

  require puppi::params

  # Main configuration file
  file { 'puppi.conf':
    ensure  => present,
    path    => "${puppi::params::basedir}/puppi.conf",
    mode    => '0644',
    owner   => $puppi::params::configfile_owner,
    group   => $puppi::params::configfile_group,
    content => template($puppi::template),
    require => File['puppi_basedir'],
  }

  # The Puppi 1.0 command
  file { 'puppi':
    ensure  => present,
    path    => '/usr/sbin/puppi.one',
    mode    => '0750',
    owner   => $puppi::params::configfile_owner,
    group   => $puppi::params::configfile_group,
    content => template('puppi/puppi.erb'),
    require => File['puppi_basedir'],
  }

}
# Class: puppi::params
#
# Sets internal variables and defaults for puppi module
#
class puppi::params  {

## PARAMETERS
  $version              = '1'
  $install_dependencies = true
  $template             = 'puppi/puppi.conf.erb'
  $helpers_class        = 'puppi::helpers'
  $logs_retention_days  = '30'
  $extra_class          = 'puppi::extras'


## INTERNALVARS
  $basedir     = '/etc/puppi'
  $scriptsdir  = '/etc/puppi/scripts'
  $checksdir   = '/etc/puppi/checks'
  $logsdir     = '/etc/puppi/logs'
  $infodir     = '/etc/puppi/info'
  $tododir     = '/etc/puppi/todo'
  $projectsdir = '/etc/puppi/projects'
  $datadir     = '/etc/puppi/data'
  $helpersdir  = '/etc/puppi/helpers'
  $libdir      = '/var/lib/puppi'
  $readmedir   = '/var/lib/puppi/readme'
  $logdir      = '/var/log/puppi'

  $archivedir = $::puppi_archivedir ? {
    ''      => '/var/lib/puppi/archive',
    default => $::puppi_archivedir,
  }

  $workdir = $::puppi_workdir ? {
    ''      => '/tmp/puppi',
    default => $::puppi_workdir,
  }

  $configfile_mode  = '0644'
  $configfile_owner = 'root'
  $configfile_group = 'root'

# External tools
# Directory where are placed the checks scripts
# By default we use Nagios plugins
  $checkpluginsdir = $::operatingsystem ? {
    /(?i:RedHat|CentOS|Scientific|Amazon|Linux)/ => $::architecture ? {
      x86_64  => '/usr/lib64/nagios/plugins',
      default => '/usr/lib/nagios/plugins',
    },
    default                    => '/usr/lib/nagios/plugins',
  }

  $package_nagiosplugins = $::operatingsystem ? {
    /(?i:RedHat|CentOS|Scientific|Amazon|Linux|Fedora)/ => 'nagios-plugins-all',
    default                       => 'nagios-plugins',
  }

  $package_mail = $::operatingsystem ? {
    /(?i:Debian|Ubuntu|Mint)/ => 'bsd-mailx',
    default           => 'mailx',
  }

  $ntp = $::ntp_server ? {
    ''    => 'pool.ntp.org' ,
    default => is_array($::ntp_server) ? {
      false   => $::ntp_server,
      true  => $::ntp_server[0],
      default => $::ntp_server,
    }
  }

# Mcollective paths
# TODO: Add Paths for Puppet Enterprise:
# /opt/puppet/libexec/mcollective/mcollective/
  $mcollective = $::operatingsystem ? {
    debian  => '/usr/share/mcollective/plugins/mcollective',
    ubuntu  => '/usr/share/mcollective/plugins/mcollective',
    centos  => '/usr/libexec/mcollective/mcollective',
    redhat  => '/usr/libexec/mcollective/mcollective',
    default => '/usr/libexec/mcollective/mcollective',
  }

  $mcollective_user = 'root'
  $mcollective_group = 'root'


# Commands used in puppi info templates
  $info_package_query = $::operatingsystem ? {
    /(?i:RedHat|CentOS|Scientific|Amazon|Linux)/ => 'rpm -qi',
    /(?i:Ubuntu|Debian|Mint)/          => 'dpkg -s',
    default                    => 'echo',
  }
  $info_package_list = $::operatingsystem ? {
    /(?i:RedHat|CentOS|Scientific|Amazon|Linux)/ => 'rpm -ql',
    /(?i:Ubuntu|Debian|Mint)/                    => 'dpkg -L',
    default                                      => 'echo',
  }
  $info_service_check = $::operatingsystem ? {
    default => '/etc/init.d/',
  }

}
# Define puppi::project
#
# This define creates and configures a Puppi project
# You must use different puppi::deploy and puppi::rollback defines
# to to build up the commands list
#
define puppi::project (
  $enable = true ) {

  require puppi::params

  $ensure = any2bool($enable) ? {
    false   => 'absent',
    default => 'directory',
  }

  $ensurefile = bool2ensure($enable)

  # Create Project subdirs
  file {
    "${puppi::params::projectsdir}/${name}":
      ensure  => $ensure,
      mode    => '0755',
      owner   => $puppi::params::configfile_owner,
      group   => $puppi::params::configfile_group,
      force   => true;

    "${puppi::params::projectsdir}/${name}/check":
      ensure  => $ensure,
      mode    => '0755',
      owner   => $puppi::params::configfile_owner,
      group   => $puppi::params::configfile_group,
      force   => true,
      recurse => true,
      purge   => true,
      require => File["${puppi::params::projectsdir}/${name}"];

    "${puppi::params::projectsdir}/${name}/rollback":
      ensure  => $ensure,
      mode    => '0755',
      owner   => $puppi::params::configfile_owner,
      group   => $puppi::params::configfile_group,
      force   => true,
      recurse => true,
      purge   => true,
      require => File["${puppi::params::projectsdir}/${name}"];

    "${puppi::params::projectsdir}/${name}/deploy":
      ensure  => $ensure,
      mode    => '0755',
      owner   => $puppi::params::configfile_owner,
      group   => $puppi::params::configfile_group,
      force   => true,
      recurse => true,
      purge   => true,
      require => File["${puppi::params::projectsdir}/${name}"];

    "${puppi::params::projectsdir}/${name}/initialize":
      ensure  => $ensure,
      mode    => '0755',
      owner   => $puppi::params::configfile_owner,
      group   => $puppi::params::configfile_group,
      force   => true,
      recurse => true,
      purge   => true,
      require => File["${puppi::params::projectsdir}/${name}"];
      
    "${puppi::params::projectsdir}/${name}/configure":
      ensure  => $ensure,
      mode    => '0755',
      owner   => $puppi::params::configfile_owner,
      group   => $puppi::params::configfile_group,
      force   => true,
      recurse => true,
      purge   => true,
      require => File["${puppi::params::projectsdir}/${name}"];

    "${puppi::params::projectsdir}/${name}/report":
      ensure  => $ensure,
      mode    => '0755',
      owner   => $puppi::params::configfile_owner,
      group   => $puppi::params::configfile_group,
      force   => true,
      recurse => true,
      purge   => true,
      require => File["${puppi::params::projectsdir}/${name}"];
  }

  # Create Project configuration file
  file {
    "${puppi::params::projectsdir}/${name}/config":
      ensure  => $ensurefile,
      content => template('puppi/project/config.erb'),
      mode    => '0644',
      owner   => $puppi::params::configfile_owner,
      group   => $puppi::params::configfile_group,
      require => File["${puppi::params::projectsdir}/${name}"];
  }

}
In this directory you find some examples of deploy procedures
for general purposes deploys (single wars, single files, tarballs, list
of files from a list...) described in a single define.

They are made in order to be generic enough to adapt to different 
environments and scenarious but you might need to design your
own deployment process.

In order to do that you can create a new define that includes:
- All the variables, required or optional, you may want
- One puppi:project statement 
- All the puppi::deploy statements you need (each one runs a command)
- All the puppi::rollback statements you need
- One or more puppi::report statements for reporting

The examples provided here make use of the scripts provided in
puppi/files/scripts and tend to split the deploy procedures in many 
different, reusable, scripts (one gets the source file(s), another 
archives the current content, another one actually copies the files
to deploy and so on) but you can use just a single new script or 
whatever combination you might prefer.

The default puppi scripts and the general ordering of commands
execution in these sample deploy defines follow this scheme:
Priority - Kind of operations
1x - Pre Deploy checks 
2x - Files retrieving and preparation
3x - Operations to accomplish before the deploy (Archiving, Services stopping..)
40 - Deploy.sh - The script that actually copied the files on deploy dir
4x - Operations to accomplish after the deploy (Services start...)
8x - Post Deploy checks
# = Define puppi::project::archive
#
# This is a puppi deployment project to be used for archives
# like tarballs and zips
#
#
# It uses different "core" defines (puppi::project, puppi:deploy (many),
# puppi::rollback (many)) to build a full featured template project for
# automatic deployments.
# If you need to customize it, either change the template defined here or
# build up your own custom ones.
#
# == Variables:
#
# [*source*]
#   The full URL of the main file to retrieve.
#   Format should be in URI standard (http:// file:// ssh:// rsync://).
#
# [*deploy_root*]
#   The destination directory where the retrieved file(s) are deployed.
#
# [*user*]
#   (Optional) - The user to be used for deploy operations.
#
# [*predeploy_customcommand*]
#   (Optional) -  Full path with arguments of an eventual custom command to
#   execute before the deploy. The command is executed as $predeploy_user.
#
# [*predeploy_user*]
#   (Optional) - The user to be used to execute the $predeploy_customcommand.
#   By default is the same of $user.
#
# [*predeploy_priority*]
#   (Optional) - The priority (execution sequence number) that defines when,
#   during the deploy procedure, the $predeploy_customcommand is executed
#   Default: 39 (immediately before the copy of files on the deploy root).
#
# [*postdeploy_customcommand*]
#   (Optional) -  Full path with arguments of an eventual custom command to
#   execute after the deploy. The command is executed as $postdeploy_user.
#
# [*postdeploy_user*]
#   (Optional) - The user to be used to execute the $postdeploy_customcommand.
#   By default is the same of $user.
#
# [*postdeploy_priority*]
#   (Optional) - The priority (execution sequence number) that defines when,
#   during the deploy procedure, the $postdeploy_customcommand is executed
#   Default: 41 (immediately after the copy of files on the deploy root).
#
# [*disable_services*]
#   (Optional) - The names (space separated) of the services you might want to
#   stop during deploy. By default is blank. Example: "apache puppet monit".
#
# [*firewall_src_ip*]
#   (Optional) - The IP address of a loadbalancer you might want to block out
#   during a deploy.
#
# [*firewall_dst_port*]
#   (Optional) - The local port to block from the loadbalancer during deploy
#   (Default all).
#
# [*firewall_delay*]
#   (Optional) - A delay time in seconds to wait after the block of
#   $firewall_src_ip. Should be at least as long as the loadbalancer check
#   interval for the services stopped during deploy (Default: 1).
#
# [*report_email*]
#   (Optional) - The (space separated) email(s) to notify of deploy/rollback
#   operations. If none is specified, no email is sent.
#
# [*clean_deploy*]
#   (Optional, default false) - If during the deploy procedure, all the
#   existing files that are not on the source have to be deleted.
#   (When true, a --delete option is added to the rsync command)
#   Do not set to true if source files are incremental.
#
# [*backup_enable*]
#   (Optional, default true) - If the backup of files in the deploy dir
#   is done (before deploy). If set to false, rollback is disabled.
#
# [*backup_rsync_options*]
#   (Optional) - The extra options to pass to rsync for backup operations. Use
#   it, for example, to exclude directories that you don't want to archive.
#   IE: "--exclude .snapshot --exclude cache --exclude www/cache".
#
# [*backup_retention*]
#   (Optional) - Number of backup archives to keep. (Default 5).
#   Lower the default value if your backups are too large and may fill up the
#   filesystem.
#
# [*run_checks*]
#   (Optional) - If you want to run local puppi checks before and after the
#   deploy procedure. Default: "true".
#
# [*always_deploy*]
#   (Optional) - If you always deploy what has been downloaded. Default="yes",
#   if set to "no" a checksum is made between the files previously downloaded
#   and the new files. If they are the same the deploy is not done.
#
# [*auto_deploy*]
#   (Optional) - If you want to automatically run this puppi deploy when
#   Puppet runs. Default: 'false'
#
define puppi::project::archive (
  $source,
  $deploy_root,
  $user                     = 'root',
  $predeploy_customcommand  = '',
  $predeploy_user           = '',
  $predeploy_priority       = '39',
  $postdeploy_customcommand = '',
  $postdeploy_user          = '',
  $postdeploy_priority      = '41',
  $disable_services         = '',
  $firewall_src_ip          = '',
  $firewall_dst_port        = '0',
  $firewall_delay           = '1',
  $report_email             = '',
  $clean_deploy             = false,
  $backup_enable            = true,
  $backup_rsync_options     = '--exclude .snapshot',
  $backup_retention         = '5',
  $run_checks               = true,
  $always_deploy            = true,
  $auto_deploy              = false,
  $enable                   = true ) {

  require puppi
  require puppi::params

  # Set default values
  $predeploy_real_user = $predeploy_user ? {
    ''      => $user,
    default => $predeploy_user,
  }

  $postdeploy_real_user = $postdeploy_user ? {
    ''      => $user,
    default => $postdeploy_user,
  }

  $real_always_deploy = any2bool($always_deploy) ? {
    false   => 'no',
    true    => 'yes',
  }


  $bool_run_checks = any2bool($run_checks)
  $bool_clean_deploy = any2bool($clean_deploy)
  $bool_backup_enable = any2bool($backup_enable)
  $bool_auto_deploy = any2bool($auto_deploy)

  $source_type = url_parse($source,filetype)

  $real_source_type = $source_type ? {
    '.tar'     => 'tar',
    '.tar.gz'  => 'tarball',
    '.gz'      => 'tarball',
    '.tgz'     => 'tarball',
    '.zip'     => 'zip',
  }

### CREATE PROJECT
    puppi::project { $name:
      enable => $enable ,
    }

### DEPLOY SEQUENCE
  if ($bool_run_checks == true) {
    puppi::deploy { "${name}-Run_PRE-Checks":
      priority  => '10' ,
      command   => 'check_project.sh' ,
      arguments => $name ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }

    # Here source file is retrieved
    puppi::deploy { "${name}-Retrieve_Archive":
      priority  => '20' ,
      command   => 'get_file.sh' ,
      arguments => "-s ${source} -t ${real_source_type} -a ${real_always_deploy}" ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }

    puppi::deploy { "${name}-PreDeploy_Archive":
      priority  => '25' ,
      command   => 'predeploy.sh' ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }

  if ($firewall_src_ip != '') {
    puppi::deploy { "${name}-Load_Balancer_Block":
      priority  => '25' ,
      command   => 'firewall.sh' ,
      arguments => "${firewall_src_ip} ${firewall_dst_port} on ${firewall_delay}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($bool_backup_enable == true) {
    puppi::deploy { "${name}-Backup_existing_Files":
      priority  => '30' ,
      command   => 'archive.sh' ,
      arguments => "-b ${deploy_root} -o '${backup_rsync_options}' -n ${backup_retention}" ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($disable_services != '') {
    puppi::deploy { "${name}-Disable_extra_services":
      priority  => '36' ,
      command   => 'service.sh' ,
      arguments => "stop ${disable_services}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($predeploy_customcommand != '') {
    puppi::deploy { "${name}-Run_Custom_PreDeploy_Script":
      priority  => $predeploy_priority ,
      command   => 'execute.sh' ,
      arguments => $predeploy_customcommand ,
      user      => $predeploy_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

    # Here is done the deploy on $deploy_root
    puppi::deploy { "${name}-Deploy":
      priority  => '40' ,
      command   => 'deploy_files.sh' ,
      arguments => "-d ${deploy_root} -c ${bool_clean_deploy}",
      user      => $user ,
      project   => $name ,
      enable    => $enable ,
    }

  if ($postdeploy_customcommand != '') {
    puppi::deploy { "${name}-Run_Custom_PostDeploy_Script":
      priority  => $postdeploy_priority ,
      command   => 'execute.sh' ,
      arguments => $postdeploy_customcommand ,
      user      => $postdeploy_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($disable_services != '') {
    puppi::deploy { "${name}-Enable_extra_services":
      priority  => '44' ,
      command   => 'service.sh' ,
      arguments => "start ${disable_services}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($firewall_src_ip != '') {
    puppi::deploy { "${name}-Load_Balancer_Unblock":
      priority  => '46' ,
      command   => 'firewall.sh' ,
      arguments => "${firewall_src_ip} ${firewall_dst_port} off 0" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($bool_run_checks == true) {
    puppi::deploy { "${name}-Run_POST-Checks":
      priority  => '80' ,
      command   => 'check_project.sh' ,
      arguments => $name ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }


### ROLLBACK PROCEDURE

  if ($bool_backup_enable == true) {
    if ($firewall_src_ip != '') {
      puppi::rollback { "${name}-Load_Balancer_Block":
        priority  => '25' ,
        command   => 'firewall.sh' ,
        arguments => "${firewall_src_ip} ${firewall_dst_port} on ${firewall_delay}" ,
        user      => 'root',
        project   => $name ,
        enable    => $enable ,
      }
    }

    if ($disable_services != '') {
      puppi::rollback { "${name}-Disable_extra_services":
        priority  => '37' ,
        command   => 'service.sh' ,
        arguments => "stop ${disable_services}" ,
        user      => 'root',
        project   => $name ,
        enable    => $enable ,
      }
    }

    if ($predeploy_customcommand != '') {
      puppi::rollback { "${name}-Run_Custom_PreDeploy_Script":
        priority  => $predeploy_priority ,
        command   => 'execute.sh' ,
        arguments => $predeploy_customcommand ,
        user      => $predeploy_real_user ,
        project   => $name ,
        enable    => $enable ,
      }
    }

    puppi::rollback { "${name}-Recover_Files_To_Deploy":
      priority  => '40' ,
      command   => 'archive.sh' ,
      arguments => "-r ${deploy_root} -o '${backup_rsync_options}'" ,
      user      => $user ,
      project   => $name ,
      enable    => $enable ,
    }

    if ($postdeploy_customcommand != '') {
      puppi::rollback { "${name}-Run_Custom_PostDeploy_Script":
        priority  => $postdeploy_priority ,
        command   => 'execute.sh' ,
        arguments => $postdeploy_customcommand ,
        user      => $postdeploy_real_user ,
        project   => $name ,
        enable    => $enable ,
      }
    }

    if ($disable_services != '') {
      puppi::rollback { "${name}-Enable_extra_services":
        priority  => '44' ,
        command   => 'service.sh' ,
        arguments => "start ${disable_services}" ,
        user      => 'root',
        project   => $name ,
        enable    => $enable ,
      }
    }

    if ($firewall_src_ip != '') {
      puppi::rollback { "${name}-Load_Balancer_Unblock":
        priority  => '46' ,
        command   => 'firewall.sh' ,
        arguments => "${firewall_src_ip} ${firewall_dst_port} off 0" ,
        user      => 'root',
        project   => $name ,
        enable    => $enable ,
      }
    }

    if ($bool_run_checks == true) {
      puppi::rollback { "${name}-Run_POST-Checks":
        priority  => '80' ,
        command   => 'check_project.sh' ,
        arguments => $name ,
        user      => 'root' ,
        project   => $name ,
        enable    => $enable ,
      }
    }
  }

### REPORTING

  if ($report_email != '') {
    puppi::report { "${name}-Mail_Notification":
      priority  => '20' ,
      command   => 'report_mail.sh' ,
      arguments => $report_email ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

### AUTO DEPLOY DURING PUPPET RUN
  if ($bool_auto_deploy == true) {
    puppi::run { $name: }
  }

}
# = Define puppi::project::builder
#
# This is a shortcut define to build a puppi project for the deploy of web
# applications based on different sources: a war file, a tar file, a source dir,
# a list of files or a nexus maven repository
# It uses different "core" defines (puppi::project, puppi:deploy (many),
# puppi::rollback (many)) to build a full featured template project for
# automatic deployments.
# If you need to customize it, either change the template defined here or
# build up your own custom ones.
#
# == Variables:
#
# [*source*]
#   The full URL of the main file to retrieve.
#   Format should be in URI standard (http:// file:// ssh:// rsync://).
#
# [*source_type*]
#   The type of file that is retrieved. Accepted values: tarball, zip, list,
#   war, dir, maven-metadata.
#
# [*deploy_root*]
#   The destination directory where the retrieved file(s) are deployed.
#
# [*init_source*]
#   (Optional) - The full URL to be used to retrieve, for the first time,
#   the project files. They are copied directly to the $deploy_root
#   Format should be in URI standard (http:// file:// ssh:// svn://).
#
# [*magicfix*]
#   (Optional) - A string that is used as prefix or suffix according to the
#   context and the scripts used in the deploy procedure.
#
# [*user*]
#   (Optional) - The user to be used for deploy operations.
#
# [*predeploy_customcommand*]
#   (Optional) -  Full path with arguments of an eventual custom command to
#   execute before the deploy. The command is executed as $predeploy_user.
#
# [*predeploy_user*]
#   (Optional) - The user to be used to execute the $predeploy_customcommand.
#   By default is the same of $user.
#
# [*predeploy_priority*]
#   (Optional) - The priority (execution sequence number) that defines when,
#   during the deploy procedure, the $predeploy_customcommand is executed
#   Default: 39 (immediately before the copy of files on the deploy root).
#
# [*postdeploy_customcommand*]
#   (Optional) -  Full path with arguments of an eventual custom command to
#   execute after the deploy. The command is executed as $postdeploy_user.
#
# [*postdeploy_user*]
#   (Optional) - The user to be used to execute the $postdeploy_customcommand.
#   By default is the same of $user.
#
# [*postdeploy_priority*]
#   (Optional) - The priority (execution sequence number) that defines when,
#   during the deploy procedure, the $postdeploy_customcommand is executed
#   Default: 41 (immediately after the copy of files on the deploy root).
#
# [*disable_services*]
#   (Optional) - The names (space separated) of the services you might want to
#   stop during deploy. By default is blank. Example: "apache puppet monit".
#
# [*firewall_src_ip*]
#   (Optional) - The IP address of a loadbalancer you might want to block out
#   during a deploy.
#
# [*firewall_dst_port*]
#   (Optional) - The local port to block from the loadbalancer during deploy
#   (Default all).
#
# [*firewall_delay*]
#   (Optional) - A delay time in seconds to wait after the block of
#   $firewall_src_ip. Should be at least as long as the loadbalancer check
#   interval for the services stopped during deploy (Default: 1).
#
# [*report_email*]
#   (Optional) - The (space separated) email(s) to notify of deploy/rollback
#   operations. If none is specified, no email is sent.
#
# [*backup*]
#   (Optional) - How backups of files are made. Default: "full". Options:
#   "full" - Make full backup of the deploy_root before making the deploy
#   "diff" - Backup only the files that are going to be deployed. Note that
#     in order to make reliable rollbacks of versions older that the latest
#     you've to individually rollback every intermediate deploy
#   "false" - Do not make backups. This disables the option to make rollbacks
#
# [*backup_rsync_options*]
#   (Optional) - The extra options to pass to rsync for backup operations. Use
#   it, for example, to exclude directories that you don't want to archive.
#   IE: "--exclude .snapshot --exclude cache --exclude www/cache".
#
# [*backup_retention*]
#   (Optional) - Number of backup archives to keep. (Default 5).
#   Lower the default value if your backups are too large and may fill up the
#   filesystem.
#
# [*run_checks*]
#   (Optional) - If you want to run local puppi checks before and after the
#   deploy procedure. Default: "true".
#
# [*always_deploy*]
#   (Optional) - If you always deploy what has been downloaded. Default="yes",
#   if set to "no" a checksum is made between the files previously downloaded
#   and the new files. If they are the same the deploy is not done.
#
# == Usage
# A sample deploy of a zip with custom postdeploy command and mail notification
# puppi::project::builder { "cms":
#   source                   => "http://repo.example42.com/deploy/cms/cms.zip",
#   source_type              => "zip",
#   user                     => "root",
#   deploy_root              => "/var/www",
#   postdeploy_customcommand => "chown -R www-data /var/www/files",
#   postdeploy_user          => "root",
#   postdeploy_priority      => "41",
#   report_email             => "sysadmins@example42.com",
#   enable                   => "true",
# }
#
# [*auto_deploy*]
#   (Optional) - If you want to automatically run this puppi deploy when
#   Puppet runs. Default: 'false'
#
define puppi::project::builder (
  $source,
  $source_type,
  $deploy_root,
  $init_source              = '',
  $user                     = 'root',
  $magicfix                 = '',
  $predeploy_customcommand  = '',
  $predeploy_user           = '',
  $predeploy_priority       = '39',
  $postdeploy_customcommand = '',
  $postdeploy_user          = '',
  $postdeploy_priority      = '41',
  $disable_services         = '',
  $firewall_src_ip          = '',
  $firewall_dst_port        = '0',
  $firewall_delay           = '1',
  $report_email             = '',
  $backup                   = 'full',
  $backup_rsync_options     = '--exclude .snapshot',
  $backup_retention         = '5',
  $run_checks               = true,
  $always_deploy            = true,
  $auto_deploy              = false,
  $enable                   = true ) {

  require puppi
  require puppi::params

  # Autoinclude the puppi class
  include puppi

  # Set default values
  $predeploy_real_user = $predeploy_user ? {
    ''      => $user,
    default => $predeploy_user,
  }

  $postdeploy_real_user = $postdeploy_user ? {
    ''      => $user,
    default => $postdeploy_user,
  }

  $real_source_type = $source_type ? {
    'dir'            => 'dir',
    'tarball'        => 'tarball',
    'zip'            => 'zip',
    'gz'             => 'gz',
    'maven-metadata' => 'maven-metadata',
    'maven'          => 'maven-metadata',
    'war'            => 'war',
    'list'           => 'list',
  }

  $real_always_deploy = any2bool($always_deploy) ? {
    false   => 'no',
    true    => 'yes',
  }

  $bool_run_checks = any2bool($run_checks)
  $bool_auto_deploy = any2bool($auto_deploy)

  $source_filename = url_parse($source,'filename')

# Create Project
  puppi::project { $name: enable => $enable }


### INIT SEQUENCE
  if ($init_source != '') {
    puppi::initialize { "${name}-Deploy_Files":
      priority  => '40' ,
      command   => 'get_file.sh' ,
      arguments => "-s ${init_source} -d ${deploy_root}" ,
      user      => $user ,
      project   => $name ,
      enable    => $enable ,
    }
  }


### DEPLOY SEQUENCE
  if ($bool_run_checks == true) {
    puppi::deploy { "${name}-Run_PRE-Checks":
      priority  => '10' ,
      command   => 'check_project.sh' ,
      arguments => $name ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  # Here source file is retrieved
  puppi::deploy { "${name}-Retrieve_SourceFile":
    priority  => '20' ,
    command   => 'get_file.sh' ,
    arguments => "-s ${source} -t ${real_source_type} -a ${real_always_deploy}" ,
    user      => 'root' ,
    project   => $name ,
    enable    => $enable ,
  }

  $args_magicfix = $magicfix ? {
    ''      => '',
    default => "-m ${magicfix}" ,
  }

  if ($real_source_type == 'tarball') {
    puppi::deploy { "${name}-PreDeploy_Tar":
      priority  => '25' ,
      command   => 'predeploy.sh' ,
      arguments => $args_magicfix,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($real_source_type == 'zip') {

    puppi::deploy { "${name}-PreDeploy_Zip":
      priority  => '25' ,
      command   => 'predeploy.sh' ,
      arguments => $args_magicfix,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($real_source_type == 'list') {
    puppi::deploy { "${name}-Extract_File_Metadata":
      priority  => '22' ,
      command   => 'get_metadata.sh' ,
      arguments => $args_magicfix,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }

    $clean_file_list_magicfix = $magicfix ? {
      ''      => '',
      default => $magicfix,
    }

    puppi::deploy { "${name}-Clean_File_List":
      priority  => '24' ,
      command   => 'clean_filelist.sh' ,
      arguments => $clean_file_list_magicfix,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
    puppi::deploy { "${name}-Retrieve_Files":
      priority  => '25' ,
      command   => 'get_filesfromlist.sh' ,
      arguments => $source ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($backup == 'full') or ($backup == 'diff') {
    puppi::deploy { "${name}-Backup_existing_Files":
      priority  => '30' ,
      command   => 'archive.sh' ,
      arguments => "-b ${deploy_root} -m ${backup} -o '${backup_rsync_options}' -n ${backup_retention}" ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($firewall_src_ip != '') {
    puppi::deploy { "${name}-Load_Balancer_Block":
      priority  => '34' ,
      command   => 'firewall.sh' ,
      arguments => "${firewall_src_ip} ${firewall_dst_port} on ${firewall_delay}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($real_source_type == 'war') {
    puppi::deploy { "${name}-Remove_existing_WAR":
      priority  => '35' ,
      command   => 'delete.sh' ,
      arguments => "${deploy_root}/${source_filename}" ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
    puppi::deploy { "${name}-Check_undeploy":
      priority  => '36' ,
      command   => 'checkwardir.sh' ,
      arguments => "-a ${deploy_root}/${source_filename}" ,
      user      => $user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($disable_services != '') {
    puppi::deploy { "${name}-Disable_extra_services":
      priority  => '37' ,
      command   => 'service.sh' ,
      arguments => "stop ${disable_services}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($predeploy_customcommand != '') {
    puppi::deploy { "${name}-Run_Custom_PreDeploy_Script":
      priority  => $predeploy_priority ,
      command   => 'execute.sh' ,
      arguments => $predeploy_customcommand ,
      user      => $predeploy_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

    # Here is done the deploy on $deploy_root
    puppi::deploy { "${name}-Deploy":
      priority  => '40' ,
      command   => 'deploy.sh' ,
      arguments => $deploy_root ,
      user      => $user ,
      project   => $name ,
      enable    => $enable ,
    }

  if ($postdeploy_customcommand != '') {
    puppi::deploy { "${name}-Run_Custom_PostDeploy_Script":
      priority  => $postdeploy_priority ,
      command   => 'execute.sh' ,
      arguments => $postdeploy_customcommand ,
      user      => $postdeploy_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($disable_services != '') {
    puppi::deploy { "${name}-Enable_extra_services":
      priority  => '44' ,
      command   => 'service.sh' ,
      arguments => "start ${disable_services}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($real_source_type == 'war') {
    puppi::deploy { "${name}-Check_deploy":
      priority  => '45' ,
      command   => 'checkwardir.sh' ,
      arguments => "-p ${deploy_root}/${source_filename}" ,
      user      => $user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($firewall_src_ip != '') {
    puppi::deploy { "${name}-Load_Balancer_Unblock":
      priority  => '46' ,
      command   => 'firewall.sh' ,
      arguments => "${firewall_src_ip} ${firewall_dst_port} off 0" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($bool_run_checks == true) {
    puppi::deploy { "${name}-Run_POST-Checks":
      priority  => '80' ,
      command   => 'check_project.sh' ,
      arguments => $name ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }


### ROLLBACK PROCEDURE

  if ($firewall_src_ip != '') {
    puppi::rollback { "${name}-Load_Balancer_Block":
      priority  => '34' ,
      command   => 'firewall.sh' ,
      arguments => "${firewall_src_ip} ${firewall_dst_port} on ${firewall_delay}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($real_source_type == 'war') {
    puppi::rollback { "${name}-Remove_existing_WAR":
      priority  => '35' ,
      command   => 'delete.sh' ,
      arguments => "${deploy_root}/${source_filename}" ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
    puppi::rollback { "${name}-Check_undeploy":
      priority  => '36' ,
      command   => 'checkwardir.sh' ,
      arguments => "-a ${deploy_root}/${source_filename}" ,
      user      => $user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($disable_services != '') {
    puppi::rollback { "${name}-Disable_extra_services":
      priority  => '37' ,
      command   => 'service.sh' ,
      arguments => "stop ${disable_services}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($predeploy_customcommand != '') {
    puppi::rollback { "${name}-Run_Custom_PreDeploy_Script":
      priority  => $predeploy_priority ,
      command   => 'execute.sh' ,
      arguments => $predeploy_customcommand ,
      user      => $predeploy_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($backup == 'full') or ($backup == 'diff') {
    puppi::rollback { "${name}-Recover_Files_To_Deploy":
      priority  => '40' ,
      command   => 'archive.sh' ,
      arguments => "-r ${deploy_root} -m ${backup} -o '${backup_rsync_options}'" ,
      user      => $user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($postdeploy_customcommand != '') {
    puppi::rollback { "${name}-Run_Custom_PostDeploy_Script":
      priority  => $postdeploy_priority ,
      command   => 'execute.sh' ,
      arguments => $postdeploy_customcommand ,
      user      => $postdeploy_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($disable_services != '') {
    puppi::rollback { "${name}-Enable_extra_services":
      priority  => '44' ,
      command   => 'service.sh' ,
      arguments => "start ${disable_services}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($real_source_type == 'war') {
    puppi::rollback { "${name}-Check_deploy":
      priority  => '45' ,
      command   => 'checkwardir.sh' ,
      arguments => "-p ${deploy_root}/${source_filename}" ,
      user      => $user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($firewall_src_ip != '') {
    puppi::rollback { "${name}-Load_Balancer_Unblock":
      priority  => '46' ,
      command   => 'firewall.sh' ,
      arguments => "${firewall_src_ip} ${firewall_dst_port} off 0" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($bool_run_checks == true) {
    puppi::rollback { "${name}-Run_POST-Checks":
      priority  => '80' ,
      command   => 'check_project.sh' ,
      arguments => $name ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }


### REPORTING

  if ($report_email != '') {
    puppi::report { "${name}-Mail_Notification":
      priority  => '20' ,
      command   => 'report_mail.sh' ,
      arguments => $report_email ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

### AUTO DEPLOY DURING PUPPET RUN
  if ($bool_auto_deploy == true) {
    puppi::run { $name: }
  }

}
# = Define puppi::project::dir
#
# This is a shortcut define to build a puppi project for a deploy based
# on the syncronization of a directory.
# It uses different "core" defines (puppi::project, puppi:deploy (many),
# puppi::rollback (many)) to build a full featured template project for
# automatic deployments.
# If you need to customize it, either change the template defined here or
# build up your own custom ones.
#
# == Variables:
#
# [*source*]
#   The full URL of the main file to retrieve.
#   Format should be in URI standard (http:// file:// ssh:// rsync://).
#
# [*deploy_root*]
#   The destination directory where the retrieved file(s) are deployed.
#
# [*init_source*]
#   (Optional) - The full URL to be used to retrieve, for the first time,
#   the project files. They are copied directly to the $deploy_root
#   Format should be in URI standard (http:// file:// ssh:// svn://).
#
# [*user*]
#   (Optional) - The user to be used for deploy operations.
#
# [*predeploy_customcommand*]
#   (Optional) -  Full path with arguments of an eventual custom command to
#   execute before the deploy. The command is executed as $predeploy_user.
#
# [*predeploy_user*]
#   (Optional) - The user to be used to execute the $predeploy_customcommand.
#   By default is the same of $user.
#
# [*predeploy_priority*]
#   (Optional) - The priority (execution sequence number) that defines when,
#   during the deploy procedure, the $predeploy_customcommand is executed
#   Default: 39 (immediately before the copy of files on the deploy root).
#
# [*postdeploy_customcommand*]
#   (Optional) -  Full path with arguments of an eventual custom command to
#   execute after the deploy. The command is executed as $postdeploy_user.
#
# [*postdeploy_user*]
#   (Optional) - The user to be used to execute the $postdeploy_customcommand.
#   By default is the same of $user.
#
# [*postdeploy_priority*]
#   (Optional) - The priority (execution sequence number) that defines when,
#   during the deploy procedure, the $postdeploy_customcommand is executed
#   Default: 41 (immediately after the copy of files on the deploy root).
#
# [*init_script*]
#   (Optional - Obsolete) - The name (ex: tomcat) of the init script of your
#   Application server. If you define it, the AS is stopped and then started
#   during deploy. This option is deprecated, you can use $disable_services
#   for the same functionality
#
# [*disable_services*]
#   (Optional) - The names (space separated) of the services you might want to
#   stop during deploy. By default is blank. Example: "apache puppet monit".
#
# [*firewall_src_ip*]
#   (Optional) - The IP address of a loadbalancer you might want to block out
#   during a deploy.
#
# [*firewall_dst_port*]
#   (Optional) - The local port to block from the loadbalancer during deploy
#   (Default all).
#
# [*firewall_delay*]
#   (Optional) - A delay time in seconds to wait after the block of
#   $firewall_src_ip. Should be at least as long as the loadbalancer check
#   interval for the services stopped during deploy (Default: 1).
#
# [*report_email*]
#   (Optional) - The (space separated) email(s) to notify of deploy/rollback
#   operations. If none is specified, no email is sent.
#
# [*backup_rsync_options*]
#   (Optional) - The extra options to pass to rsync for backup operations. Use
#   it, for example, to exclude directories that you don't want to archive.
#   IE: "--exclude .snapshot --exclude cache --exclude www/cache".
#
# [*backup_retention*]
#   (Optional) - Number of backup archives to keep. (Default 5).
#   Lower the default value if your backups are too large and may fill up the
#   filesystem.
#
# [*run_checks*]
#   (Optional) - If you want to run local puppi checks before and after the
#   deploy procedure. Default: "true".
#
# [*skip_predeploy*]
#    For large data to deploy predeploy copy in /tmp/puppi might full the
#    filesystem. Set to "yes" to deploy directly to $deploy_root. Default: no
#    (files are first predeployed in /tmp/puppi then copied to $deploy_root)
#
# [*auto_deploy*]
#   (Optional) - If you want to automatically run this puppi deploy when
#   Puppet runs. Default: 'false'
#
define puppi::project::dir (
  $source,
  $deploy_root,
  $init_source              = '',
  $user                     = 'root',
  $predeploy_customcommand  = '',
  $predeploy_user           = '',
  $predeploy_priority       = '39',
  $postdeploy_customcommand = '',
  $postdeploy_user          = '',
  $postdeploy_priority      = '41',
  $init_script              = '',
  $disable_services         = '',
  $firewall_src_ip          = '',
  $firewall_dst_port        = '0',
  $firewall_delay           = '1',
  $report_email             = '',
  $backup_rsync_options     = '--exclude .snapshot',
  $backup_retention         = '5',
  $run_checks               = true,
  $skip_predeploy           = false,
  $auto_deploy              = false,
  $enable                   = true ) {

  require puppi
  require puppi::params

  # Set default values
  $predeploy_real_user = $predeploy_user ? {
    ''      => $user,
    default => $predeploy_user,
  }

  $postdeploy_real_user = $postdeploy_user ? {
    ''      => $user,
    default => $postdeploy_user,
  }

  $bool_run_checks = any2bool($run_checks)
  $bool_skip_predeploy = any2bool($skip_predeploy)
  $bool_auto_deploy = any2bool($auto_deploy)

### CREATE PROJECT
    puppi::project { $name:
      enable => $enable ,
    }


### INIT SEQUENCE
  if ($init_source != '') {
    puppi::initialize { "${name}-Deploy_Files":
      priority  => '40' ,
      command   => 'get_file.sh' ,
      arguments => "-s ${init_source} -d ${deploy_root}" ,
      user      => $user ,
      project   => $name ,
      enable    => $enable ,
    }
  }


### DEPLOY SEQUENCE
  if ($bool_run_checks == true) {
    puppi::deploy { "${name}-Run_PRE-Checks":
      priority  => '10' ,
      command   => 'check_project.sh' ,
      arguments => $name ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($bool_skip_predeploy == false) {
    puppi::deploy { "${name}-Sync_Files":
      priority  => '20' ,
      command   => 'get_file.sh' ,
      arguments => "-s ${source} -t dir" ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($firewall_src_ip != '') {
    puppi::deploy { "${name}-Load_Balancer_Block":
      priority  => '25' ,
      command   => 'firewall.sh' ,
      arguments => "${firewall_src_ip} ${firewall_dst_port} on ${firewall_delay}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

    puppi::deploy { "${name}-Backup_existing_Files":
      priority  => '30' ,
      command   => 'archive.sh' ,
      arguments => "-b ${deploy_root} -o '${backup_rsync_options}' -n ${backup_retention}" ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }

  if ($disable_services != '') {
    puppi::deploy { "${name}-Disable_extra_services":
      priority  => '36' ,
      command   => 'service.sh' ,
      arguments => "stop ${disable_services}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($init_script != '') {
    puppi::deploy { "${name}-Service_stop":
      priority  => '38' ,
      command   => 'service.sh' ,
      arguments => "stop ${init_script}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($predeploy_customcommand != '') {
    puppi::deploy { "${name}-Run_Custom_PreDeploy_Script":
      priority  => $predeploy_priority ,
      command   => 'execute.sh' ,
      arguments => $predeploy_customcommand ,
      user      => $predeploy_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  # Here is done the deploy on $deploy_root
  if ($bool_skip_predeploy == false) {
    puppi::deploy { "${name}-Deploy":
      priority  => '40' ,
      command   => 'deploy.sh' ,
      arguments => $deploy_root ,
      user      => $user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($bool_skip_predeploy == true) {
    puppi::deploy { "${name}-Deploy":
      priority  => '40' ,
      command   => 'get_file.sh' ,
      arguments => "-s ${source} -d ${deploy_root}" ,
      user      => $user ,
      project   => $name ,
      enable    => $enable ,
    }
  }
  # End deploy

  if ($postdeploy_customcommand != '') {
    puppi::deploy { "${name}-Run_Custom_PostDeploy_Script":
      priority  => $postdeploy_priority ,
      command   => 'execute.sh' ,
      arguments => $postdeploy_customcommand ,
      user      => $postdeploy_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($init_script != '') {
    puppi::deploy { "${name}-Service_start":
      priority  => '42' ,
      command   => 'service.sh' ,
      arguments => "start ${init_script}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($disable_services != '') {
    puppi::deploy { "${name}-Enable_extra_services":
      priority  => '44' ,
      command   => 'service.sh' ,
      arguments => "start ${disable_services}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($firewall_src_ip != '') {
    puppi::deploy { "${name}-Load_Balancer_Unblock":
      priority  => '46' ,
      command   => 'firewall.sh' ,
      arguments => "${firewall_src_ip} ${firewall_dst_port} off 0" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($bool_run_checks == true) {
    puppi::deploy { "${name}-Run_POST-Checks":
      priority  => '80' ,
      command   => 'check_project.sh' ,
      arguments => $name ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }


### ROLLBACK SEQUENCE

  if ($firewall_src_ip != '') {
    puppi::rollback { "${name}-Load_Balancer_Block":
      priority  => '25' ,
      command   => 'firewall.sh' ,
      arguments => "${firewall_src_ip} ${firewall_dst_port} on ${firewall_delay}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($disable_services != '') {
    puppi::rollback { "${name}-Disable_extra_services":
      priority  => '37' ,
      command   => 'service.sh' ,
      arguments => "stop ${disable_services}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($init_script != '') {
    puppi::rollback { "${name}-Service_stop":
      priority  => '38' ,
      command   => 'service.sh' ,
      arguments => "stop ${init_script}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($predeploy_customcommand != '') {
    puppi::rollback { "${name}-Run_Custom_PreDeploy_Script":
      priority  => $predeploy_priority ,
      command   => 'execute.sh' ,
      arguments => $predeploy_customcommand ,
      user      => $predeploy_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

    puppi::rollback { "${name}-Recover_Files_To_Deploy":
      priority  => '40' ,
      command   => 'archive.sh' ,
      arguments => "-r ${deploy_root} -o '${backup_rsync_options}'" ,
      user      => $user ,
      project   => $name ,
      enable    => $enable ,
    }

  if ($postdeploy_customcommand != '') {
    puppi::rollback { "${name}-Run_Custom_PostDeploy_Script":
      priority  => $postdeploy_priority ,
      command   => 'execute.sh' ,
      arguments => $postdeploy_customcommand ,
      user      => $postdeploy_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($init_script != '') {
    puppi::rollback { "${name}-Service_start":
      priority  => '42' ,
      command   => 'service.sh' ,
      arguments => "start ${init_script}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($disable_services != '') {
    puppi::rollback { "${name}-Enable_extra_services":
      priority  => '44' ,
      command   => 'service.sh' ,
      arguments => "start ${disable_services}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($firewall_src_ip != '') {
    puppi::rollback { "${name}-Load_Balancer_Unblock":
      priority  => '46' ,
      command   => 'firewall.sh' ,
      arguments => "${firewall_src_ip} ${firewall_dst_port} off 0" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($bool_run_checks == true) {
    puppi::rollback { "${name}-Run_POST-Checks":
      priority  => '80' ,
      command   => 'check_project.sh' ,
      arguments => $name ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }


### REPORTING

  if ($report_email != '') {
    puppi::report { "${name}-Mail_Notification":
      priority  => '20' ,
      command   => 'report_mail.sh' ,
      arguments => $report_email ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

### AUTO DEPLOY DURING PUPPET RUN
  if ($bool_auto_deploy == true) {
    puppi::run { $name: }
  }

}
# = Define puppi::project::files
#
# This is a sample define to build a puppi project for the deploy of
# one or more files based on a provided list containing, one per line,
# the full path of the files to deploy.
# The place (url) from where to get the files is defined by the
# $source_baseurl variable.
# You can strip out some beginning chars from each line with the
# (optional) $files_prefix variable.
# Files are then copied to the $deploy_root you define.
#
# Many different variables are optional in order to adapt the define
# to different cases and needs, if you still need to customize it,
# you can clone this puppi::project into another file and change the
# define name.
#
# == Variables:
#
# [*source*]
#   The full URL of the main file to retrieve.
#   Format should be in URI standard (http:// file:// ssh:// rsync://).
#
# [*deploy_root*]
#   The destination directory where the retrieved file(s) are deployed.
#
# [*source_baseurl*]
#   The full URL, in URI standard format, to prepend to the entries i
#   the files list in order to retrieve the relative files.
#
# [*init_source*]
#   (Optional) - The full URL to be used to retrieve, for the first time,
#   the project files. They are copied directly to the $deploy_root
#   Format should be in URI standard (http:// file:// ssh:// svn://).
#
# [*prefix*]
#   (Optional) - The prefix that might be present in the filelist to
#   define custom  metadata
#
# [*files_prefix*]
#   (Optional) The prefix to remove from the list entries in order to
#   determine the files path on the deploy_root
#   We suggest to place in the files list just the deploy_root relative
#   paths of the files, and in this case the $files_prefix is null
#
# [*user*]
#   (Optional) - The user to be used for deploy operations.
#
# [*predeploy_customcommand*]
#   (Optional) -  Full path with arguments of an eventual custom command to
#   execute before the deploy. The command is executed as $predeploy_user.
#
# [*predeploy_user*]
#   (Optional) - The user to be used to execute the $predeploy_customcommand.
#   By default is the same of $user.
#
# [*predeploy_priority*]
#   (Optional) - The priority (execution sequence number) that defines when,
#   during the deploy procedure, the $predeploy_customcommand is executed
#   Default: 39 (immediately before the copy of files on the deploy root).
#
# [*postdeploy_customcommand*]
#   (Optional) -  Full path with arguments of an eventual custom command to
#   execute after the deploy. The command is executed as $postdeploy_user.
#
# [*postdeploy_user*]
#   (Optional) - The user to be used to execute the $postdeploy_customcommand.
#   By default is the same of $user.
#
# [*postdeploy_priority*]
#   (Optional) - The priority (execution sequence number) that defines when,
#   during the deploy procedure, the $postdeploy_customcommand is executed
#   Default: 41 (immediately after the copy of files on the deploy root).
#
# [*init_script*]
#   (Optional - Obsolete) - The name (ex: tomcat) of the init script of your
#   Application server. If you define it, the AS is stopped and then started
#   during deploy. This option is deprecated, you can use $disable_services
#   for the same functionality
#
# [*disable_services*]
#   (Optional) - The names (space separated) of the services you might want to
#   stop during deploy. By default is blank. Example: "apache puppet monit".
#
# [*firewall_src_ip*]
#   (Optional) - The IP address of a loadbalancer you might want to block out
#   during a deploy.
#
# [*firewall_dst_port*]
#   (Optional) - The local port to block from the loadbalancer during deploy
#   (Default all).
#
# [*firewall_delay*]
#   (Optional) - A delay time in seconds to wait after the block of
#   $firewall_src_ip. Should be at least as long as the loadbalancer check
#   interval for the services stopped during deploy (Default: 1).
#
# [*report_email*]
#   (Optional) - The (space separated) email(s) to notify of deploy/rollback
#   operations. If none is specified, no email is sent.
#
# [*backup_rsync_options*]
#   (Optional) - The extra options to pass to rsync for backup operations. Use
#   it, for example, to exclude directories that you don't want to archive.
#   IE: "--exclude .snapshot --exclude cache --exclude www/cache".
#
# [*backup_retention*]
#   (Optional) - Number of backup archives to keep. (Default 5).
#   Lower the default value if your backups are too large and may fill up the
#   filesystem.
#
# [*run_checks*]
#   (Optional) - If you want to run local puppi checks before and after the
#   deploy procedure. Default: "true".
#
# [*auto_deploy*]
#   (Optional) - If you want to automatically run this puppi deploy when
#   Puppet runs. Default: 'false'
#
define puppi::project::files (
  $source,
  $source_baseurl,
  $deploy_root,
  $init_source              = '',
  $files_prefix             = '',
  $prefix                   = '',
  $user                     = 'root',
  $predeploy_customcommand  = '',
  $predeploy_user           = '',
  $predeploy_priority       = '39',
  $postdeploy_customcommand = '',
  $postdeploy_user          = '',
  $postdeploy_priority      = '41',
  $init_script              = '',
  $disable_services         = '',
  $firewall_src_ip          = '',
  $firewall_dst_port        = '0',
  $firewall_delay           = '1',
  $report_email             = '',
  $backup_rsync_options     = '--exclude .snapshot',
  $backup_retention         = '5',
  $run_checks               = true,
  $auto_deploy              = false,
  $enable                   = true ) {

  require puppi
  require puppi::params

  # Set default values
  $predeploy_real_user = $predeploy_user ? {
    ''      => $user,
    default => $predeploy_user,
  }

  $postdeploy_real_user = $postdeploy_user ? {
    ''      => $user,
    default => $postdeploy_user,
  }

  $bool_run_checks = any2bool($run_checks)
  $bool_auto_deploy = any2bool($auto_deploy)

### CREATE PROJECT
    puppi::project { $name:
      enable => $enable ,
    }


### INIT SEQUENCE
  if ($init_source != '') {
    puppi::initialize { "${name}-Deploy_Files":
      priority  => '40' ,
      command   => 'get_file.sh' ,
      arguments => "-s ${init_source} -d ${deploy_root}" ,
      user      => $user ,
      project   => $name ,
      enable    => $enable ,
    }
  }


### DEPLOY SEQUENCE
  if ($bool_run_checks == true) {
    puppi::deploy { "${name}-Run_PRE-Checks":
      priority  => '10' ,
      command   => 'check_project.sh' ,
      arguments => $name ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }

    puppi::deploy { "${name}-Retrieve_File_List":
      priority  => '20' ,
      command   => 'get_file.sh' ,
      arguments => "-s ${source} -t list" ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }

    $args_prefix = $prefix ? {
      ''      => '',
      default => "-m ${prefix}",
    }

    puppi::deploy { "${name}-Extract_File_Metadata":
      priority  => '22' ,
      command   => 'get_metadata.sh' ,
      arguments => $args_prefix,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }

    puppi::deploy { "${name}-Clean_File_List":
      priority  => '24' ,
      command   => 'clean_filelist.sh' ,
      arguments => $files_prefix ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }

    puppi::deploy { "${name}-Retrieve_Files":
      priority  => '25' ,
      command   => 'get_filesfromlist.sh' ,
      arguments => $source_baseurl ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }

  if ($firewall_src_ip != '') {
    puppi::deploy { "${name}-Load_Balancer_Block":
      priority  => '25' ,
      command   => 'firewall.sh' ,
      arguments => "${firewall_src_ip} ${firewall_dst_port} on ${firewall_delay}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

    puppi::deploy { "${name}-Backup_existing_Files":
      priority  => '30' ,
      command   => 'archive.sh' ,
      arguments => "-b ${deploy_root} -o '${backup_rsync_options}' -n ${backup_retention}" ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }

  if ($disable_services != '') {
    puppi::deploy { "${name}-Disable_extra_services":
      priority  => '36' ,
      command   => 'service.sh' ,
      arguments => "stop ${disable_services}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($init_script != '') {
    puppi::deploy { "${name}-Service_stop":
      priority  => '38' ,
      command   => 'service.sh' ,
      arguments => "stop ${init_script}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($predeploy_customcommand != '') {
    puppi::deploy { "${name}-Run_Custom_PreDeploy_Script":
      priority  => $predeploy_priority ,
      command   => 'execute.sh' ,
      arguments => $predeploy_customcommand ,
      user      => $predeploy_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  # Here is done the deploy on $deploy_root
    puppi::deploy { "${name}-Deploy":
      priority  => '40' ,
      command   => 'deploy.sh' ,
      arguments => $deploy_root ,
      user      => $user ,
      project   => $name ,
      enable    => $enable ,
    }

  if ($postdeploy_customcommand != '') {
    puppi::deploy { "${name}-Run_Custom_PostDeploy_Script":
      priority  => $postdeploy_priority ,
      command   => 'execute.sh' ,
      arguments => $postdeploy_customcommand ,
      user      => $postdeploy_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($init_script != '') {
    puppi::deploy { "${name}-Service_start":
      priority  => '42' ,
      command   => 'service.sh' ,
      arguments => "start ${init_script}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($disable_services != '') {
    puppi::deploy { "${name}-Enable_extra_services":
      priority  => '44' ,
      command   => 'service.sh' ,
      arguments => "start ${disable_services}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($firewall_src_ip != '') {
    puppi::deploy { "${name}-Load_Balancer_Unblock":
      priority  => '46' ,
      command   => 'firewall.sh' ,
      arguments => "${firewall_src_ip} ${firewall_dst_port} off 0" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($bool_run_checks == true) {
    puppi::deploy { "${name}-Run_POST-Checks":
      priority  => '80' ,
      command   => 'check_project.sh' ,
      arguments => $name ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }


### ROLLBACK SEQUENCE

  if ($firewall_src_ip != '') {
    puppi::rollback { "${name}-Load_Balancer_Block":
      priority  => '25' ,
      command   => 'firewall.sh' ,
      arguments => "${firewall_src_ip} ${firewall_dst_port} on ${firewall_delay}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($disable_services != '') {
    puppi::rollback { "${name}-Disable_extra_services":
      priority  => '36' ,
      command   => 'service.sh' ,
      arguments => "stop ${disable_services}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($init_script != '') {
    puppi::rollback { "${name}-Service_stop":
      priority  => '38' ,
      command   => 'service.sh' ,
      arguments => "stop ${init_script}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($predeploy_customcommand != '') {
    puppi::rollback { "${name}-Run_Custom_PreDeploy_Script":
      priority  => $predeploy_priority ,
      command   => 'execute.sh' ,
      arguments => $predeploy_customcommand ,
      user      => $predeploy_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

    puppi::rollback { "${name}-Recover_Files_To_Deploy":
      priority  => '40' ,
      command   => 'archive.sh' ,
      arguments => "-r ${deploy_root} -o '${backup_rsync_options}'" ,
      user      => $user ,
      project   => $name ,
      enable    => $enable ,
    }

  if ($postdeploy_customcommand != '') {
    puppi::rollback { "${name}-Run_Custom_PostDeploy_Script":
      priority  => $postdeploy_priority ,
      command   => 'execute.sh' ,
      arguments => $postdeploy_customcommand ,
      user      => $postdeploy_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($init_script != '') {
    puppi::rollback { "${name}-Service_start":
      priority  => '42' ,
      command   => 'service.sh' ,
      arguments => "start ${init_script}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($disable_services != '') {
    puppi::rollback { "${name}-Enable_extra_services":
      priority  => '44' ,
      command   => 'service.sh' ,
      arguments => "start ${disable_services}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($firewall_src_ip != '') {
    puppi::rollback { "${name}-Load_Balancer_Unblock":
      priority  => '46' ,
      command   => 'firewall.sh' ,
      arguments => "${firewall_src_ip} ${firewall_dst_port} off 0" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($bool_run_checks == true) {
    puppi::rollback { "${name}-Run_POST-Checks":
      priority  => '80' ,
      command   => 'check_project.sh' ,
      arguments => $name ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }


### REPORTING

  if ($report_email != '') {
    puppi::report { "${name}-Mail_Notification":
      priority  => '20' ,
      command   => 'report_mail.sh' ,
      arguments => $report_email ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

### AUTO DEPLOY DURING PUPPET RUN
  if ($bool_auto_deploy == true) {
    puppi::run { $name: }
  }

}
# == Define puppi::project::git
#
# This is a shortcut define to build a puppi project for the deploy of
# file from a git repo.
# It uses different "core" defines (puppi::project, puppi:deploy (many),
# puppi::rollback (many)) to build a full featured template project for
# automatic deployments.
# If you need to customize it, either change the template defined here or
# build up your own custom ones.
#
# == Variables:
#
# [*source*]
#   The full URL of the git repo to retrieve.
#   Format should be in git friendly standard (http:// git:// ssh:// ..).
#
# [*deploy_root*]
#   The destination directory where the retrieved file(s) are deployed.
#
# [*install_git*]
#   If the git package hs to be installed. Default true.
#   Set to false if you install git via other modules and have resource
#   conflicts.
#
# [*git_subdir*]
#   (Optional) - If you want to copy to the deploy_root only a subdir
#   of the specified git repo, specify here the path of the directory
#   relative to the repo root. Default undefined
#
# [*tag*]
#   (Optional) - A specific tag you may want to deploy. Default undefined
#   You can override the default value via command-line with:
#   puppi deploy myapp -o "tag=release"
#
# [*branch*]
#   (Optional) - A specific branch you may want to deploy. Default: master
#   You can override the default value via command-line with:
#   puppi deploy myapp -o "branch=devel"
#
# [*commit*]
#   (Optional) - A specific commit you may want to use. Default undefined
#   You can override the default value via command-line with:
#   puppi deploy myapp -o "commit=1061cb731bc75a1188b58b889b74ce1505ccb412"
#
# [*keep_gitdata*]
#   (Optional) - Define if you want to keep git metadata directory (.git)
#   in the deploy root. According to this value backup and rollback
#   operations change (with keep_gitdata set to true no real backups are done
#   and operations are made on the git tree, if set to false, file are copied
#   and the $backup_* options used. Default is true
#
# [*verbose*]
#   (Optional) - If you want to see verbose git utput (file names) during
#   the deploy. Default is true.
#
# [*user*]
#   (Optional) - The user to be used for deploy operations.
#   If different from root (default) it must have write permissions on
#   the $deploy_root dir.
#
# [*predeploy_customcommand*]
#   (Optional) -  Full path with arguments of an eventual custom command to
#   execute before the deploy. The command is executed as $predeploy_user.
#
# [*predeploy_user*]
#   (Optional) - The user to be used to execute the $predeploy_customcommand.
#   By default is the same of $user.
#
# [*predeploy_priority*]
#   (Optional) - The priority (execution sequence number) that defines when,
#   during the deploy procedure, the $predeploy_customcommand is executed
#   Default: 39 (immediately before the copy of files on the deploy root).
#
# [*postdeploy_customcommand*]
#   (Optional) -  Full path with arguments of an eventual custom command to
#   execute after the deploy. The command is executed as $postdeploy_user.
#
# [*postdeploy_user*]
#   (Optional) - The user to be used to execute the $postdeploy_customcommand.
#   By default is the same of $user.
#
# [*postdeploy_priority*]
#   (Optional) - The priority (execution sequence number) that defines when,
#   during the deploy procedure, the $postdeploy_customcommand is executed
#   Default: 41 (immediately after the copy of files on the deploy root).
#
# [*disable_services*]
#   (Optional) - The names (space separated) of the services you might want to
#   stop during deploy. By default is blank. Example: "apache puppet monit".
#
# [*firewall_src_ip*]
#   (Optional) - The IP address of a loadbalancer you might want to block out
#   during a deploy.
#
# [*firewall_dst_port*]
#   (Optional) - The local port to block from the loadbalancer during deploy
#   (Default all).
#
# [*firewall_delay*]
#   (Optional) - A delay time in seconds to wait after the block of
#   $firewall_src_ip. Should be at least as long as the loadbalancer check
#   interval for the services stopped during deploy (Default: 1).
#
# [*report_email*]
#   (Optional) - The (space separated) email(s) to notify of deploy/rollback
#   operations. If none is specified, no email is sent.
#
# [*backup_rsync_options*]
#   (Optional) - The extra options to pass to rsync for backup operations. Use
#   it, for example, to exclude directories that you don't want to archive.
#   IE: "--exclude .snapshot --exclude cache --exclude www/cache".
#   This option is used when $keep_gitmeta is set to false
#
# [*backup_retention*]
#   (Optional) - Number of backup archives to keep. (Default 5).
#   Lower the default value if your backups are too large and may fill up the
#   filesystem.
#   This option is used when $keep_gitmeta is set to false
#
# [*run_checks*]
#   (Optional) - If you want to run local puppi checks before and after the
#   deploy procedure. Default: "true".
#
# [*auto_deploy*]
#   (Optional) - If you want to automatically run this puppi deploy when
#   Puppet runs. Default: 'false'
#
define puppi::project::git (
  $source,
  $deploy_root,
  $install_git              = true,
  $git_subdir               = 'undefined',
  $tag                      = 'undefined',
  $branch                   = 'master',
  $commit                   = 'undefined',
  $keep_gitdata             = true,
  $verbose                  = true,
  $user                     = 'root',
  $predeploy_customcommand  = '',
  $predeploy_user           = '',
  $predeploy_priority       = '39',
  $postdeploy_customcommand = '',
  $postdeploy_user          = '',
  $postdeploy_priority      = '41',
  $disable_services         = '',
  $firewall_src_ip          = '',
  $firewall_dst_port        = '0',
  $firewall_delay           = '1',
  $report_email             = '',
  $backup_rsync_options     = '--exclude .snapshot',
  $backup_retention         = '5',
  $run_checks               = true,
  $auto_deploy              = false,
  $enable                   = true ) {

  require puppi
  require puppi::params

  # Set default values
  $predeploy_real_user = $predeploy_user ? {
    ''      => $user,
    default => $predeploy_user,
  }

  $postdeploy_real_user = $postdeploy_user ? {
    ''      => $user,
    default => $postdeploy_user,
  }

  $bool_install_git = any2bool($install_git)
  $bool_keep_gitdata = any2bool($keep_gitdata)
  $bool_verbose = any2bool($verbose)
  $bool_run_checks = any2bool($run_checks)
  $bool_auto_deploy = any2bool($auto_deploy)

### INSTALL GIT
  if ($bool_install_git == true) {
    if ! defined(Package['git']) { package { 'git': ensure => installed } }
  }

### CREATE PROJECT
    puppi::project { $name:
      enable => $enable ,
    }


### DEPLOY SEQUENCE
  if ($bool_run_checks == true) {
    puppi::deploy { "${name}-Run_PRE-Checks":
      priority  => '10' ,
      command   => 'check_project.sh' ,
      arguments => $name ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($firewall_src_ip != '') {
    puppi::deploy { "${name}-Load_Balancer_Block":
      priority  => '25' ,
      command   => 'firewall.sh' ,
      arguments => "${firewall_src_ip} ${firewall_dst_port} on ${firewall_delay}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($bool_keep_gitdata == true) {
    puppi::deploy { "${name}-Backup_existing_data":
      priority  => '30' ,
      command   => 'archive.sh' ,
      arguments => "-b ${deploy_root} -o '${backup_rsync_options}' -n ${backup_retention}" ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($disable_services != '') {
    puppi::deploy { "${name}-Disable_extra_services":
      priority  => '36' ,
      command   => 'service.sh' ,
      arguments => "stop ${disable_services}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($predeploy_customcommand != '') {
    puppi::deploy { "${name}-Run_Custom_PreDeploy_Script":
      priority  => $predeploy_priority ,
      command   => 'execute.sh' ,
      arguments => $predeploy_customcommand ,
      user      => $predeploy_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

    # Here is done the deploy on $deploy_root
    puppi::deploy { "${name}-Deploy_Files":
      priority  => '40' ,
      command   => 'git.sh' ,
      arguments => "-a deploy -s ${source} -d ${deploy_root} -u ${user} -gs ${git_subdir} -t ${tag} -b ${branch} -c ${commit} -v ${bool_verbose} -k ${bool_keep_gitdata}" ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }

  if ($postdeploy_customcommand != '') {
    puppi::deploy { "${name}-Run_Custom_PostDeploy_Script":
      priority  => $postdeploy_priority ,
      command   => 'execute.sh' ,
      arguments => $postdeploy_customcommand ,
      user      => $postdeploy_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($disable_services != '') {
    puppi::deploy { "${name}-Enable_extra_services":
      priority  => '44' ,
      command   => 'service.sh' ,
      arguments => "start ${disable_services}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($firewall_src_ip != '') {
    puppi::deploy { "${name}-Load_Balancer_Unblock":
      priority  => '46' ,
      command   => 'firewall.sh' ,
      arguments => "${firewall_src_ip} ${firewall_dst_port} off 0" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($bool_run_checks == true) {
    puppi::deploy { "${name}-Run_POST-Checks":
      priority  => '80' ,
      command   => 'check_project.sh' ,
      arguments => $name ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }


### ROLLBACK PROCEDURE

  if ($firewall_src_ip != '') {
    puppi::rollback { "${name}-Load_Balancer_Block":
      priority  => '25' ,
      command   => 'firewall.sh' ,
      arguments => "${firewall_src_ip} ${firewall_dst_port} on ${firewall_delay}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($disable_services != '') {
    puppi::rollback { "${name}-Disable_extra_services":
      priority  => '37' ,
      command   => 'service.sh' ,
      arguments => "stop ${disable_services}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($predeploy_customcommand != '') {
    puppi::rollback { "${name}-Run_Custom_PreDeploy_Script":
      priority  => $predeploy_priority ,
      command   => 'execute.sh' ,
      arguments => $predeploy_customcommand ,
      user      => $predeploy_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($bool_keep_gitdata == true) {
    puppi::rollback { "${name}-Recover_Files_To_Deploy":
      priority  => '40' ,
      command   => 'archive.sh' ,
      arguments => "-r ${deploy_root} -o '${backup_rsync_options}'" ,
      user      => $user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($bool_keep_gitdata != true) {
    puppi::rollback { "${name}-Rollback_Files":
      priority  => '40' ,
      command   => 'git.sh' ,
      arguments => "-a rollback -s ${source} -d ${deploy_root} -gs ${git_subdir} -t ${tag} -b ${branch} -c ${commit} -v ${bool_verbose} -k ${bool_keep_gitdata}" ,
      user      => $user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($postdeploy_customcommand != '') {
    puppi::rollback { "${name}-Run_Custom_PostDeploy_Script":
      priority  => $postdeploy_priority ,
      command   => 'execute.sh' ,
      arguments => $postdeploy_customcommand ,
      user      => $postdeploy_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($disable_services != '') {
    puppi::rollback { "${name}-Enable_extra_services":
      priority  => '44' ,
      command   => 'service.sh' ,
      arguments => "start ${disable_services}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($firewall_src_ip != '') {
    puppi::rollback { "${name}-Load_Balancer_Unblock":
      priority  => '46' ,
      command   => 'firewall.sh' ,
      arguments => "${firewall_src_ip} ${firewall_dst_port} off 0" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($bool_run_checks == true) {
    puppi::rollback { "${name}-Run_POST-Checks":
      priority  => '80' ,
      command   => 'check_project.sh' ,
      arguments => $name ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }


### REPORTING

  if ($report_email != '') {
    puppi::report { "${name}-Mail_Notification":
      priority  => '20' ,
      command   => 'report_mail.sh' ,
      arguments => $report_email ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

### AUTO DEPLOY DURING PUPPET RUN
  if ($bool_auto_deploy == true) {
    puppi::run { $name: }
  }

}
# = Define puppi::project::maven
#
# This is a shortcut define to build a puppi project for the
# deploy of war and tar files generated via Maven and published on
# a repository like Sonar.
#
# It uses different "core" defines (puppi::project, puppi:deploy (many),
# puppi::rollback (many)) to build a full featured template project for
# automatic deployments.
# If you need to customize it, either change the template defined here or
# build up your own custom ones.
#
# == Variables:
#
# [*source*]
#   The full URL of the maven-metadata.xml file to retrieve.
#   Format should be in URI standard (http:// file:// ssh:// rsync://).
#
# [*http_password*]
#   The http_password to use for authentication to the source in case of http.
#
# [*http_user*]
#   The http_user to use for authentication to the source in case of http.
#
# [*artifact_type*]
#   The artifact_type to parse the maven-metadata.xml. Either "release", "latest" or
#   a specific version (e.g. "2.5.0")
#   Default is "release". With artifactory, don't use the
#   "Maven Snapshot Version Behavior" "unique" for your repository.
#
# [*deploy_root*]
#   The destination directory where file(s) are deployed.
#
# [*user*]
#   (Optional) - The user to be used for deploy operations.
#
# [*war_suffix*]
#   (Optional) - The suffix (Maven qualifier) that might be appended to the war
#
# [*zip_root*]
#   (Optional) - The destination directory where the zip is unpacked
#
# [*zip_user*]
#   (Optional) - The user to be used for deploy operations of the zip
#
# [*zip_suffix*]
#   (Optional) - The suffix (Maven qualifier) that might be appended to the zip
#
# [*jar_root*]
#   (Optional) - The destination directory where the jar is copied.
#   If set a jar file is searched in Maven
#
# [*jar_user*]
#   (Optional) - The user to be used for deploy operations of the jar
#   (owner of the files deployed in $jar_root)
#
# [*jar_suffix*]
#   (Optional) - The suffix (Maven qualifier) that might be appended to the jar
#
# [*document_root*]
#   (Optional) - The destination directory where the eventual tarball generated
#   via Maven containing static files ("src tar") is unpacked
#
# [*document_suffix*]
#   (Optional) - The suffix (Maven qualifier) that might be appended to the
#   static files tarballs ("src tar")
#
# [*document_init_source*]
#   (Optional) - The full URL to be used to retrieve, for the first time, the
#    project files present in the source tarball. They are copied to the
#    $document_root. Format should be in URI standard (http:// file:// ...)
#
# [*document_user*]
#   (Optional) - The user to be used for deploy operations of the tarball
#   (owner of the files in $document_root)
#
# [*config_root*]
#   (Optional) - The destination directory where the cfg tar is unpacked
#
# [*config_suffix*]
#   (Optional) - The suffix (Maven qualifier) that might be appended to
#   configuration tarballs ("cfg tar")
#
# [*config_init_source*]
#   (Optional) - The full URL to be used to retrieve, for the first time, the
#   project files present in the cfg tar. They are copied to the $config_root.
#   Format should be in URI standard (http:// file:// ssh:// svn://)
#
# [*config_user*]
#   (Optional) - The user to be used for deploy operations of cfg tar
#   (owner of the files in $config_root)
#
# [*predeploy_customcommand*]
#   (Optional) -  Full path with arguments of an eventual custom command to
#   execute before the deploy. The command is executed as $predeploy_user.
#
# [*predeploy_user*]
#   (Optional) - The user to be used to execute the $predeploy_customcommand.
#   By default is the same of $user.
#
# [*predeploy_priority*]
#   (Optional) - The priority (execution sequence number) that defines when,
#   during the deploy procedure, the $predeploy_customcommand is executed
#   Default: 39 (immediately before the copy of files on the deploy root).
#
# [*postdeploy_customcommand*]
#   (Optional) -  Full path with arguments of an eventual custom command to
#   execute after the deploy. The command is executed as $postdeploy_user.
#
# [*postdeploy_user*]
#   (Optional) - The user to be used to execute the $postdeploy_customcommand.
#   By default is the same of $user.
#
# [*postdeploy_priority*]
#   (Optional) - The priority (execution sequence number) that defines when,
#   during the deploy procedure, the $postdeploy_customcommand is executed
#   Default: 41 (immediately after the copy of files on the deploy root).
#
# [*init_script*]
#   (Optional - Obsolete) - The name (ex: tomcat) of the init script of your
#   Application server. If you define it, the AS is stopped and then started
#   during deploy. This option is deprecated, you can use $disable_services
#   for the same functionality
#
# [*disable_services*]
#   (Optional) - The names (space separated) of the services you might want to
#   stop during deploy. By default is blank. Example: "apache puppet monit".
#
# [*firewall_src_ip*]
#   (Optional) - The IP address of a loadbalancer you might want to block out
#   during a deploy.
#
# [*firewall_dst_port*]
#   (Optional) - The local port to block from the loadbalancer during deploy
#   (Default all).
#
# [*firewall_delay*]
#   (Optional) - A delay time in seconds to wait after the block of
#   $firewall_src_ip. Should be at least as long as the loadbalancer check
#   interval for the services stopped during deploy (Default: 1).
#
# [*report_email*]
#   (Optional) - The (space separated) email(s) to notify of deploy/rollback
#   operations. If none is specified, no email is sent.
#
# [*report_mongo*]
#   (Optional) - A mongourl with optional user:password to report to. Append the
#   database with a slash ("mongodb://user:password@mymongo.mydomain.com/theNameOfDb")
#
# [*backup_rsync_options*]
#   (Optional) - The extra options to pass to rsync for backup operations. Use
#   it, for example, to exclude directories that you don't want to archive.
#   IE: "--exclude .snapshot --exclude cache --exclude www/cache".
#
# [*backup_retention*]
#   (Optional) - Number of backup archives to keep. (Default 5).
#   Lower the default value if your backups are too large and may fill up the
#   filesystem.
#
# [*run_checks*]
#   (Optional) - If you want to run local puppi checks before and after the
#   deploy procedure. Default: "true".
#
# [*always_deploy*]
#   (Optional) - If you always deploy what has been downloaded. Default="yes",
#   if set to "no" a checksum is made between the files previously downloaded
#   and the new files. If they are the same the deploy is not done.
#
# [*check_deploy*]
#   (Optional) - Checks if the war is deployed (Default yes). Set to no if
#   you deploy on Jboss or the deployed dir is different for the war filename
#
# [*auto_deploy*]
#   (Optional) - If you want to automatically run this puppi deploy when
#   Puppet runs. Default: 'false'
#
define puppi::project::maven (
  $source,
  $http_user                = '',
  $http_password            = '',
  $artifact_type            = 'release',
  $deploy_root              = '',
  $user                     = 'root',
  $war_suffix               = 'suffixnotset',
  $zip_root                 = '',
  $zip_user                 = '',
  $zip_suffix               = 'suffixnotset',
  $jar_root                 = '',
  $jar_user                 = '',
  $jar_suffix               = 'suffixnotset',
  $document_root            = '',
  $document_user            = '',
  $document_suffix          = 'suffixnotset',
  $document_init_source     = '',
  $config_root              = '',
  $config_user              = '',
  $config_suffix            = 'suffixnotset',
  $config_init_source       = '',
  $predeploy_customcommand  = '',
  $predeploy_user           = '',
  $predeploy_priority       = '39',
  $postdeploy_customcommand = '',
  $postdeploy_user          = '',
  $postdeploy_priority      = '41',
  $init_script              = '',
  $disable_services         = '',
  $firewall_src_ip          = '',
  $firewall_dst_port        = '0',
  $firewall_delay           = '1',
  $report_email             = '',
  $report_mongo             = '',
  $backup_rsync_options     = '--exclude .snapshot',
  $backup_retention         = '5',
  $run_checks               = true,
  $always_deploy            = true,
  $check_deploy             = true,
  $auto_deploy              = false,
  $enable                   = true ) {

  require puppi
  require puppi::params

  # Set default values
  $predeploy_real_user = $predeploy_user ? {
    ''      => $user,
    default => $predeploy_user,
  }

  $postdeploy_real_user = $postdeploy_user ? {
    ''      => $user,
    default => $postdeploy_user,
  }

  $config_real_user = $config_user ? {
    ''      => $user,
    default => $config_user,
  }

  $document_real_user = $document_user ? {
    ''      => $user,
    default => $document_user,
  }

  $jar_real_user = $jar_user ? {
    ''      => $user,
    default => $jar_user,
  }

  $zip_real_user = $zip_user ? {
    ''      => $user,
    default => $zip_user,
  }

  $real_always_deploy = any2bool($always_deploy) ? {
    false   => 'no',
    true    => 'yes',
  }

  $bool_run_checks = any2bool($run_checks)
  $bool_check_deploy = any2bool($check_deploy)
  $bool_auto_deploy = any2bool($auto_deploy)


### CREATE PROJECT
    puppi::project { $name:
      enable => $enable ,
    }


### INIT SEQUENCE
  if ($document_init_source != '') {
    puppi::initialize { "${name}-Deploy_Files":
      priority  => '40' ,
      command   => 'get_file.sh' ,
      arguments => "-s ${document_init_source} -d ${deploy_root}" ,
      user      => $document_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($config_init_source != '') {
    puppi::initialize { "${name}-Deploy_CFG_Files":
      priority  => '40' ,
      command   => 'get_file.sh' ,
      arguments => "-s ${config_init_source} -d ${deploy_root}" ,
      user      => $config_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

### DEPLOY SEQUENCE
  if ($bool_run_checks == true) {
    puppi::deploy { "${name}-Run_PRE-Checks":
      priority  => '10' ,
      command   => 'check_project.sh' ,
      arguments => $name ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  $metadata_arguments = $http_password ? {
    '' => "-s ${source}/maven-metadata.xml -t maven-metadata -a ${real_always_deploy}",
    default => "-s ${source}/maven-metadata.xml -t maven-metadata -a ${real_always_deploy} -u ${http_user} -p ${http_password}"
  }

  puppi::deploy { "${name}-Get_Maven_Metadata_File":
    priority  => '20' ,
    command   => 'get_file.sh' ,
    arguments => $metadata_arguments,
    user      => 'root' ,
    project   => $name ,
    enable    => $enable ,
  }

  puppi::deploy { "${name}-Extract_Maven_Metadata":
    priority  => '22' ,
    command   => 'get_metadata.sh' ,
    arguments => "-m ${document_suffix} -mc ${config_suffix} -mj ${jar_suffix} -mw ${war_suffix} -mz ${zip_suffix} -at ${artifact_type}" ,
    user      => 'root' ,
    project   => $name ,
    enable    => $enable ,
  }

  # Files retrieval
  if ($deploy_root != '') {
    $war_arguments = $http_password ? {
      '' => "${source} warfile",
      default => "-u ${http_user} -p ${http_password} ${source} warfile"
    }

    puppi::deploy { "${name}-Get_Maven_Files_WAR":
      priority  => '25' ,
      command   => 'get_maven_files.sh' ,
      arguments => $war_arguments,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($jar_root != '') {
    puppi::deploy { "${name}-Get_Maven_Files_JAR":
      priority  => '25' ,
      command   => 'get_maven_files.sh' ,
      arguments => "${source} jarfile" ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($config_root != '') {
    puppi::deploy { "${name}-Get_Maven_Files_Config":
      priority  => '25' ,
      command   => 'get_maven_files.sh' ,
      arguments => "${source} configfile" ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($document_root != '') {
    puppi::deploy { "${name}-Get_Maven_Files_SRC":
      priority  => '25' ,
      command   => 'get_maven_files.sh' ,
      arguments => "${source} srcfile" ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($zip_root != '') {
    $real_arguments = $http_password ? {
      ''      => "${source} zipfile",
      default => "-u ${http_user} -p ${http_password} ${source} zipfile"
    }

    puppi::deploy { "${name}-Get_Maven_Files_ZIP":
      priority  => '25' ,
      command   => 'get_maven_files.sh' ,
      arguments =>  $real_arguments,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($firewall_src_ip != '') {
    puppi::deploy { "${name}-Load_Balancer_Block":
      priority  => '30' ,
      command   => 'firewall.sh' ,
      arguments => "${firewall_src_ip} ${firewall_dst_port} on ${firewall_delay}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  # Existing files backup
  if ($deploy_root != '') {
    puppi::deploy { "${name}-Backup_Existing_WAR":
      priority  => '30' ,
      command   => 'archive.sh' ,
      arguments => "-b ${deploy_root} -t war -s move -m diff -o '${backup_rsync_options}' -n ${backup_retention}" ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($jar_root != '') {
    puppi::deploy { "${name}-Backup_Existing_JAR":
      priority  => '30' ,
      command   => 'archive.sh' ,
      arguments => "-b ${jar_root} -t jar -s move -m diff -o '${backup_rsync_options}' -n ${backup_retention}" ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($config_root != '') {
    puppi::deploy { "${name}-Backup_Existing_ConfigDir":
      priority  => '30' ,
      command   => 'archive.sh' ,
      arguments => "-b ${config_root} -t config -d predeploydir_configfile -o '${backup_rsync_options}' -n ${backup_retention}" ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($document_root != '') {
    puppi::deploy { "${name}-Backup_Existing_DocumentDir":
      priority  => '30' ,
      command   => 'archive.sh' ,
      arguments => "-b ${document_root} -t docroot -d predeploydir_configfile -o '${backup_rsync_options}' -n ${backup_retention}" ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($zip_root != '') {
    puppi::deploy { "${name}-Backup_Existing_ZipDir":
      priority  => '30' ,
      command   => 'archive.sh' ,
      arguments => "-b ${zip_root} -t ziproot -d predeploydir_zipfile -o '${backup_rsync_options}' -n ${backup_retention}" ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($bool_check_deploy == true) and ($deploy_root != '') {
    puppi::deploy { "${name}-Check_undeploy":
      priority  => '31' ,
      command   => 'checkwardir.sh' ,
      arguments => "-a ${deploy_root} -c deploy_warpath" ,
      user      => $user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($disable_services != '') {
    puppi::deploy { "${name}-Disable_extra_services":
      priority  => '36' ,
      command   => 'service.sh' ,
      arguments => "stop ${disable_services}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($init_script != '') {
    puppi::deploy { "${name}-Service_stop":
      priority  => '38' ,
      command   => 'service.sh' ,
      arguments => "stop ${init_script}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($predeploy_customcommand != '') {
    puppi::deploy { "${name}-Run_Custom_PreDeploy_Script":
      priority  => $predeploy_priority ,
      command   => 'execute.sh' ,
      arguments => $predeploy_customcommand ,
      user      => $predeploy_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  # Deploys
  if ($deploy_root != '') {
    puppi::deploy { "${name}-Deploy_Maven_WAR":
      priority  => '40' ,
      command   => 'deploy.sh' ,
      arguments => $deploy_root ,
      user      => $user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($jar_root != '') {
    puppi::deploy { "${name}-Deploy_Maven_JAR":
      priority  => '40' ,
      command   => 'deploy.sh' ,
      arguments => $jar_root ,
      user      => $jar_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($config_root != '') {
    puppi::deploy { "${name}-Deploy_ConfigDir":
      priority  => '40' ,
      command   => 'deploy.sh' ,
      arguments => "${config_root} predeploydir_configfile" ,
      user      => $config_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($document_root != '') {
    puppi::deploy { "${name}-Deploy_DocumentDir":
      priority  => '40' ,
      command   => 'deploy.sh' ,
      arguments => "${document_root} predeploydir_srcfile" ,
      user      => $document_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($zip_root != '') {
    puppi::deploy { "${name}-Deploy_Zip":
      priority  => '40' ,
      command   => 'deploy.sh' ,
      arguments => "${zip_root} predeploydir_zipfile" ,
      user      => $zip_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($postdeploy_customcommand != '') {
    puppi::deploy { "${name}-Run_Custom_PostDeploy_Script":
      priority  => $postdeploy_priority ,
      command   => 'execute.sh' ,
      arguments => $postdeploy_customcommand ,
      user      => $postdeploy_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($init_script != '') {
    puppi::deploy { "${name}-Service_start":
      priority  => '42' ,
      command   => 'service.sh' ,
      arguments => "start ${init_script}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($disable_services != '') {
    puppi::deploy { "${name}-Enable_extra_services":
      priority  => '44' ,
      command   => 'service.sh' ,
      arguments => "start ${disable_services}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($bool_check_deploy == true) and ($deploy_root != '') {
    puppi::deploy { "${name}-Check_deploy":
      priority  => '45' ,
      command   => 'checkwardir.sh' ,
      arguments => "-p ${deploy_root} -c deploy_warpath" ,
      user      => $user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($firewall_src_ip != '') {
    puppi::deploy { "${name}-Load_Balancer_Unblock":
      priority  => '46' ,
      command   => 'firewall.sh' ,
      arguments => "${firewall_src_ip} ${firewall_dst_port} off 0" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($bool_run_checks == true) {
    puppi::deploy { "${name}-Run_POST-Checks":
      priority  => '80' ,
      command   => 'check_project.sh' ,
      arguments => $name ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }


### ROLLBACK PROCEDURE

  if ($firewall_src_ip != '') {
    puppi::rollback { "${name}-Load_Balancer_Block":
      priority  => '25' ,
      command   => 'firewall.sh' ,
      arguments => "${firewall_src_ip} ${firewall_dst_port} on ${firewall_delay}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($disable_services != '') {
    puppi::rollback { "${name}-Disable_extra_services":
      priority  => '37' ,
      command   => 'service.sh' ,
      arguments => "stop ${disable_services}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($init_script != '') {
    puppi::rollback { "${name}-Service_stop":
      priority  => '38' ,
      command   => 'service.sh' ,
      arguments => "stop ${init_script}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($predeploy_customcommand != '') {
    puppi::rollback { "${name}-Run_Custom_PreDeploy_Script":
      priority  => $predeploy_priority ,
      command   => 'execute.sh' ,
      arguments => $predeploy_customcommand ,
      user      => $predeploy_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($deploy_root != '') {
    puppi::rollback { "${name}-Recover_WAR":
      priority  => '40' ,
      command   => 'archive.sh' ,
      arguments => "-r ${deploy_root} -t war -o '${backup_rsync_options}'" ,
      user      => $user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($jar_root != '') {
    puppi::rollback { "${name}-Recover_JAR":
      priority  => '40' ,
      command   => 'archive.sh' ,
      arguments => "-r ${jar_root} -t jar -o '${backup_rsync_options}'" ,
      user      => $jar_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($config_root != '') {
    puppi::rollback { "${name}-Recover_ConfigDir":
      priority  => '40' ,
      command   => 'archive.sh' ,
      arguments => "-r ${config_root} -t config -o '${backup_rsync_options}'" ,
      user      => $config_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($document_root != '') {
    puppi::rollback { "${name}-Recover_DocumentDir":
      priority  => '40' ,
      command   => 'archive.sh' ,
      arguments => "-r ${document_root} -t docroot -o '${backup_rsync_options}'" ,
      user      => $document_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($postdeploy_customcommand != '') {
    puppi::rollback { "${name}-Run_Custom_PostDeploy_Script":
      priority  => $postdeploy_priority ,
      command   => 'execute.sh' ,
      arguments => $postdeploy_customcommand ,
      user      => $postdeploy_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($init_script != '') {
    puppi::rollback { "${name}-Service_start":
      priority  => '42' ,
      command   => 'service.sh' ,
      arguments => "start ${init_script}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($disable_services != '') {
    puppi::rollback { "${name}-Enable_extra_services":
      priority  => '44' ,
      command   => 'service.sh' ,
      arguments => "start ${disable_services}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($bool_check_deploy == true) {
    puppi::rollback { "${name}-Check_deploy":
      priority  => '45' ,
      command   => 'checkwardir.sh' ,
      arguments => "-p ${deploy_root} -c deploy_warpath" ,
      user      => $user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($firewall_src_ip != '') {
    puppi::rollback { "${name}-Load_Balancer_Unblock":
      priority  => '46' ,
      command   => 'firewall.sh' ,
      arguments => "${firewall_src_ip} ${firewall_dst_port} off 0" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($bool_run_checks == true) {
    puppi::rollback { "${name}-Run_POST-Checks":
      priority  => '80' ,
      command   => 'check_project.sh' ,
      arguments => $name ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }


### REPORTING

  if ($report_email != '') {
    puppi::report { "${name}-Mail_Notification":
      priority  => '20' ,
      command   => 'report_mail.sh' ,
      arguments => $report_email ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($report_mongo != '') {
    puppi::report { "${name}-Mongo_Store":
      priority  => '30' ,
      command   => 'report_mongo.sh' ,
      arguments => $report_mongo ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

### AUTO DEPLOY DURING PUPPET RUN
  if ($bool_auto_deploy == true) {
    puppi::run { $name: }
  }

}
# = Define puppi::project::mysql
#
# This is a shortcut define to build a puppi project for the
# management of mysql queries, contained in the .sql file defined
# as $source
#
# == Variables:
#
# [*source*]
#   The full URL of the main sql file to retrieve.
#   Format should be in URI standard (http:// file:// ssh:// rsync://).
#
# [*mysql_database*]
#   (Required) - The Mysql database to work on
#   Default: root
#
# [*mysql_user*]
#   (Optional) - The Mysql user to be used to run the queries
#   Default: root
#
# [*mysql_password*]
#   (Optional) - The password to use for the specified mysql user
#   Default: '' (blank)
#
# [*mysql_host*]
#   (Optional) - The Mysql server. Use ip or hostname
#   Default: localhost
#
# [*init_source*]
#   (Optional) - The full URL to be used to retrieve a sql file to
#   process only for the first time,
#
# [*predeploy_customcommand*]
#   (Optional) -  Full path with arguments of an eventual custom command to
#   execute before the deploy. The command is executed as $predeploy_user.
#
# [*predeploy_user*]
#   (Optional) - The user to be used to execute the $predeploy_customcommand.
#   By default is the same of $user.
#
# [*predeploy_priority*]
#   (Optional) - The priority (execution sequence number) that defines when,
#   during the deploy procedure, the $predeploy_customcommand is executed
#   Default: 39 (immediately before the copy of files on the deploy root).
#
# [*postdeploy_customcommand*]
#   (Optional) -  Full path with arguments of an eventual custom command to
#   execute after the deploy. The command is executed as $postdeploy_user.
#
# [*postdeploy_user*]
#   (Optional) - The user to be used to execute the $postdeploy_customcommand.
#   By default is the same of $user.
#
# [*postdeploy_priority*]
#   (Optional) - The priority (execution sequence number) that defines when,
#   during the deploy procedure, the $postdeploy_customcommand is executed
#   Default: 41 (immediately after the copy of files on the deploy root).
#
# [*disable_services*]
#   (Optional) - The names (space separated) of the services you might want to
#   stop during deploy. By default is blank. Example: "apache puppet monit".
#
# [*firewall_src_ip*]
#   (Optional) - The IP address of a loadbalancer you might want to block out
#   during a deploy.
#
# [*firewall_dst_port*]
#   (Optional) - The local port to block from the loadbalancer during deploy
#   (Default all).
#
# [*firewall_delay*]
#   (Optional) - A delay time in seconds to wait after the block of
#   $firewall_src_ip. Should be at least as long as the loadbalancer check
#   interval for the services stopped during deploy (Default: 1).
#
# [*report_email*]
#   (Optional) - The (space separated) email(s) to notify of deploy/rollback
#   operations. If none is specified, no email is sent.
#
# [*backup*]
#   (Optional) - If and how backups of existing databases are made.
#   Default: true
#
# [*backup_retention*]
#   (Optional) - Number of backup archives to keep. (Default 5).
#   Lower the default value if your backups are too large and may fill up the
#   filesystem.
#
# [*run_checks*]
#   (Optional) - If you want to run local puppi checks before and after the
#   deploy procedure. Default: "true".
#
# [*always_deploy*]
#   (Optional) - If you always deploy what has been downloaded. Default="yes",
#   if set to "no" a checksum is made between the files previously downloaded
#   and the new files. If they are the same the deploy is not done.
#
# [*auto_deploy*]
#   (Optional) - If you want to automatically run this puppi deploy when
#   Puppet runs. Default: 'false'
#
define puppi::project::mysql (
  $source,
  $mysql_database,
  $mysql_user               = 'root',
  $mysql_host               = 'localhost',
  $mysql_password           = '',
  $init_source              = '',
  $predeploy_customcommand  = '',
  $predeploy_user           = '',
  $predeploy_priority       = '39',
  $postdeploy_customcommand = '',
  $postdeploy_user          = '',
  $postdeploy_priority      = '41',
  $disable_services         = '',
  $firewall_src_ip          = '',
  $firewall_dst_port        = '0',
  $firewall_delay           = '1',
  $report_email             = '',
  $backup                   = true,
  $backup_retention         = '5',
  $run_checks               = true,
  $always_deploy            = true,
  $auto_deploy              = false,
  $enable                   = true ) {

  require puppi
  require puppi::params

  # Set default values
  $predeploy_real_user = $predeploy_user ? {
    ''      => 'root',
    default => $predeploy_user,
  }

  $postdeploy_real_user = $postdeploy_user ? {
    ''      => 'root',
    default => $postdeploy_user,
  }

  $init_real_source = $init_source ? {
    ''      => $source,
    default => $init_source,
  }

  $real_always_deploy = any2bool($always_deploy) ? {
    false   => 'no',
    true    => 'yes',
  }

  $bool_run_checks = any2bool($run_checks)
  $bool_backup = any2bool($backup)
  $real_source_type = 'mysql'
  $bool_auto_deploy = any2bool($auto_deploy)

  $source_filename = url_parse($source,'filename')

### CREATE PROJECT
    puppi::project { $name:
      enable => $enable ,
    }


### INIT SEQUENCE
  if ($init_source != '') {
    puppi::initialize { "${name}-Deploy_Files":
      priority  => '40' ,
      command   => 'get_file.sh' ,
      arguments => "-s ${init_source} -t ${real_source_type}" ,
      user      => root ,
      project   => $name ,
      enable    => $enable ,
    }
    puppi::initialize { "${name}-Run_SQL":
      priority  => '42' ,
      command   => 'database.sh' ,
      arguments => "-t mysql -a run -u ${mysql_user} -p '${mysql_password}' -d ${mysql_database} -h ${mysql_host}" ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }


### DEPLOY SEQUENCE
  if ($bool_run_checks == true) {
    puppi::deploy { "${name}-Run_PRE-Checks":
      priority  => '10' ,
      command   => 'check_project.sh' ,
      arguments => $name ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }

    puppi::deploy { "${name}-Retrieve_SQLFile":
      priority  => '20' ,
      command   => 'get_file.sh' ,
      arguments => "-s ${source} -t ${real_source_type} -a ${real_always_deploy}" ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }

  if ($firewall_src_ip != '') {
    puppi::deploy { "${name}-Load_Balancer_Block":
      priority  => '25' ,
      command   => 'firewall.sh' ,
      arguments => "${firewall_src_ip} ${firewall_dst_port} on ${firewall_delay}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($bool_backup == true) {
    puppi::deploy { "${name}-Backup_Database":
      priority  => '30' ,
      command   => 'database.sh' ,
      arguments => "-t mysql -a dump -u ${mysql_user} -p '${mysql_password}' -d ${mysql_database} -h ${mysql_host}" ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($disable_services != '') {
    puppi::deploy { "${name}-Disable_extra_services":
      priority  => '36' ,
      command   => 'service.sh' ,
      arguments => "stop ${disable_services}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($predeploy_customcommand != '') {
    puppi::deploy { "${name}-Run_Custom_PreDeploy_Script":
      priority  => $predeploy_priority ,
      command   => 'execute.sh' ,
      arguments => $predeploy_customcommand ,
      user      => $predeploy_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

    # Here is done the db change
    puppi::deploy { "${name}-Run_SQL":
      priority  => '40' ,
      command   => 'database.sh' ,
      arguments => "-t mysql -a run -u ${mysql_user} -p '${mysql_password}' -d ${mysql_database} -h ${mysql_host}" ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }

  if ($postdeploy_customcommand != '') {
    puppi::deploy { "${name}-Run_Custom_PostDeploy_Script":
      priority  => $postdeploy_priority ,
      command   => 'execute.sh' ,
      arguments => $postdeploy_customcommand ,
      user      => $postdeploy_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($disable_services != '') {
    puppi::deploy { "${name}-Enable_extra_services":
      priority  => '44' ,
      command   => 'service.sh' ,
      arguments => "start ${disable_services}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($firewall_src_ip != '') {
    puppi::deploy { "${name}-Load_Balancer_Unblock":
      priority  => '46' ,
      command   => 'firewall.sh' ,
      arguments => "${firewall_src_ip} ${firewall_dst_port} off 0" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($bool_run_checks == true) {
    puppi::deploy { "${name}-Run_POST-Checks":
      priority  => '80' ,
      command   => 'check_project.sh' ,
      arguments => $name ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }


### ROLLBACK PROCEDURE

  if ($firewall_src_ip != '') {
    puppi::rollback { "${name}-Load_Balancer_Block":
      priority  => '25' ,
      command   => 'firewall.sh' ,
      arguments => "${firewall_src_ip} ${firewall_dst_port} on ${firewall_delay}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($bool_backup == true) {
    puppi::rollback { "${name}-Backup_Database_PreRollback":
      priority  => '30' ,
      command   => 'database.sh' ,
      arguments => "-t mysql -a dump -u ${mysql_user} -p '${mysql_password}' -d ${mysql_database} -h ${mysql_host}" ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($disable_services != '') {
    puppi::rollback { "${name}-Disable_extra_services":
      priority  => '37' ,
      command   => 'service.sh' ,
      arguments => "stop ${disable_services}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($predeploy_customcommand != '') {
    puppi::rollback { "${name}-Run_Custom_PreDeploy_Script":
      priority  => $predeploy_priority ,
      command   => 'execute.sh' ,
      arguments => $predeploy_customcommand ,
      user      => $predeploy_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($bool_backup == true) {
    puppi::rollback { "${name}-Recover_Database":
      priority  => '40' ,
      command   => 'database.sh' ,
      arguments => "-t mysql -a restore -u ${mysql_user} -p '${mysql_password}' -d ${mysql_database} -h ${mysql_host}" ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($postdeploy_customcommand != '') {
    puppi::rollback { "${name}-Run_Custom_PostDeploy_Script":
      priority  => $postdeploy_priority ,
      command   => 'execute.sh' ,
      arguments => $postdeploy_customcommand ,
      user      => $postdeploy_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($disable_services != '') {
    puppi::rollback { "${name}-Enable_extra_services":
      priority  => '44' ,
      command   => 'service.sh' ,
      arguments => "start ${disable_services}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($firewall_src_ip != '') {
    puppi::rollback { "${name}-Load_Balancer_Unblock":
      priority  => '46' ,
      command   => 'firewall.sh' ,
      arguments => "${firewall_src_ip} ${firewall_dst_port} off 0" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($bool_run_checks == true) {
    puppi::rollback { "${name}-Run_POST-Checks":
      priority  => '80' ,
      command   => 'check_project.sh' ,
      arguments => $name ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }


### REPORTING

  if ($report_email != '') {
    puppi::report { "${name}-Mail_Notification":
      priority  => '20' ,
      command   => 'report_mail.sh' ,
      arguments => $report_email ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

### AUTO DEPLOY DURING PUPPET RUN
  if ($bool_auto_deploy == true) {
    puppi::run { $name: }
  }

}
# = Define puppi::project::service
#
# This is a shortcut define to build a case-limit puppi project
# that just manages services and custom commands without deploying
# any file. It doesn't require any parameter but you should at least
# provide one among predeploy_customcommand, postdeploy_customcommand,
# init_script, disable_services to make something useful.
# The rollback option is kept for coherency with the standard puppi
# deploy approach, but actually should not be used since there is no
# data to rollback.
#
# == Variables:
#
# [*user*]
#   (Optional) - The user to be used for deploy operations.
#
# [*predeploy_customcommand*]
#   (Optional) -  Full path with arguments of an eventual custom command to
#   execute before the deploy. The command is executed as $predeploy_user.
#
# [*predeploy_user*]
#   (Optional) - The user to be used to execute the $predeploy_customcommand.
#   By default is the same of $user.
#
# [*predeploy_priority*]
#   (Optional) - The priority (execution sequence number) that defines when,
#   during the deploy procedure, the $predeploy_customcommand is executed
#   Default: 39 (immediately before the copy of files on the deploy root).
#
# [*postdeploy_customcommand*]
#   (Optional) -  Full path with arguments of an eventual custom command to
#   execute after the deploy. The command is executed as $postdeploy_user.
#
# [*postdeploy_user*]
#   (Optional) - The user to be used to execute the $postdeploy_customcommand.
#   By default is the same of $user.
#
# [*postdeploy_priority*]
#   (Optional) - The priority (execution sequence number) that defines when,
#   during the deploy procedure, the $postdeploy_customcommand is executed
#   Default: 41 (immediately after the copy of files on the deploy root).
#
# [*init_script*]
#   (Optional - Obsolete) - The name (ex: tomcat) of the init script of your
#   Application server. If you define it, the AS is stopped and then started
#   during deploy. This option is deprecated, you can use $disable_services
#   for the same functionality
#
# [*disable_services*]
#   (Optional) - The names (space separated) of the services you might want to
#   stop during deploy. By default is blank. Example: "apache puppet monit".
#
# [*firewall_src_ip*]
#   (Optional) - The IP address of a loadbalancer you might want to block out
#   during a deploy.
#
# [*firewall_dst_port*]
#   (Optional) - The local port to block from the loadbalancer during deploy
#   (Default all).
#
# [*firewall_delay*]
#   (Optional) - A delay time in seconds to wait after the block of
#   $firewall_src_ip. Should be at least as long as the loadbalancer check
#   interval for the services stopped during deploy (Default: 1).
#
# [*report_email*]
#   (Optional) - The (space separated) email(s) to notify of deploy/rollback
#   operations. If none is specified, no email is sent.
#
# [*run_checks*]
#   (Optional) - If you want to run local puppi checks before and after the
#   deploy procedure. Default: "true".
#
# [*auto_deploy*]
#   (Optional) - If you want to automatically run this puppi deploy when
#   Puppet runs. Default: 'false'
#
define puppi::project::service (
  $user                     = 'root',
  $predeploy_customcommand  = '',
  $predeploy_user           = '',
  $predeploy_priority       = '39',
  $postdeploy_customcommand = '',
  $postdeploy_user          = '',
  $postdeploy_priority      = '41',
  $init_script              = '',
  $disable_services         = '',
  $firewall_src_ip          = '',
  $firewall_dst_port        = '0',
  $firewall_delay           = '1',
  $report_email             = '',
  $run_checks               = true,
  $auto_deploy              = false,
  $enable                   = true ) {

  require puppi
  require puppi::params

  # Set default values
  $predeploy_real_user = $predeploy_user ? {
    ''      => $user,
    default => $predeploy_user,
  }

  $postdeploy_real_user = $postdeploy_user ? {
    ''      => $user,
    default => $postdeploy_user,
  }

  $bool_run_checks = any2bool($run_checks)
  $bool_auto_deploy = any2bool($auto_deploy)

### CREATE PROJECT
    puppi::project { $name:
      enable => $enable ,
    }


### DEPLOY SEQUENCE
  if ($bool_run_checks == true) {
    puppi::deploy { "${name}-Run_PRE-Checks":
      priority  => '10' ,
      command   => 'check_project.sh' ,
      arguments => $name ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($firewall_src_ip != '') {
    puppi::deploy { "${name}-Load_Balancer_Block":
      priority  => '25' ,
      command   => 'firewall.sh' ,
      arguments => "${firewall_src_ip} ${firewall_dst_port} on ${firewall_delay}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($disable_services != '') {
    puppi::deploy { "${name}-Disable_extra_services":
      priority  => '36' ,
      command   => 'service.sh' ,
      arguments => "stop ${disable_services}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($init_script != '') {
    puppi::deploy { "${name}-Service_stop":
      priority  => '38' ,
      command   => 'service.sh' ,
      arguments => "stop ${init_script}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($predeploy_customcommand != '') {
    puppi::deploy { "${name}-Run_Custom_PreDeploy_Script":
      priority  => $predeploy_priority ,
      command   => 'execute.sh' ,
      arguments => $predeploy_customcommand ,
      user      => $predeploy_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }


  if ($postdeploy_customcommand != '') {
    puppi::deploy { "${name}-Run_Custom_PostDeploy_Script":
      priority  => $postdeploy_priority ,
      command   => 'execute.sh' ,
      arguments => $postdeploy_customcommand ,
      user      => $postdeploy_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($init_script != '') {
    puppi::deploy { "${name}-Service_start":
      priority  => '42' ,
      command   => 'service.sh' ,
      arguments => "start ${init_script}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($disable_services != '') {
    puppi::deploy { "${name}-Enable_extra_services":
      priority  => '44' ,
      command   => 'service.sh' ,
      arguments => "start ${disable_services}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($firewall_src_ip != '') {
    puppi::deploy { "${name}-Load_Balancer_Unblock":
      priority  => '46' ,
      command   => 'firewall.sh' ,
      arguments => "${firewall_src_ip} ${firewall_dst_port} off 0" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($bool_run_checks == true) {
    puppi::deploy { "${name}-Run_POST-Checks":
      priority  => '80' ,
      command   => 'check_project.sh' ,
      arguments => $name ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }


### ROLLBACK PROCEDURE

  if ($firewall_src_ip != '') {
    puppi::rollback { "${name}-Load_Balancer_Block":
      priority  => '25' ,
      command   => 'firewall.sh' ,
      arguments => "${firewall_src_ip} ${firewall_dst_port} on ${firewall_delay}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($disable_services != '') {
    puppi::rollback { "${name}-Disable_extra_services":
      priority  => '37' ,
      command   => 'service.sh' ,
      arguments => "stop ${disable_services}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($init_script != '') {
    puppi::rollback { "${name}-Service_stop":
      priority  => '38' ,
      command   => 'service.sh' ,
      arguments => "stop ${init_script}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($predeploy_customcommand != '') {
    puppi::rollback { "${name}-Run_Custom_PreDeploy_Script":
      priority  => $predeploy_priority ,
      command   => 'execute.sh' ,
      arguments => $predeploy_customcommand ,
      user      => $predeploy_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($postdeploy_customcommand != '') {
    puppi::rollback { "${name}-Run_Custom_PostDeploy_Script":
      priority  => $postdeploy_priority ,
      command   => 'execute.sh' ,
      arguments => $postdeploy_customcommand ,
      user      => $postdeploy_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($init_script != '') {
    puppi::rollback { "${name}-Service_start":
      priority  => '42' ,
      command   => 'service.sh' ,
      arguments => "start ${init_script}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($disable_services != '') {
    puppi::rollback { "${name}-Enable_extra_services":
      priority  => '44' ,
      command   => 'service.sh' ,
      arguments => "start ${disable_services}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($firewall_src_ip != '') {
    puppi::rollback { "${name}-Load_Balancer_Unblock":
      priority  => '46' ,
      command   => 'firewall.sh' ,
      arguments => "${firewall_src_ip} ${firewall_dst_port} off 0" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($bool_run_checks == true) {
    puppi::rollback { "${name}-Run_POST-Checks":
      priority  => '80' ,
      command   => 'check_project.sh' ,
      arguments => $name ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }


### REPORTING

  if ($report_email != '') {
    puppi::report { "${name}-Mail_Notification":
      priority  => '20' ,
      command   => 'report_mail.sh' ,
      arguments => $report_email ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

### AUTO DEPLOY DURING PUPPET RUN
  if ($bool_auto_deploy == true) {
    puppi::run { $name: }
  }

}
# == Define puppi::project::svn
#
# This is a shortcut define to build a puppi project for the deploy of
# file from a svn repo.
# It uses different "core" defines (puppi::project, puppi:deploy (many),
# puppi::rollback (many)) to build a full featured template project for
# automatic deployments.
# If you need to customize it, either change the template defined here or
# build up your own custom ones.
#
# == Variables:
#
# [*source*]
#   The full URL of the svn repo to retrieve.
#   Format should be in svn friendly standard (http:// svn:// ..).
#
# [*svn_user*]
#   Name of the user to access a private svn repo. Optional.
#
# [*svn_password*]
#   Name of the password to access a private svn repo. Optional.
#
# [*deploy_root*]
#   The destination directory where the retrieved file(s) are deployed.
#
# [*install_svn*]
#   If the svn package has to be installed. Default true.
#   Set to false if you install svn via other modules and have resource
#   conflicts.
#
# [*svn_subdir*]
#   (Optional) - If you want to copy to the deploy_root only a subdir
#   of the specified svn repo, specify here the path of the directory
#   relative to the repo root. Default undefined
#
# [*svn_export*]
#   (Optional) - If to use a svn export command instead of checkout
#   Default: false (A checkout is done)
#
# [*tag*]
#   (Optional) - A specific tag you may want to deploy. Default undefined
#   You can override the default value via command-line with:
#   puppi deploy myapp -o "tag=release"
#
# [*branch*]
#   (Optional) - A specific branch you may want to deploy. Default: master
#   You can override the default value via command-line with:
#   puppi deploy myapp -o "branch=devel"
#
# [*commit*]
#   (Optional) - A specific commit you may want to use. Default undefined
#   You can override the default value via command-line with:
#   puppi deploy myapp -o "commit=1061cb731bc75a1188b58b889b74ce1505ccb412"
#
# [*keep_svndata*]
#   (Optional) - Define if you want to keep svn metadata directory (.svn)
#   in the deploy root. According to this value backup and rollback
#   operations change (with keep_svndata set to true no real backups are done
#   and operations are made on the svn tree, if set to false, file are copied
#   and the $backup_* options used. Default is true
#
# [*verbose*]
#   (Optional) - If you want to see verbose svn utput (file names) during
#   the deploy. Default is true.
#
# [*user*]
#   (Optional) - The user to be used for deploy operations.
#   If different from root (default) it must have write permissions on
#   the $deploy_root dir.
#
# [*predeploy_customcommand*]
#   (Optional) -  Full path with arguments of an eventual custom command to
#   execute before the deploy. The command is executed as $predeploy_user.
#
# [*predeploy_user*]
#   (Optional) - The user to be used to execute the $predeploy_customcommand.
#   By default is the same of $user.
#
# [*predeploy_priority*]
#   (Optional) - The priority (execution sequence number) that defines when,
#   during the deploy procedure, the $predeploy_customcommand is executed
#   Default: 39 (immediately before the copy of files on the deploy root).
#
# [*postdeploy_customcommand*]
#   (Optional) -  Full path with arguments of an eventual custom command to
#   execute after the deploy. The command is executed as $postdeploy_user.
#
# [*postdeploy_user*]
#   (Optional) - The user to be used to execute the $postdeploy_customcommand.
#   By default is the same of $user.
#
# [*postdeploy_priority*]
#   (Optional) - The priority (execution sequence number) that defines when,
#   during the deploy procedure, the $postdeploy_customcommand is executed
#   Default: 41 (immediately after the copy of files on the deploy root).
#
# [*disable_services*]
#   (Optional) - The names (space separated) of the services you might want to
#   stop during deploy. By default is blank. Example: "apache puppet monit".
#
# [*firewall_src_ip*]
#   (Optional) - The IP address of a loadbalancer you might want to block out
#   during a deploy.
#
# [*firewall_dst_port*]
#   (Optional) - The local port to block from the loadbalancer during deploy
#   (Default all).
#
# [*firewall_delay*]
#   (Optional) - A delay time in seconds to wait after the block of
#   $firewall_src_ip. Should be at least as long as the loadbalancer check
#   interval for the services stopped during deploy (Default: 1).
#
# [*report_email*]
#   (Optional) - The (space separated) email(s) to notify of deploy/rollback
#   operations. If none is specified, no email is sent.
#
# [*backup_enable*]
#   (Optional, default true) - If the backup of files in the deploy dir
#   is done (before deploy). If set to false, rollback is disabled.
#
# [*backup_rsync_options*]
#   (Optional) - The extra options to pass to rsync for backup operations. Use
#   it, for example, to exclude directories that you don't want to archive.
#   IE: "--exclude .snapshot --exclude cache --exclude www/cache".
#   This option is used when $keep_svnmeta is set to false
#
# [*backup_retention*]
#   (Optional) - Number of backup archives to keep. (Default 5).
#   Lower the default value if your backups are too large and may fill up the
#   filesystem.
#   This option is used when $keep_svnmeta is set to false
#
# [*run_checks*]
#   (Optional) - If you want to run local puppi checks before and after the
#   deploy procedure. Default: "true".
#
# [*auto_deploy*]
#   (Optional) - If you want to automatically run this puppi deploy when
#   Puppet runs. Default: 'false'
#
define puppi::project::svn (
  $source,
  $deploy_root,
  $install_svn              = true,
  $svn_user                 = 'undefined',
  $svn_password             = 'undefined',
  $svn_subdir               = 'undefined',
  $svn_export               = false,
  $tag                      = 'undefined',
  $branch                   = 'master',
  $commit                   = 'undefined',
  $keep_svndata             = true,
  $verbose                  = true,
  $user                     = 'root',
  $predeploy_customcommand  = '',
  $predeploy_user           = '',
  $predeploy_priority       = '39',
  $postdeploy_customcommand = '',
  $postdeploy_user          = '',
  $postdeploy_priority      = '41',
  $disable_services         = '',
  $firewall_src_ip          = '',
  $firewall_dst_port        = '0',
  $firewall_delay           = '1',
  $report_email             = '',
  $backup_enable            = true,
  $backup_rsync_options     = '--exclude .snapshot',
  $backup_retention         = '5',
  $run_checks               = true,
  $auto_deploy              = false,
  $enable                   = true ) {

  require puppi
  require puppi::params

  # Set default values
  $predeploy_real_user = $predeploy_user ? {
    ''      => $user,
    default => $predeploy_user,
  }

  $postdeploy_real_user = $postdeploy_user ? {
    ''      => $user,
    default => $postdeploy_user,
  }

  $bool_install_svn = any2bool($install_svn)
  $bool_svn_export = any2bool($svn_export)
  $bool_keep_svndata = any2bool($keep_svndata)
  $bool_verbose = any2bool($verbose)
  $bool_backup_enable = any2bool($backup_enable)
  $bool_run_checks = any2bool($run_checks)
  $bool_auto_deploy = any2bool($auto_deploy)

### INSTALL GIT
  if ($bool_install_svn == true) {
    if ! defined(Package['subversion']) { package { 'subversion': ensure => installed } }
  }

### CREATE PROJECT
    puppi::project { $name:
      enable => $enable ,
    }


### DEPLOY SEQUENCE
  if ($bool_run_checks == true) {
    puppi::deploy { "${name}-Run_PRE-Checks":
      priority  => '10' ,
      command   => 'check_project.sh' ,
      arguments => $name ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($firewall_src_ip != '') {
    puppi::deploy { "${name}-Load_Balancer_Block":
      priority  => '25' ,
      command   => 'firewall.sh' ,
      arguments => "${firewall_src_ip} ${firewall_dst_port} on ${firewall_delay}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($bool_keep_svndata == true and $bool_backup_enable == true) {
    puppi::deploy { "${name}-Backup_existing_data":
      priority  => '30' ,
      command   => 'archive.sh' ,
      arguments => "-b ${deploy_root} -o '${backup_rsync_options}' -n ${backup_retention}" ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($disable_services != '') {
    puppi::deploy { "${name}-Disable_extra_services":
      priority  => '36' ,
      command   => 'service.sh' ,
      arguments => "stop ${disable_services}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($predeploy_customcommand != '') {
    puppi::deploy { "${name}-Run_Custom_PreDeploy_Script":
      priority  => $predeploy_priority ,
      command   => 'execute.sh' ,
      arguments => $predeploy_customcommand ,
      user      => $predeploy_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

    # Here is done the deploy on $deploy_root
    puppi::deploy { "${name}-Deploy_Files":
      priority  => '40' ,
      command   => 'svn.sh' ,
      arguments => "-a deploy -s ${source} -d ${deploy_root} -u ${user} -gs ${svn_subdir} -su ${svn_user} -sp ${svn_password} -t ${tag} -b ${branch} -c ${commit} -v ${bool_verbose} -k ${bool_keep_svndata} -e ${bool_svn_export}" ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }

  if ($postdeploy_customcommand != '') {
    puppi::deploy { "${name}-Run_Custom_PostDeploy_Script":
      priority  => $postdeploy_priority ,
      command   => 'execute.sh' ,
      arguments => $postdeploy_customcommand ,
      user      => $postdeploy_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($disable_services != '') {
    puppi::deploy { "${name}-Enable_extra_services":
      priority  => '44' ,
      command   => 'service.sh' ,
      arguments => "start ${disable_services}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($firewall_src_ip != '') {
    puppi::deploy { "${name}-Load_Balancer_Unblock":
      priority  => '46' ,
      command   => 'firewall.sh' ,
      arguments => "${firewall_src_ip} ${firewall_dst_port} off 0" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($bool_run_checks == true) {
    puppi::deploy { "${name}-Run_POST-Checks":
      priority  => '80' ,
      command   => 'check_project.sh' ,
      arguments => $name ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }


### ROLLBACK PROCEDURE

  if ($bool_backup_enable == true) {
  if ($firewall_src_ip != '') {
      puppi::rollback { "${name}-Load_Balancer_Block":
        priority  => '25' ,
        command   => 'firewall.sh' ,
        arguments => "${firewall_src_ip} ${firewall_dst_port} on ${firewall_delay}" ,
        user      => 'root',
        project   => $name ,
        enable    => $enable ,
      }
    }

    if ($disable_services != '') {
      puppi::rollback { "${name}-Disable_extra_services":
        priority  => '37' ,
        command   => 'service.sh' ,
        arguments => "stop ${disable_services}" ,
        user      => 'root',
        project   => $name ,
        enable    => $enable ,
      }
    }

    if ($predeploy_customcommand != '') {
      puppi::rollback { "${name}-Run_Custom_PreDeploy_Script":
        priority  => $predeploy_priority ,
        command   => 'execute.sh' ,
        arguments => $predeploy_customcommand ,
        user      => $predeploy_real_user ,
        project   => $name ,
        enable    => $enable ,
      }
    }

    if ($bool_keep_svndata == true) {
      puppi::rollback { "${name}-Recover_Files_To_Deploy":
        priority  => '40' ,
        command   => 'archive.sh' ,
        arguments => "-r ${deploy_root} -o '${backup_rsync_options}'" ,
        user      => $user ,
        project   => $name ,
        enable    => $enable ,
      }
    }

    if ($bool_keep_svndata != true) {
      puppi::rollback { "${name}-Rollback_Files":
        priority  => '40' ,
        command   => 'svn.sh' ,
        arguments => "-a rollback -s ${source} -d ${deploy_root} -gs ${svn_subdir} -t ${tag} -b ${branch} -c ${commit} -v ${bool_verbose} -k ${bool_keep_svndata}" ,
        user      => $user ,
        project   => $name ,
        enable    => $enable ,
      }
    }

    if ($postdeploy_customcommand != '') {
      puppi::rollback { "${name}-Run_Custom_PostDeploy_Script":
        priority  => $postdeploy_priority ,
        command   => 'execute.sh' ,
        arguments => $postdeploy_customcommand ,
        user      => $postdeploy_real_user ,
        project   => $name ,
        enable    => $enable ,
      }
    }

    if ($disable_services != '') {
      puppi::rollback { "${name}-Enable_extra_services":
        priority  => '44' ,
        command   => 'service.sh' ,
        arguments => "start ${disable_services}" ,
        user      => 'root',
        project   => $name ,
        enable    => $enable ,
      }
    }

    if ($firewall_src_ip != '') {
      puppi::rollback { "${name}-Load_Balancer_Unblock":
        priority  => '46' ,
        command   => 'firewall.sh' ,
        arguments => "${firewall_src_ip} ${firewall_dst_port} off 0" ,
        user      => 'root',
        project   => $name ,
        enable    => $enable ,
      }
    }

    if ($bool_run_checks == true) {
      puppi::rollback { "${name}-Run_POST-Checks":
        priority  => '80' ,
        command   => 'check_project.sh' ,
        arguments => $name ,
        user      => 'root' ,
        project   => $name ,
        enable    => $enable ,
      }
    }
  }

### REPORTING

  if ($report_email != '') {
    puppi::report { "${name}-Mail_Notification":
      priority  => '20' ,
      command   => 'report_mail.sh' ,
      arguments => $report_email ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

### AUTO DEPLOY DURING PUPPET RUN
  if ($bool_auto_deploy == true) {
    puppi::run { $name: }
  }
}
# = Define puppi::project::tar
#
# This is a shortcut define to build a puppi project for the
# deploy of a tar.gz file into a deploy root
#
# It uses different "core" defines (puppi::project, puppi:deploy (many),
# puppi::rollback (many)) to build a full featured template project for
# automatic deployments.
# If you need to customize it, either change the template defined here or
# build up your own custom ones.
#
# == Variables:
#
# [*source*]
#   The full URL of the main file to retrieve.
#   Format should be in URI standard (http:// file:// ssh:// rsync://).
#
# [*deploy_root*]
#   The destination directory where the retrieved file(s) are deployed.
#
# [*init_source*]
#   (Optional) - The full URL to be used to retrieve, for the first time,
#   the project files. They are copied directly to the $deploy_root
#   Format should be in URI standard (http:// file:// ssh:// svn://).
#
# [*user*]
#   (Optional) - The user to be used for deploy operations.
#
# [*predeploy_customcommand*]
#   (Optional) -  Full path with arguments of an eventual custom command to
#   execute before the deploy. The command is executed as $predeploy_user.
#
# [*predeploy_user*]
#   (Optional) - The user to be used to execute the $predeploy_customcommand.
#   By default is the same of $user.
#
# [*predeploy_priority*]
#   (Optional) - The priority (execution sequence number) that defines when,
#   during the deploy procedure, the $predeploy_customcommand is executed
#   Default: 39 (immediately before the copy of files on the deploy root).
#
# [*postdeploy_customcommand*]
#   (Optional) -  Full path with arguments of an eventual custom command to
#   execute after the deploy. The command is executed as $postdeploy_user.
#
# [*postdeploy_user*]
#   (Optional) - The user to be used to execute the $postdeploy_customcommand.
#   By default is the same of $user.
#
# [*postdeploy_priority*]
#   (Optional) - The priority (execution sequence number) that defines when,
#   during the deploy procedure, the $postdeploy_customcommand is executed
#   Default: 41 (immediately after the copy of files on the deploy root).
#
# [*init_script*]
#   (Optional - Obsolete) - The name (ex: tomcat) of the init script of your
#   Application server. If you define it, the AS is stopped and then started
#   during deploy. This option is deprecated, you can use $disable_services
#   for the same functionality
#
# [*disable_services*]
#   (Optional) - The names (space separated) of the services you might want to
#   stop during deploy. By default is blank. Example: "apache puppet monit".
#
# [*firewall_src_ip*]
#   (Optional) - The IP address of a loadbalancer you might want to block out
#   during a deploy.
#
# [*firewall_dst_port*]
#   (Optional) - The local port to block from the loadbalancer during deploy
#   (Default all).
#
# [*firewall_delay*]
#   (Optional) - A delay time in seconds to wait after the block of
#   $firewall_src_ip. Should be at least as long as the loadbalancer check
#   interval for the services stopped during deploy (Default: 1).
#
# [*report_email*]
#   (Optional) - The (space separated) email(s) to notify of deploy/rollback
#   operations. If none is specified, no email is sent.
#
# [*clean_deploy*]
#   (Optional, default false) - If during the deploy procedure, all the
#   existing files that are not on the source have to be deleted.
#   (When true, a --delete option is added to the rsync command)
#   Do not set to true if source files are incremental.
#
# [*backup_enable*]
#   (Optional, default true) - If the backup of files in the deploy dir
#   is done (before deploy). If set to false, rollback is disabled.
#
# [*backup_rsync_options*]
#   (Optional) - The extra options to pass to rsync for backup operations. Use
#   it, for example, to exclude directories that you don't want to archive.
#   IE: "--exclude .snapshot --exclude cache --exclude www/cache".
#
# [*backup_retention*]
#   (Optional) - Number of backup archives to keep. (Default 5).
#   Lower the default value if your backups are too large and may fill up the
#   filesystem.
#
# [*run_checks*]
#   (Optional) - If you want to run local puppi checks before and after the
#   deploy procedure. Default: "true".
#
# [*always_deploy*]
#   (Optional) - If you always deploy what has been downloaded. Default="yes",
#   if set to "no" a checksum is made between the files previously downloaded
#   and the new files. If they are the same the deploy is not done.
#
# [*auto_deploy*]
#   (Optional) - If you want to automatically run this puppi deploy when
#   Puppet runs. Default: 'false'
#
define puppi::project::tar (
  $source,
  $deploy_root,
  $init_source              = '',
  $user                     = 'root',
  $predeploy_customcommand  = '',
  $predeploy_user           = '',
  $predeploy_priority       = '39',
  $postdeploy_customcommand = '',
  $postdeploy_user          = '',
  $postdeploy_priority      = '41',
  $init_script              = '',
  $disable_services         = '',
  $firewall_src_ip          = '',
  $firewall_dst_port        = '0',
  $firewall_delay           = '1',
  $report_email             = '',
  $clean_deploy             = false,
  $backup_enable            = true,
  $backup_rsync_options     = '--exclude .snapshot',
  $backup_retention         = '5',
  $run_checks               = true,
  $always_deploy            = true,
  $auto_deploy              = false,
  $verify_ssl               = true,
  $enable                   = true ) {

  require puppi
  require puppi::params

  # Set default values
  $predeploy_real_user = $predeploy_user ? {
    ''      => $user,
    default => $predeploy_user,
  }

  $postdeploy_real_user = $postdeploy_user ? {
    ''      => $user,
    default => $postdeploy_user,
  }

  $init_real_source = $init_source ? {
    ''      => $source,
    default => $init_source,
  }

  $real_always_deploy = any2bool($always_deploy) ? {
    false   => 'no',
    true    => 'yes',
  }

  $bool_clean_deploy = any2bool($clean_deploy)
  $bool_backup_enable = any2bool($backup_enable)
  $bool_run_checks = any2bool($run_checks)
  $bool_auto_deploy = any2bool($auto_deploy)

  if ($verify_ssl) {
    $ssl_arg = ''
  }else{
    $ssl_arg = '-k'
  }


### CREATE PROJECT
    puppi::project { $name:
      enable => $enable ,
    }


### INIT SEQUENCE
  if ($init_source != '') {
    puppi::initialize { "${name}-Deploy_Files":
      priority  => '40' ,
      command   => 'get_file.sh' ,
      arguments => "${ssl_arg} -s '${init_source}' -d ${deploy_root}" ,
      user      => $user ,
      project   => $name ,
      enable    => $enable ,
    }
  }


### DEPLOY SEQUENCE
  if ($bool_run_checks == true) {
    puppi::deploy { "${name}-Run_PRE-Checks":
      priority  => '10' ,
      command   => 'check_project.sh' ,
      arguments => $name ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }

    # Here source file is retrieved
    puppi::deploy { "${name}-Retrieve_TarBall":
      priority  => '20' ,
      command   => 'get_file.sh' ,
      arguments => "${ssl_arg} -s '${source}' -t tarball -a ${real_always_deploy}" ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }

    puppi::deploy { "${name}-PreDeploy_TarBall":
      priority  => '25' ,
      command   => 'predeploy_tar.sh' ,
      arguments => 'downloadedfile' ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }

  if ($firewall_src_ip != '') {
    puppi::deploy { "${name}-Load_Balancer_Block":
      priority  => '25' ,
      command   => 'firewall.sh' ,
      arguments => "${firewall_src_ip} ${firewall_dst_port} on ${firewall_delay}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($bool_backup_enable == true) {
    puppi::deploy { "${name}-Backup_existing_Files":
      priority  => '30' ,
      command   => 'archive.sh' ,
      arguments => "-b ${deploy_root} -o '${backup_rsync_options}' -n ${backup_retention}" ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($disable_services != '') {
    puppi::deploy { "${name}-Disable_extra_services":
      priority  => '36' ,
      command   => 'service.sh' ,
      arguments => "stop ${disable_services}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($init_script != '') {
    puppi::deploy { "${name}-Service_stop":
      priority  => '38' ,
      command   => 'service.sh' ,
      arguments => "stop ${init_script}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($predeploy_customcommand != '') {
    puppi::deploy { "${name}-Run_Custom_PreDeploy_Script":
      priority  => $predeploy_priority ,
      command   => 'execute.sh' ,
      arguments => $predeploy_customcommand ,
      user      => $predeploy_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

    # Here is done the deploy on $deploy_root
    puppi::deploy { "${name}-Deploy":
      priority  => '40' ,
      command   => 'deploy_files.sh' ,
      arguments => "-d ${deploy_root} -c ${bool_clean_deploy}",
      user      => $user ,
      project   => $name ,
      enable    => $enable ,
    }

  if ($postdeploy_customcommand != '') {
    puppi::deploy { "${name}-Run_Custom_PostDeploy_Script":
      priority  => $postdeploy_priority ,
      command   => 'execute.sh' ,
      arguments => $postdeploy_customcommand ,
      user      => $postdeploy_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($init_script != '') {
    puppi::deploy { "${name}-Service_start":
      priority  => '42' ,
      command   => 'service.sh' ,
      arguments => "start ${init_script}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($disable_services != '') {
    puppi::deploy { "${name}-Enable_extra_services":
      priority  => '44' ,
      command   => 'service.sh' ,
      arguments => "start ${disable_services}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($firewall_src_ip != '') {
    puppi::deploy { "${name}-Load_Balancer_Unblock":
      priority  => '46' ,
      command   => 'firewall.sh' ,
      arguments => "${firewall_src_ip} ${firewall_dst_port} off 0" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($bool_run_checks == true) {
    puppi::deploy { "${name}-Run_POST-Checks":
      priority  => '80' ,
      command   => 'check_project.sh' ,
      arguments => $name ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }


### ROLLBACK PROCEDURE

  if ($bool_backup_enable == true) {
    if ($firewall_src_ip != '') {
      puppi::rollback { "${name}-Load_Balancer_Block":
        priority  => '25' ,
        command   => 'firewall.sh' ,
        arguments => "${firewall_src_ip} ${firewall_dst_port} on ${firewall_delay}" ,
        user      => 'root',
        project   => $name ,
        enable    => $enable ,
      }
    }

    if ($disable_services != '') {
      puppi::rollback { "${name}-Disable_extra_services":
        priority  => '37' ,
        command   => 'service.sh' ,
        arguments => "stop ${disable_services}" ,
        user      => 'root',
        project   => $name ,
        enable    => $enable ,
      }
    }

    if ($init_script != '') {
      puppi::rollback { "${name}-Service_stop":
        priority  => '38' ,
        command   => 'service.sh' ,
        arguments => "stop ${init_script}" ,
        user      => 'root',
        project   => $name ,
        enable    => $enable ,
      }
    }

    if ($predeploy_customcommand != '') {
      puppi::rollback { "${name}-Run_Custom_PreDeploy_Script":
        priority  => $predeploy_priority ,
        command   => 'execute.sh' ,
        arguments => $predeploy_customcommand ,
        user      => $predeploy_real_user ,
        project   => $name ,
        enable    => $enable ,
      }
    }

      puppi::rollback { "${name}-Recover_Files_To_Deploy":
        priority  => '40' ,
        command   => 'archive.sh' ,
        arguments => "-r ${deploy_root} -o '${backup_rsync_options}'" ,
        user      => $user ,
        project   => $name ,
        enable    => $enable ,
      }

    if ($postdeploy_customcommand != '') {
      puppi::rollback { "${name}-Run_Custom_PostDeploy_Script":
        priority  => $postdeploy_priority ,
        command   => 'execute.sh' ,
        arguments => $postdeploy_customcommand ,
        user      => $postdeploy_real_user ,
        project   => $name ,
        enable    => $enable ,
      }
    }

    if ($init_script != '') {
      puppi::rollback { "${name}-Service_start":
        priority  => '42' ,
        command   => 'service.sh' ,
        arguments => "start ${init_script}" ,
        user      => 'root',
        project   => $name ,
        enable    => $enable ,
      }
    }

    if ($disable_services != '') {
      puppi::rollback { "${name}-Enable_extra_services":
        priority  => '44' ,
        command   => 'service.sh' ,
        arguments => "start ${disable_services}" ,
        user      => 'root',
        project   => $name ,
        enable    => $enable ,
      }
    }

    if ($firewall_src_ip != '') {
      puppi::rollback { "${name}-Load_Balancer_Unblock":
        priority  => '46' ,
        command   => 'firewall.sh' ,
        arguments => "${firewall_src_ip} ${firewall_dst_port} off 0" ,
        user      => 'root',
        project   => $name ,
        enable    => $enable ,
      }
    }

    if ($bool_run_checks == true) {
      puppi::rollback { "${name}-Run_POST-Checks":
        priority  => '80' ,
        command   => 'check_project.sh' ,
        arguments => $name ,
        user      => 'root' ,
        project   => $name ,
        enable    => $enable ,
      }
    }
  }

### REPORTING

  if ($report_email != '') {
    puppi::report { "${name}-Mail_Notification":
      priority  => '20' ,
      command   => 'report_mail.sh' ,
      arguments => $report_email ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

### AUTO DEPLOY DURING PUPPET RUN
  if ($bool_auto_deploy == true) {
    puppi::run { $name: }
  }

}
# == Define puppi::project::war
#
# This is a shortcut define to build a puppi project for the deploy of warfiles
# It uses different "core" defines (puppi::project, puppi:deploy (many),
# puppi::rollback (many)) to build a full featured template project for
# automatic deployments.
# If you need to customize it, either change the template defined here or
# build up your own custom ones.
#
# == Variables:
#
# [*source*]
#   The full URL of the main file to retrieve.
#   Format should be in URI standard (http:// file:// ssh:// rsync://).
#
# [*deploy_root*]
#   The destination directory where the retrieved file(s) are deployed.
#
# [*init_source*]
#   (Optional) - The full URL to be used to retrieve, for the first time,
#   the project files. They are copied directly to the $deploy_root
#   Format should be in URI standard (http:// file:// ssh:// svn://).
#
# [*user*]
#   (Optional) - The user to be used for deploy operations.
#
# [*predeploy_customcommand*]
#   (Optional) -  Full path with arguments of an eventual custom command to
#   execute before the deploy. The command is executed as $predeploy_user.
#
# [*predeploy_user*]
#   (Optional) - The user to be used to execute the $predeploy_customcommand.
#   By default is the same of $user.
#
# [*predeploy_priority*]
#   (Optional) - The priority (execution sequence number) that defines when,
#   during the deploy procedure, the $predeploy_customcommand is executed
#   Default: 39 (immediately before the copy of files on the deploy root).
#
# [*postdeploy_customcommand*]
#   (Optional) -  Full path with arguments of an eventual custom command to
#   execute after the deploy. The command is executed as $postdeploy_user.
#
# [*postdeploy_user*]
#   (Optional) - The user to be used to execute the $postdeploy_customcommand.
#   By default is the same of $user.
#
# [*postdeploy_priority*]
#   (Optional) - The priority (execution sequence number) that defines when,
#   during the deploy procedure, the $postdeploy_customcommand is executed
#   Default: 41 (immediately after the copy of files on the deploy root).
#
# [*init_script*]
#   (Optional - Obsolete) - The name (ex: tomcat) of the init script of your
#   Application server. If you define it, the AS is stopped and then started
#   during deploy. This option is deprecated, you can use $disable_services
#   for the same functionality
#
# [*disable_services*]
#   (Optional) - The names (space separated) of the services you might want to
#   stop during deploy. By default is blank. Example: "apache puppet monit".
#
# [*firewall_src_ip*]
#   (Optional) - The IP address of a loadbalancer you might want to block out
#   during a deploy.
#
# [*firewall_dst_port*]
#   (Optional) - The local port to block from the loadbalancer during deploy
#   (Default all).
#
# [*firewall_delay*]
#   (Optional) - A delay time in seconds to wait after the block of
#   $firewall_src_ip. Should be at least as long as the loadbalancer check
#   interval for the services stopped during deploy (Default: 1).
#
# [*report_email*]
#   (Optional) - The (space separated) email(s) to notify of deploy/rollback
#   operations. If none is specified, no email is sent.
#
# [*clean_deploy*]
#   (Optional, default false) - If during the deploy procedure, all the
#   existing files that are not on the source have to be deleted.
#   (When true, a --delete option is added to the rsync command)
#   Do not set to true if source files are incremental.
#
# [*backup_enable*]
#   (Optional, default true) - If the backup of files in the deploy dir
#   is done (before deploy). If set to false, rollback is disabled.
#
# [*backup_rsync_options*]
#   (Optional) - The extra options to pass to rsync for backup operations. Use
#   it, for example, to exclude directories that you don't want to archive.
#   IE: "--exclude .snapshot --exclude cache --exclude www/cache".
#
# [*backup_retention*]
#   (Optional) - Number of backup archives to keep. (Default 5).
#   Lower the default value if your backups are too large and may fill up the
#   filesystem.
#
# [*run_checks*]
#   (Optional) - If you want to run local puppi checks before and after the
#   deploy procedure. Default: "true".
#
# [*always_deploy*]
#   (Optional) - If you always deploy what has been downloaded. Default="yes",
#   if set to "no" a checksum is made between the files previously downloaded
#   and the new files. If they are the same the deploy is not done.
#
# [*check_deploy*]
#   (Optional) - Checks if the war is deployed (Default yes). Set to no if
#   you deploy on Jboss or the deployed dir is different for the war filename
#
# [*auto_deploy*]
#   (Optional) - If you want to automatically run this puppi deploy when
#   Puppet runs. Default: 'false'
#
define puppi::project::war (
  $source,
  $deploy_root,
  $init_source              = '',
  $user                     = 'root',
  $predeploy_customcommand  = '',
  $predeploy_user           = '',
  $predeploy_priority       = '39',
  $postdeploy_customcommand = '',
  $postdeploy_user          = '',
  $postdeploy_priority      = '41',
  $init_script              = '',
  $disable_services         = '',
  $firewall_src_ip          = '',
  $firewall_dst_port        = '0',
  $firewall_delay           = '1',
  $report_email             = '',
  $clean_deploy             = false,
  $backup_enable            = true,
  $backup_rsync_options     = '--exclude .snapshot',
  $backup_retention         = '5',
  $run_checks               = true,
  $always_deploy            = true,
  $check_deploy             = true,
  $auto_deploy              = false,
  $enable                   = true ) {

  require puppi
  require puppi::params

  # Set default values
  $predeploy_real_user = $predeploy_user ? {
    ''      => $user,
    default => $predeploy_user,
  }

  $postdeploy_real_user = $postdeploy_user ? {
    ''      => $user,
    default => $postdeploy_user,
  }

  # Unless explicitely defined, we assume that the WAR file to use
  # for initialization is the same to use for deploys
  $init_real_source = $init_source ? {
    ''      => $source,
    default => $init_source,
  }

  $real_always_deploy = any2bool($always_deploy) ? {
    false   => 'no',
    true    => 'yes',
  }

  $bool_run_checks = any2bool($run_checks)
  $bool_clean_deploy = any2bool($clean_deploy)
  $bool_backup_enable = any2bool($backup_enable)
  $bool_check_deploy = any2bool($check_deploy)
  $bool_auto_deploy = any2bool($auto_deploy)

  $war_file = url_parse($source,'filename')


### CREATE PROJECT
    puppi::project { $name:
      enable => $enable ,
    }


### INIT SEQUENCE
  if ($init_source != '') {
    puppi::initialize { "${name}-Deploy_Files":
      priority  => '40' ,
      command   => 'get_file.sh' ,
      arguments => "-s ${init_source} -d ${deploy_root}" ,
      user      => $user ,
      project   => $name ,
      enable    => $enable ,
    }
  }


### DEPLOY SEQUENCE
  if ($bool_run_checks == true) {
    puppi::deploy { "${name}-Run_PRE-Checks":
      priority  => '10' ,
      command   => 'check_project.sh' ,
      arguments => $name ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }

    # Here source file is retrieved
    puppi::deploy { "${name}-Retrieve_WAR":
      priority  => '20' ,
      command   => 'get_file.sh' ,
      arguments => "-s ${source} -a ${real_always_deploy}" ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }

  if ($firewall_src_ip != '') {
    puppi::deploy { "${name}-Load_Balancer_Block":
      priority  => '25' ,
      command   => 'firewall.sh' ,
      arguments => "${firewall_src_ip} ${firewall_dst_port} on ${firewall_delay}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($bool_backup_enable == true) {
    puppi::deploy { "${name}-Backup_existing_WAR":
      priority  => '30' ,
      command   => 'archive.sh' ,
      arguments => "-b ${deploy_root} -t war -s move -m diff -o '${backup_rsync_options}' -n ${backup_retention}" ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
}

  if ($bool_check_deploy == true) {
    puppi::deploy { "${name}-Check_undeploy":
      priority  => '32' ,
      command   => 'checkwardir.sh' ,
      arguments => "-a ${deploy_root}/${war_file}" ,
      user      => $user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($disable_services != '') {
    puppi::deploy { "${name}-Disable_extra_services":
      priority  => '36' ,
      command   => 'service.sh' ,
      arguments => "stop ${disable_services}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($init_script != '') {
    puppi::deploy { "${name}-Service_stop":
      priority  => '38' ,
      command   => 'service.sh' ,
      arguments => "stop ${init_script}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($predeploy_customcommand != '') {
    puppi::deploy { "${name}-Run_Custom_PreDeploy_Script":
      priority  => $predeploy_priority ,
      command   => 'execute.sh' ,
      arguments => $predeploy_customcommand ,
      user      => $predeploy_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

    # Here is done the deploy on $deploy_root
    puppi::deploy { "${name}-Deploy_WAR":
      priority  => '40' ,
      command   => 'deploy_files.sh' ,
      arguments => "-d ${deploy_root} -c ${bool_clean_deploy}",
      user      => $user ,
      project   => $name ,
      enable    => $enable ,
    }

  if ($postdeploy_customcommand != '') {
    puppi::deploy { "${name}-Run_Custom_PostDeploy_Script":
      priority  => $postdeploy_priority ,
      command   => 'execute.sh' ,
      arguments => $postdeploy_customcommand ,
      user      => $postdeploy_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($init_script != '') {
    puppi::deploy { "${name}-Service_start":
      priority  => '42' ,
      command   => 'service.sh' ,
      arguments => "start ${init_script}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($disable_services != '') {
    puppi::deploy { "${name}-Enable_extra_services":
      priority  => '44' ,
      command   => 'service.sh' ,
      arguments => "start ${disable_services}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($bool_check_deploy == true) {
    puppi::deploy { "${name}-Check_deploy":
      priority  => '45' ,
      command   => 'checkwardir.sh' ,
      arguments => "-p ${deploy_root}/${war_file}" ,
      user      => $user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($firewall_src_ip != '') {
    puppi::deploy { "${name}-Load_Balancer_Unblock":
      priority  => '46' ,
      command   => 'firewall.sh' ,
      arguments => "${firewall_src_ip} ${firewall_dst_port} off 0" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($bool_run_checks == true) {
    puppi::deploy { "${name}-Run_POST-Checks":
      priority  => '80' ,
      command   => 'check_project.sh' ,
      arguments => $name ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }


### ROLLBACK PROCEDURE

  if ($bool_backup_enable == true) {

    if ($firewall_src_ip != '') {
      puppi::rollback { "${name}-Load_Balancer_Block":
        priority  => '25' ,
        command   => 'firewall.sh' ,
        arguments => "${firewall_src_ip} ${firewall_dst_port} on ${firewall_delay}" ,
        user      => 'root',
        project   => $name ,
        enable    => $enable ,
      }
    }

      puppi::rollback { "${name}-Remove_existing_WAR":
        priority  => '30' ,
        command   => 'delete.sh' ,
        arguments => "${deploy_root}/${war_file}" ,
        user      => 'root' ,
        project   => $name ,
        enable    => $enable ,
      }

    if ($bool_check_deploy == true) {
      puppi::rollback { "${name}-Check_undeploy":
        priority  => '36' ,
        command   => 'checkwardir.sh' ,
        arguments => "-a ${deploy_root}/${war_file}" ,
        user      => $user ,
        project   => $name ,
        enable    => $enable ,
      }
    }

    if ($disable_services != '') {
      puppi::rollback { "${name}-Disable_extra_services":
        priority  => '37' ,
        command   => 'service.sh' ,
        arguments => "stop ${disable_services}" ,
        user      => 'root',
        project   => $name ,
        enable    => $enable ,
      }
    }

    if ($init_script != '') {
      puppi::rollback { "${name}-Service_stop":
        priority  => '38' ,
        command   => 'service.sh' ,
        arguments => "stop ${init_script}" ,
        user      => 'root',
        project   => $name ,
        enable    => $enable ,
      }
    }

    if ($predeploy_customcommand != '') {
      puppi::rollback { "${name}-Run_Custom_PreDeploy_Script":
        priority  => $predeploy_priority ,
        command   => 'execute.sh' ,
        arguments => $predeploy_customcommand ,
        user      => $predeploy_real_user ,
        project   => $name ,
        enable    => $enable ,
      }
    }

      puppi::rollback { "${name}-Recover_Files_To_Deploy":
        priority  => '40' ,
        command   => 'archive.sh' ,
        arguments => "-r ${deploy_root} -t war -o '${backup_rsync_options}'" ,
        user      => $user ,
        project   => $name ,
        enable    => $enable ,
      }

    if ($postdeploy_customcommand != '') {
      puppi::rollback { "${name}-Run_Custom_PostDeploy_Script":
        priority  => $postdeploy_priority ,
        command   => 'execute.sh' ,
        arguments => $postdeploy_customcommand ,
        user      => $postdeploy_real_user ,
        project   => $name ,
        enable    => $enable ,
      }
    }

    if ($init_script != '') {
      puppi::rollback { "${name}-Service_start":
        priority  => '42' ,
        command   => 'service.sh' ,
        arguments => "start ${init_script}" ,
        user      => 'root',
        project   => $name ,
        enable    => $enable ,
      }
    }

    if ($disable_services != '') {
      puppi::rollback { "${name}-Enable_extra_services":
        priority  => '44' ,
        command   => 'service.sh' ,
        arguments => "start ${disable_services}" ,
        user      => 'root',
        project   => $name ,
        enable    => $enable ,
      }
    }

    if ($bool_check_deploy == true) {
      puppi::rollback { "${name}-Check_deploy":
        priority  => '45' ,
        command   => 'checkwardir.sh' ,
        arguments => "-p ${deploy_root}/${war_file}" ,
        user      => $user ,
        project   => $name ,
        enable    => $enable ,
      }
    }

    if ($firewall_src_ip != '') {
      puppi::rollback { "${name}-Load_Balancer_Unblock":
        priority  => '46' ,
        command   => 'firewall.sh' ,
        arguments => "${firewall_src_ip} ${firewall_dst_port} off 0" ,
        user      => 'root',
        project   => $name ,
        enable    => $enable ,
      }
    }

    if ($bool_run_checks == true) {
      puppi::rollback { "${name}-Run_POST-Checks":
        priority  => '80' ,
        command   => 'check_project.sh' ,
        arguments => $name ,
        user      => 'root' ,
        project   => $name ,
        enable    => $enable ,
      }
    }
  }

### REPORTING

  if ($report_email != '') {
    puppi::report { "${name}-Mail_Notification":
      priority  => '20' ,
      command   => 'report_mail.sh' ,
      arguments => $report_email ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

### AUTO DEPLOY DURING PUPPET RUN
  if ($bool_auto_deploy == true) {
    puppi::run { $name: }
  }

}
# = Define puppi::project::y4maven
#
# This is a shortcut define to build a puppi project for the
# deploying hybris-production-zips via Maven and published on
# a repository like artifactory.
#
# It uses different "core" defines (puppi::project, puppi:deploy (many),
# puppi::rollback (many)) to build a full featured template project for
# automatic deployments.
# If you need to customize it, either change the template defined here or
# build up your own custom ones.
#
# == Variables:
#
# [*source*]
#   The full URL of the maven-metadata.xml file to retrieve.
#   Format should be in URI standard (http:// file:// ssh:// rsync://).
#
# [*http_password*]
#   The http_password to use for authentication to the source in case of http.
#
# [*http_user*]
#   The http_user to use for authentication to the source in case of http.
#
# [*artifact_type*]
#   The artifact_type to parse the maven-metadata.xml. Either "release" or "latest"
#   Default is "release". With artifactory, don't use the
#   "Maven Snapshot Version Behavior" "unique" for your repository.
#
# [*deploy_root*]
#   The destination directory where file(s) are deployed.
#
# [*user*]
#   (Optional) - The user to be used for deploy operations.
#
# [*war_suffix*]
#   (Optional) - The suffix (Maven qualifier) that might be appended to the war
#
# [*zip_suffix*]
#   (Optional) - The suffix (Maven qualifier) that might be appended to the zip
#
# [*jar_root*]
#   (Optional) - The destination directory where the jar is copied.
#   If set a jar file is searched in Maven
#
# [*jar_user*]
#   (Optional) - The user to be used for deploy operations of the jar
#   (owner of the files deployed in $jar_root)
#
# [*jar_suffix*]
#   (Optional) - The suffix (Maven qualifier) that might be appended to the jar
#
# [*document_root*]
#   (Optional) - The destination directory where the eventual tarball generated
#   via Maven containing static files ("src tar") is unpacked
#
# [*document_suffix*]
#   (Optional) - The suffix (Maven qualifier) that might be appended to the
#   static files tarballs ("src tar")
#
# [*document_init_source*]
#   (Optional) - The full URL to be used to retrieve, for the first time, the
#    project files present in the source tarball. They are copied to the
#    $document_root. Format should be in URI standard (http:// file:// ...)
#
# [*document_user*]
#   (Optional) - The user to be used for deploy operations of the tarball
#   (owner of the files in $document_root)
#
# [*config_root*]
#   (Optional) - The destination directory where the cfg tar is unpacked
#
# [*config_suffix*]
#   (Optional) - The suffix (Maven qualifier) that might be appended to
#   configuration tarballs ("cfg tar")
#
# [*config_init_source*]
#   (Optional) - The full URL to be used to retrieve, for the first time, the
#   project files present in the cfg tar. They are copied to the $config_root.
#   Format should be in URI standard (http:// file:// ssh:// svn://)
#
# [*config_user*]
#   (Optional) - The user to be used for deploy operations of cfg tar
#   (owner of the files in $config_root)
#
# [*predeploy_customcommand*]
#   (Optional) -  Full path with arguments of an eventual custom command to
#   execute before the deploy. The command is executed as $predeploy_user.
#
# [*predeploy_user*]
#   (Optional) - The user to be used to execute the $predeploy_customcommand.
#   By default is the same of $user.
#
# [*predeploy_priority*]
#   (Optional) - The priority (execution sequence number) that defines when,
#   during the deploy procedure, the $predeploy_customcommand is executed
#   Default: 39 (immediately before the copy of files on the deploy root).
#
# [*postdeploy_customcommand*]
#   (Optional) -  Full path with arguments of an eventual custom command to
#   execute after the deploy. The command is executed as $postdeploy_user.
#
# [*postdeploy_user*]
#   (Optional) - The user to be used to execute the $postdeploy_customcommand.
#   By default is the same of $user.
#
# [*postdeploy_priority*]
#   (Optional) - The priority (execution sequence number) that defines when,
#   during the deploy procedure, the $postdeploy_customcommand is executed
#   Default: 41 (immediately after the copy of files on the deploy root).
#
# [*init_script*]
#   (Optional - Obsolete) - The name (ex: tomcat) of the init script of your
#   Application server. If you define it, the AS is stopped and then started
#   during deploy. This option is deprecated, you can use $disable_services
#   for the same functionality
#
# [*disable_services*]
#   (Optional) - The names (space separated) of the services you might want to
#   stop during deploy. By default is blank. Example: "apache puppet monit".
#
# [*firewall_src_ip*]
#   (Optional) - The IP address of a loadbalancer you might want to block out
#   during a deploy.
#
# [*firewall_dst_port*]
#   (Optional) - The local port to block from the loadbalancer during deploy
#   (Default all).
#
# [*firewall_delay*]
#   (Optional) - A delay time in seconds to wait after the block of
#   $firewall_src_ip. Should be at least as long as the loadbalancer check
#   interval for the services stopped during deploy (Default: 1).
#
# [*report_email*]
#   (Optional) - The (space separated) email(s) to notify of deploy/rollback
#   operations. If none is specified, no email is sent.
#
# [*backup_rsync_options*]
#   (Optional) - The extra options to pass to rsync for backup operations. Use
#   it, for example, to exclude directories that you don't want to archive.
#   IE: "--exclude .snapshot --exclude cache --exclude www/cache".
#
# [*backup_retention*]
#   (Optional) - Number of backup archives to keep. (Default 5).
#   Lower the default value if your backups are too large and may fill up the
#   filesystem.
#
# [*run_checks*]
#   (Optional) - If you want to run local puppi checks before and after the
#   deploy procedure. Default: "true".
#
# [*always_deploy*]
#   (Optional) - If you always deploy what has been downloaded. Default="yes",
#   if set to "no" a checksum is made between the files previously downloaded
#   and the new files. If they are the same the deploy is not done.
#
# [*check_deploy*]
#   (Optional) - Checks if the war is deployed (Default yes). Set to no if
#   you deploy on Jboss or the deployed dir is different for the war filename
#
# [*auto_deploy*]
#   (Optional) - If you want to automatically run this puppi deploy when
#   Puppet runs. Default: 'false'
#
define puppi::project::y4maven (
  $source,
  $http_user                = '',
  $http_password            = '',
  $artifact_type            = 'release',
  $deploy_root              = '',
  $user                     = 'root',
  $war_suffix               = 'suffixnotset',
  $zip_suffix               = 'suffixnotset',
  $jar_root                 = '',
  $jar_user                 = '',
  $jar_suffix               = 'suffixnotset',
  $document_root            = '',
  $document_user            = '',
  $document_suffix          = 'suffixnotset',
  $document_init_source     = '',
  $config_root              = '',
  $config_user              = '',
  $config_suffix            = 'suffixnotset',
  $config_init_source       = '',
  $predeploy_customcommand  = '',
  $predeploy_user           = '',
  $predeploy_priority       = '39',
  $postdeploy_customcommand = '',
  $postdeploy_user          = '',
  $postdeploy_priority      = '41',
  $init_script              = '',
  $disable_services         = '',
  $firewall_src_ip          = '',
  $firewall_dst_port        = '0',
  $firewall_delay           = '1',
  $report_email             = '',
  $backup_rsync_options     = '--exclude .snapshot',
  $backup_retention         = '5',
  $run_checks               = true,
  $always_deploy            = true,
  $check_deploy             = true,
  $auto_deploy              = false,
  $enable                   = true ) {

  require puppi
  require puppi::params

  # Set default values
  $predeploy_real_user = $predeploy_user ? {
    ''      => $user,
    default => $predeploy_user,
  }

  $postdeploy_real_user = $postdeploy_user ? {
    ''      => $user,
    default => $postdeploy_user,
  }

  $config_real_user = $config_user ? {
    ''      => $user,
    default => $config_user,
  }

  $document_real_user = $document_user ? {
    ''      => $user,
    default => $document_user,
  }

  $jar_real_user = $jar_user ? {
    ''      => $user,
    default => $jar_user,
  }

  $real_always_deploy = any2bool($always_deploy) ? {
    false   => 'no',
    true    => 'yes',
  }

  $bool_run_checks = any2bool($run_checks)
  $bool_check_deploy = any2bool($check_deploy)
  $bool_auto_deploy = any2bool($auto_deploy)


### CREATE PROJECT
    puppi::project { $name:
      enable => $enable ,
    }


### INIT SEQUENCE
  if ($document_init_source != '') {
    puppi::initialize { "${name}-Deploy_Files":
      priority  => '40' ,
      command   => 'get_file.sh' ,
      arguments => "-s ${document_init_source} -d ${deploy_root}" ,
      user      => $document_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($config_init_source != '') {
    puppi::initialize { "${name}-Deploy_CFG_Files":
      priority  => '40' ,
      command   => 'get_file.sh' ,
      arguments => "-s ${config_init_source} -d ${deploy_root}" ,
      user      => $config_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

### DEPLOY SEQUENCE
  if ($bool_run_checks == true) {
    puppi::deploy { "${name}-Run_PRE-Checks":
      priority  => '10' ,
      command   => 'check_project.sh' ,
      arguments => $name ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }

    # First: hybrisServer-Platform
    $platform_metadata_arguments = $http_password ? {
      '' => "-s ${source}/hybrisServer-Platform/maven-metadata.xml -t maven-metadata -a ${real_always_deploy}" ,
      default => "-s ${source}/hybrisServer-Platform/maven-metadata.xml -t maven-metadata -a ${real_always_deploy} -u ${http_user} -p ${http_password}"
    }

    puppi::deploy { "${name}-Get_Maven_Metadata_hybrisServer-Platform_File":
      priority  => '20' ,
      command   => 'get_file.sh' ,
      arguments => $platform_metadata_arguments,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }

    puppi::deploy { "${name}-Extract_Maven_Metadata_hybrisServer-Platform":
      priority  => '21' ,
      command   => 'get_metadata.sh' ,
      arguments => "-m ${document_suffix} -mc ${config_suffix} -mj ${jar_suffix} -mw ${war_suffix} -mz ${zip_suffix} -at ${artifact_type}" ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }

  # Files retrieval
  $platform_zipfile_arguments = $http_password ? {
    ''      => "${source}/hybrisServer-Platform zipfile",
    default => "-u ${http_user} -p ${http_password} ${source}/hybrisServer-Platform zipfile",
  }

  if ($deploy_root != '') {
    puppi::deploy { "${name}-Get_Maven_Files_ZIP_hybrisServer-Platform":
      priority  => '22' ,
      command   => 'get_maven_files.sh' ,
      arguments => $platform_zipfile_arguments,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }

    # Second: hybrisServer-AllExtensions
    $extensions_metadata_arguments = $http_password ? {
      ''      => "-s ${source}/hybrisServer-AllExtensions/maven-metadata.xml -t maven-metadata -a ${real_always_deploy}",
      default => "-s ${source}/hybrisServer-AllExtensions/maven-metadata.xml -t maven-metadata -a ${real_always_deploy} -u ${http_user} -p ${http_password}",
    }

    puppi::deploy { "${name}-Get_Maven_Metadata_hybrisServer-AllExtensions_File":
      priority  => '23' ,
      command   => 'get_file.sh' ,
      arguments => $extensions_metadata_arguments,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }

    puppi::deploy { "${name}-Extract_Maven_Metadata_hybrisServer-AllExtensions":
      priority  => '24' ,
      command   => 'get_metadata.sh' ,
      arguments => "-m ${document_suffix} -mc ${config_suffix} -mj ${jar_suffix} -mw ${war_suffix} -mz ${zip_suffix} -at ${artifact_type}" ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }

  # Files retrieval
  if ($deploy_root != '') {
    $extensions_zipfile_arguments = $http_password ? {
      ''      => "${source}/hybrisServer-AllExtensions zipfile",
      default => "-u ${http_user} -p ${http_password} ${source}/hybrisServer-AllExtensions zipfile",
    }

    puppi::deploy { "${name}-Get_Maven_Files_ZIP_hybrisServer-AllExtensions":
      priority  => '25' ,
      command   => 'get_maven_files.sh' ,
      arguments => $extensions_zipfile_arguments,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }


  if ($config_root != '') {
    # Third: config-tarball (optional, right now not supported)
    $config_metadata_arguments = $http_password ? {
      ''      => "-s ${source}/config/maven-metadata.xml -t maven-metadata -a ${real_always_deploy}",
      default => "-s ${source}/config/maven-metadata.xml -t maven-metadata -a ${real_always_deploy} -u ${http_user} -p ${http_password}"
    }

    puppi::deploy { "${name}-Get_Maven_Metadata_config-tarball_File":
      priority  => '26' ,
      command   => 'get_file.sh' ,
      arguments => $config_metadata_arguments,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }

    puppi::deploy { "${name}-Extract_Maven_Metadata_config-tarball":
      priority  => '27' ,
      command   => 'get_metadata.sh' ,
      arguments => "-m ${document_suffix} -mc ${config_suffix} -mj ${jar_suffix} -mw ${war_suffix} -mz ${zip_suffix} -at ${artifact_type}" ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }

    puppi::deploy { "${name}-Get_Maven_Files_Config":
      priority  => '28' ,
      command   => 'get_maven_files.sh' ,
      arguments => "${source} configfile" ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($firewall_src_ip != '') {
    puppi::deploy { "${name}-Load_Balancer_Block":
      priority  => '30' ,
      command   => 'firewall.sh' ,
      arguments => "${firewall_src_ip} ${firewall_dst_port} on ${firewall_delay}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  # Existing files backup
  if ($deploy_root != '') {
    puppi::deploy { "${name}-Backup_Existing_WAR":
      priority  => '30' ,
      command   => 'archive.sh' ,
      arguments => "-b ${deploy_root} -t war -s move -m diff -o '${backup_rsync_options}' -n ${backup_retention}" ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($jar_root != '') {
    puppi::deploy { "${name}-Backup_Existing_JAR":
      priority  => '30' ,
      command   => 'archive.sh' ,
      arguments => "-b ${jar_root} -t jar -s move -m diff -o '${backup_rsync_options}' -n ${backup_retention}" ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($config_root != '') {
    puppi::deploy { "${name}-Backup_Existing_ConfigDir":
      priority  => '30' ,
      command   => 'archive.sh' ,
      arguments => "-b ${config_root} -t config -d predeploydir_configfile -o '${backup_rsync_options}' -n ${backup_retention}" ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($document_root != '') {
    puppi::deploy { "${name}-Backup_Existing_DocumentDir":
      priority  => '30' ,
      command   => 'archive.sh' ,
      arguments => "-b ${document_root} -t docroot -d predeploydir_configfile -o '${backup_rsync_options}' -n ${backup_retention}" ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($disable_services != '') {
    puppi::deploy { "${name}-Disable_extra_services":
      priority  => '36' ,
      command   => 'service.sh' ,
      arguments => "stop ${disable_services}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($init_script != '') {
    puppi::deploy { "${name}-Service_stop":
      priority  => '38' ,
      command   => 'service.sh' ,
      arguments => "stop ${init_script}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($predeploy_customcommand != '') {
    puppi::deploy { "${name}-Run_Custom_PreDeploy_Script":
      priority  => $predeploy_priority ,
      command   => 'execute.sh' ,
      arguments => $predeploy_customcommand ,
      user      => $predeploy_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  # Deploys
  if ($deploy_root != '') {
    puppi::deploy { "${name}-Deploy_Maven_ZIP":
      priority  => '40' ,
      command   => 'deploy.sh' ,
      arguments => "${deploy_root} predeploydir_zipfile ",
      user      => $user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($config_root != '') {
    puppi::deploy { "${name}-Deploy_ConfigDir":
      priority  => '40' ,
      command   => 'deploy.sh' ,
      arguments => "${config_root} predeploydir_configfile" ,
      user      => $config_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  puppi::deploy { "${name}-yant":
    priority  => '42' ,
    command   => 'yant.sh' ,
    arguments => "${deploy_root} clean all" ,
    user      => $user ,
    project   => $name ,
    enable    => $enable ,
  }

  if ($postdeploy_customcommand != '') {
    puppi::deploy { "${name}-Run_Custom_PostDeploy_Script":
      priority  => $postdeploy_priority ,
      command   => 'execute.sh' ,
      arguments => $postdeploy_customcommand ,
      user      => $postdeploy_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($init_script != '') {
    puppi::deploy { "${name}-Service_start":
      priority  => '44' ,
      command   => 'service.sh' ,
      arguments => "start ${init_script}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($disable_services != '') {
    puppi::deploy { "${name}-Enable_extra_services":
      priority  => '45' ,
      command   => 'service.sh' ,
      arguments => "start ${disable_services}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($firewall_src_ip != '') {
    puppi::deploy { "${name}-Load_Balancer_Unblock":
      priority  => '47' ,
      command   => 'firewall.sh' ,
      arguments => "${firewall_src_ip} ${firewall_dst_port} off 0" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($bool_run_checks == true) {
    puppi::deploy { "${name}-Run_POST-Checks":
      priority  => '80' ,
      command   => 'check_project.sh' ,
      arguments => $name ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }


### ROLLBACK PROCEDURE

  if ($firewall_src_ip != '') {
    puppi::rollback { "${name}-Load_Balancer_Block":
      priority  => '25' ,
      command   => 'firewall.sh' ,
      arguments => "${firewall_src_ip} ${firewall_dst_port} on ${firewall_delay}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($disable_services != '') {
    puppi::rollback { "${name}-Disable_extra_services":
      priority  => '37' ,
      command   => 'service.sh' ,
      arguments => "stop ${disable_services}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($init_script != '') {
    puppi::rollback { "${name}-Service_stop":
      priority  => '38' ,
      command   => 'service.sh' ,
      arguments => "stop ${init_script}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($predeploy_customcommand != '') {
    puppi::rollback { "${name}-Run_Custom_PreDeploy_Script":
      priority  => $predeploy_priority ,
      command   => 'execute.sh' ,
      arguments => $predeploy_customcommand ,
      user      => $predeploy_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($deploy_root != '') {
    puppi::rollback { "${name}-Recover_ZIP":
      priority  => '40' ,
      command   => 'archive.sh' ,
      arguments => "-r ${deploy_root} -t zip -o '${backup_rsync_options}'" ,
      user      => $user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($config_root != '') {
    puppi::rollback { "${name}-Recover_ConfigDir":
      priority  => '40' ,
      command   => 'archive.sh' ,
      arguments => "-r ${config_root} -t config -o '${backup_rsync_options}'" ,
      user      => $config_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($postdeploy_customcommand != '') {
    puppi::rollback { "${name}-Run_Custom_PostDeploy_Script":
      priority  => $postdeploy_priority ,
      command   => 'execute.sh' ,
      arguments => $postdeploy_customcommand ,
      user      => $postdeploy_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($init_script != '') {
    puppi::rollback { "${name}-Service_start":
      priority  => '42' ,
      command   => 'service.sh' ,
      arguments => "start ${init_script}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($disable_services != '') {
    puppi::rollback { "${name}-Enable_extra_services":
      priority  => '44' ,
      command   => 'service.sh' ,
      arguments => "start ${disable_services}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($firewall_src_ip != '') {
    puppi::rollback { "${name}-Load_Balancer_Unblock":
      priority  => '46' ,
      command   => 'firewall.sh' ,
      arguments => "${firewall_src_ip} ${firewall_dst_port} off 0" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($bool_run_checks == true) {
    puppi::rollback { "${name}-Run_POST-Checks":
      priority  => '80' ,
      command   => 'check_project.sh' ,
      arguments => $name ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }


### REPORTING

  if ($report_email != '') {
    puppi::report { "${name}-Mail_Notification":
      priority  => '20' ,
      command   => 'report_mail.sh' ,
      arguments => $report_email ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

### AUTO DEPLOY DURING PUPPET RUN
  if ($bool_auto_deploy == true) {
    puppi::run { $name: }
  }

}
# = Define puppi::project::yum
#
# This is a shortcut define to build a puppi project for the
# deploy of applications packaged as rpm and retrievable via yum
#
# It uses different "core" defines (puppi::project, puppi:deploy (many),
# puppi::rollback (many)) to build a full featured template project for
# automatic deployments.
# If you need to customize it, either change the template defined here or
# build up your own custom ones.
#
# == Variables:
#
# [*rpm*]
#   The name of the rpm to install
#
# [*rpm_version*]
#   (Optional) - The version to install (default: latest)
#
# [*install_root*]
#   (Optional) - The rpm installation root (default: / )
#
# [*predeploy_customcommand*]
#   (Optional) -  Full path with arguments of an eventual custom command to
#   execute before the deploy. The command is executed as $predeploy_user.
#
# [*predeploy_user*]
#   (Optional) - The user to be used to execute the $predeploy_customcommand.
#   By default is the same of $user.
#
# [*predeploy_priority*]
#   (Optional) - The priority (execution sequence number) that defines when,
#   during the deploy procedure, the $predeploy_customcommand is executed
#   Default: 39 (immediately before the copy of files on the deploy root).
#
# [*postdeploy_customcommand*]
#   (Optional) -  Full path with arguments of an eventual custom command to
#   execute after the deploy. The command is executed as $postdeploy_user.
#
# [*postdeploy_user*]
#   (Optional) - The user to be used to execute the $postdeploy_customcommand.
#   By default is the same of $user.
#
# [*postdeploy_priority*]
#   (Optional) - The priority (execution sequence number) that defines when,
#   during the deploy procedure, the $postdeploy_customcommand is executed
#   Default: 41 (immediately after the copy of files on the deploy root).
#
# [*disable_services*]
#   (Optional) - The names (space separated) of the services you might want to
#   stop during deploy. By default is blank. Example: "apache puppet monit".
#
# [*firewall_src_ip*]
#   (Optional) - The IP address of a loadbalancer you might want to block out
#   during a deploy.
#
# [*firewall_dst_port*]
#   (Optional) - The local port to block from the loadbalancer during deploy
#   (Default all).
#
# [*firewall_delay*]
#   (Optional) - A delay time in seconds to wait after the block of
#   $firewall_src_ip. Should be at least as long as the loadbalancer check
#   interval for the services stopped during deploy (Default: 1).
#
# [*report_email*]
#   (Optional) - The (space separated) email(s) to notify of deploy/rollback
#   operations. If none is specified, no email is sent.
#
# [*run_checks*]
#   (Optional) - If you want to run local puppi checks before and after the
#   deploy procedure. Default: "true".
#
# [*checks_required*]
#   (Optional) - Set to "true" if you want to block the installation if
#   preliminary checks fail. Default: "false"
#
# [*always_deploy*]
#   (Optional) - If you always deploy what has been downloaded. Default="yes",
#   if set to "no" a checksum is made between the files previously downloaded
#   and the new files. If they are the same the deploy is not done.
#
# [*auto_deploy*]
#   (Optional) - If you want to automatically run this puppi deploy when
#   Puppet runs. Default: 'false'
#
define puppi::project::yum (
  $rpm,
  $rpm_version              = 'latest',
  $install_root             = '/',
  $predeploy_customcommand  = '',
  $predeploy_user           = '',
  $predeploy_priority       = '39',
  $postdeploy_customcommand = '',
  $postdeploy_user          = '',
  $postdeploy_priority      = '41',
  $disable_services         = '',
  $firewall_src_ip          = '',
  $firewall_dst_port        = '0',
  $firewall_delay           = '1',
  $report_email             = '',
  $run_checks               = true,
  $checks_required          = false,
  $always_deploy            = true,
  $auto_deploy              = false,
  $enable                   = true ) {

  require puppi
  require puppi::params

  # Set default values
  $predeploy_real_user = $predeploy_user ? {
    ''      => 'root',
    default => $predeploy_user,
  }

  $postdeploy_real_user = $postdeploy_user ? {
    ''      => 'root',
    default => $postdeploy_user,
  }

  $real_always_deploy = any2bool($always_deploy) ? {
    true    => 'yes',
    default => 'no',
  }

  $real_checks_required = any2bool($checks_required) ? {
    true    => 'yes',
    default => 'no',
  }

  $bool_run_checks = any2bool($run_checks)
  $bool_auto_deploy = any2bool($auto_deploy)

### CREATE PROJECT
    puppi::project { $name:
      enable => $enable ,
    }

### DEPLOY SEQUENCE
  if ($bool_run_checks == true) {
    puppi::deploy { "${name}-Run_PRE-Checks":
      priority  => '10' ,
      command   => 'check_project.sh' ,
      arguments => "${name} ${real_checks_required}",
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($firewall_src_ip != '') {
    puppi::deploy { "${name}-Load_Balancer_Block":
      priority  => '25' ,
      command   => 'firewall.sh' ,
      arguments => "${firewall_src_ip} ${firewall_dst_port} on ${firewall_delay}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($disable_services != '') {
    puppi::deploy { "${name}-Disable_extra_services":
      priority  => '36' ,
      command   => 'service.sh' ,
      arguments => "stop ${disable_services}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($predeploy_customcommand != '') {
    puppi::deploy { "${name}-Run_Custom_PreDeploy_Script":
      priority  => $predeploy_priority ,
      command   => 'execute.sh' ,
      arguments => $predeploy_customcommand ,
      user      => $predeploy_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

    # Here is done the deploy on $deploy_root
    puppi::deploy { "${name}-Deploy":
      priority  => '40' ,
      command   => 'yum.sh' ,
      arguments => "-a deploy -n ${rpm} -r ${install_root} -v ${rpm_version}" ,
      user      => root ,
      project   => $name ,
      enable    => $enable ,
    }

  if ($postdeploy_customcommand != '') {
    puppi::deploy { "${name}-Run_Custom_PostDeploy_Script":
      priority  => $postdeploy_priority ,
      command   => 'execute.sh' ,
      arguments => $postdeploy_customcommand ,
      user      => $postdeploy_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($disable_services != '') {
    puppi::deploy { "${name}-Enable_extra_services":
      priority  => '44' ,
      command   => 'service.sh' ,
      arguments => "start ${disable_services}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($firewall_src_ip != '') {
    puppi::deploy { "${name}-Load_Balancer_Unblock":
      priority  => '46' ,
      command   => 'firewall.sh' ,
      arguments => "${firewall_src_ip} ${firewall_dst_port} off 0" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($bool_run_checks == true) {
    puppi::deploy { "${name}-Run_POST-Checks":
      priority  => '80' ,
      command   => 'check_project.sh' ,
      arguments => $name ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }


### ROLLBACK PROCEDURE

  if ($firewall_src_ip != '') {
    puppi::rollback { "${name}-Load_Balancer_Block":
      priority  => '25' ,
      command   => 'firewall.sh' ,
      arguments => "${firewall_src_ip} ${firewall_dst_port} on ${firewall_delay}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($disable_services != '') {
    puppi::rollback { "${name}-Disable_extra_services":
      priority  => '37' ,
      command   => 'service.sh' ,
      arguments => "stop ${disable_services}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($predeploy_customcommand != '') {
    puppi::rollback { "${name}-Run_Custom_PreDeploy_Script":
      priority  => $predeploy_priority ,
      command   => 'execute.sh' ,
      arguments => $predeploy_customcommand ,
      user      => $predeploy_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

    puppi::rollback { "${name}-Rollback":
      priority  => '40' ,
      command   => 'yum.sh' ,
      arguments => "-a rollback -n ${rpm} -r ${install_root} -v ${rpm_version}" ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }

  if ($postdeploy_customcommand != '') {
    puppi::rollback { "${name}-Run_Custom_PostDeploy_Script":
      priority  => $postdeploy_priority ,
      command   => 'execute.sh' ,
      arguments => $postdeploy_customcommand ,
      user      => $postdeploy_real_user ,
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($disable_services != '') {
    puppi::rollback { "${name}-Enable_extra_services":
      priority  => '44' ,
      command   => 'service.sh' ,
      arguments => "start ${disable_services}" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($firewall_src_ip != '') {
    puppi::rollback { "${name}-Load_Balancer_Unblock":
      priority  => '46' ,
      command   => 'firewall.sh' ,
      arguments => "${firewall_src_ip} ${firewall_dst_port} off 0" ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

  if ($bool_run_checks == true) {
    puppi::rollback { "${name}-Run_POST-Checks":
      priority  => '80' ,
      command   => 'check_project.sh' ,
      arguments => $name ,
      user      => 'root' ,
      project   => $name ,
      enable    => $enable ,
    }
  }


### REPORTING

  if ($report_email != '') {
    puppi::report { "${name}-Mail_Notification":
      priority  => '20' ,
      command   => 'report_mail.sh' ,
      arguments => $report_email ,
      user      => 'root',
      project   => $name ,
      enable    => $enable ,
    }
  }

### AUTO DEPLOY DURING PUPPET RUN
  if ($bool_auto_deploy == true) {
    puppi::run { $name: }
  }

}
# Define puppi::report
#
# This define creates a file with a report command that can be used locally.
#
# Usage:
# puppi::report { "Retrieve files":
#   command  => "report_mail.sh",
#   argument => "roots@example42.com",
#   priority => "10",
#   user   => "root",
#   project  => "spysite",
# }
#
define puppi::report (
  $project,
  $command,
  $arguments = '',
  $priority  = '50',
  $user      = 'root',
  $enable    = true ) {

  require puppi::params

  # Autoinclude the puppi class
  include puppi

  $ensure = bool2ensure($enable)

  file { "${puppi::params::projectsdir}/${project}/report/${priority}-${name}":
    ensure  => $ensure,
    mode    => '0755',
    owner   => $puppi::params::configfile_owner,
    group   => $puppi::params::configfile_group,
    content => "su - ${user} -c \"export project=${project} && ${puppi::params::scriptsdir}/${command} ${arguments}\"\n",
    tag     => 'puppi_report',
  }

}
# Define puppi::rollback
#
# This define creates a file with a rollback command that can be used locally.
#
# Usage:
# puppi::rollback { "Retrieve files":
#   command  => "get_file.sh",
#   argument => "/remote/dir/file",
#   priority => "10",
#   user   => "root",
#   project  => "spysite",
# }
#
define puppi::rollback (
  $project,
  $command,
  $arguments = '',
  $priority  = '50',
  $user      = 'root',
  $enable    = true ) {

  require puppi
  require puppi::params

  $ensure = bool2ensure($enable)

  file { "${puppi::params::projectsdir}/${project}/rollback/${priority}-${name}":
    ensure  => $ensure,
    mode    => '0750',
    owner   => $puppi::params::configfile_owner,
    group   => $puppi::params::configfile_group,
    content => "su - ${user} -c \"export project=${project} && ${puppi::params::scriptsdir}/${command} ${arguments}\"\n",
    tag     => 'puppi_rollback',
  }

}
# Define puppi::run
#
# This define triggers a puppi deploy run directly during Puppet
# execution. It can be used to automate FIRST TIME applications
# deployments directly during the first Puppet execution
#
# == Variables
#
# [*name*]
#   The title/name you use has to be the name of an existing puppi::project
#   procedure define
#
# == Usage
# Basic Usage:
# puppi::run { "myapp": }
#
define puppi::run (
  $project = '',
  $timeout = 300) {

  require puppi

  exec { "Run_Puppi_${name}":
    command => "puppi deploy ${name}; [ $? -le \"1\" ] && touch ${puppi::params::archivedir}/puppirun_${name}",
    path    => '/bin:/sbin:/usr/sbin:/usr/bin',
    creates => "${puppi::params::archivedir}/puppirun_${name}",
    timeout => $timeout,
    # require => File[ tag == 'puppi_deploy' ],
  }

}
# = Define: puppi::runscript
#
# This define creates, executes and optionally crontabs a
# simple whose content is directly managed by arguments.
# The script content is provided either with $source or $content arguments.
# It's placed in:
# $destination_path , if provided, or in /usr/local/sbin/${name}
#
# Cron execution times are defined by the $cron argument (Default empty).
# Automatic execution of the script via Puppet is managed by the $autorun
# parameter (default: true).
# Conditional execution of the script at subsequent puppet runs is
# defined by the $refreshonly, $creates, $unless $onlyif parameters
# that map the omonimous exec type arguments.
#
# == Parameters:
#
# [*source*]
#   String. Optional. Default: undef. Alternative to content.
#   Source of the script file to provide for execuution.
#   Sample: source => 'puppet:///modules/site/scripts/my_script',
#
# [*content*]
#   String. Optional. Default: undef. Alternative to source.
#   Content of the script file to provide for execuution.
#   This parameter is alternative to source.
#   Sample: content => 'template(site/scripts/my_script.erb'),
#
# [*destination_path*]
#   String. Optional. Default: ''
#   Path of the provided script. If not provided the script in saved in
#   /usr/local/sbin/${name}
#
# [*parameters*]
#   String. Optional. Default: ''
#   Optional parameters to pass to the script when executing it.
#
# [*autorun*]
#   Boolean. Default: true.
#   Define if to automatically execute the script when Puppet runs.
#
# [*refreshonly*]
#   Boolen. Optional. Default: true
#   Defines the logic of execution of the script when Puppet runs.
#   Maps to the omonymous Exec type argument.
#
# [*creates*]
#   String. Optional. Default: undef
#   Defines the logic of execution of the script when Puppet runs.
#   Maps to the omonymous Exec type argument.
#
# [*onlyif*]
#   String. Optional. Default: undef
#   Defines the logic of execution of the script when Puppet runs.
#   Maps to the omonymous Exec type argument.
#
# [*unless*]
#   String. Optional. Default: undef
#   Defines the logic of execution of the script when Puppet runs.
#   Maps to the omonymous Exec type argument.
#
# [*basedir*]
#   String. Optional. Default: /usr/local/sbin
#   Directory where the runscript scripts are created when destination_path
#   is empty.
#
# [*cron*]
#   String. Optional. Default: ''
#   Optional cron schedule to crontab the execution of the
#   script. Format must be in standard cron style.
#   Example: '0 4 * * *' .
#   By default no cron is scheduled.
#
# [*cron_user*]
#   String. Optional. Default: 'root'
#   When cron is enabled the user that executes the cron job.
#
# [*owner*]
#   Owner of the created script. Default: root.
#
# [*group*]
#   Group of the created script. Default: root.
#
# [*mode*]
#   Mode of the created script. Default: '7550'.
#   NOTE: Keep the execution flag!
#
# [*ensure*]
#   Define if the runscript script and eventual cron job
#   must be present or absent. Default: present.
#
# == Examples
#
# - Minimal setup
# puppi::runscript { 'my_script':
#   source           => 'puppet:///modules/site/scripts/my_script.sh',
#   destination_path => '/usr/local/bin/my_script.sh',
# }
#
define puppi::runscript (
  $source           = undef,
  $content          = undef,
  $destination_path = '',
  $parameters       = '',
  $autorun          = true,
  $refreshonly      = true,
  $creates          = undef,
  $onlyif           = undef,
  $unless           = undef,
  $basedir          = '/usr/local/sbin',
  $cron             = '',
  $cron_user        = 'root',
  $owner            = 'root',
  $group            = 'root',
  $mode             = '0755',
  $ensure           = 'present' ) {

  $real_command = $destination_path ? {
    ''      => "${basedir}/${name}",
    default => $destination_path,
  }

  file { "runscript_${name}":
    ensure  => $ensure,
    path    => $real_command,
    mode    => $mode,
    owner   => $owner,
    group   => $group,
    content => $content,
    source  => $source,
  }

  if $autorun == true {
    exec { "runscript_${name}":
      command     => $real_command,
      refreshonly => $refreshonly,
      creates     => $creates,
      onlyif      => $onlyif,
      unless      => $unless,
      subscribe   => File["runscript_${name}"],
    }
  }

  if $cron != '' {
    file { "runscript_cron_${name}":
      ensure  => $ensure,
      path    => "/etc/cron.d/runscript_${name}",
      mode    => '0644',
      owner   => 'root',
      group   => 'root',
      content => "${cron} ${cron_user} ${real_command} ${parameters}\n",
    }
  }
}
#
# Class puppi::skel
#
# Creates the base Puppi dirs
#
class puppi::skel {

  require puppi::params

  file { 'puppi_basedir':
    ensure  => directory,
    path    => $puppi::params::basedir,
    mode    => '0755',
    owner   => $puppi::params::configfile_owner,
    group   => $puppi::params::configfile_group,
  }

  file { 'puppi_checksdir':
    ensure  => directory,
    path    => $puppi::params::checksdir,
    mode    => '0755',
    owner   => $puppi::params::configfile_owner,
    group   => $puppi::params::configfile_group,
    require => File['puppi_basedir'],
    recurse => true,
    purge   => true,
    force   => true,
  }

  file { 'puppi_logsdir':
    ensure  => directory,
    path    => $puppi::params::logsdir,
    mode    => '0755',
    owner   => $puppi::params::configfile_owner,
    group   => $puppi::params::configfile_group,
    require => File['puppi_basedir'],
    recurse => true,
    purge   => true,
    force   => true,
  }

  file { 'puppi_helpersdir':
    ensure  => directory,
    path    => $puppi::params::helpersdir,
    mode    => '0755',
    owner   => $puppi::params::configfile_owner,
    group   => $puppi::params::configfile_group,
    require => File['puppi_basedir'],
  }

  file { 'puppi_infodir':
    ensure  => directory,
    path    => $puppi::params::infodir,
    mode    => '0755',
    owner   => $puppi::params::configfile_owner,
    group   => $puppi::params::configfile_group,
    require => File['puppi_basedir'],
    recurse => true,
    purge   => true,
    force   => true,
  }

  file { 'puppi_tododir':
    ensure  => directory,
    path    => $puppi::params::tododir,
    mode    => '0755',
    owner   => $puppi::params::configfile_owner,
    group   => $puppi::params::configfile_group,
    require => File['puppi_basedir'],
    recurse => true,
    purge   => true,
    force   => true,
  }

  file { 'puppi_projectsdir':
    ensure  => directory,
    path    => $puppi::params::projectsdir,
    mode    => '0755',
    owner   => $puppi::params::configfile_owner,
    group   => $puppi::params::configfile_group,
    require => File['puppi_basedir'],
    recurse => true,
    purge   => true,
    force   => true,
  }

  file { 'puppi_datadir':
    ensure  => directory,
    path    => $puppi::params::datadir,
    mode    => '0750',
    owner   => $puppi::params::configfile_owner,
    group   => $puppi::params::configfile_group,
    require => File['puppi_basedir'],
    recurse => true,
    purge   => true,
    force   => true,
  }

  file { 'puppi_workdir':
    ensure  => directory,
    path    => $puppi::params::workdir,
    mode    => '0755',
    owner   => $puppi::params::configfile_owner,
    group   => $puppi::params::configfile_group,
    require => File['puppi_basedir'],
  }

  file { 'puppi_archivedir':
    ensure  => directory,
    path    => $puppi::params::archivedir,
    mode    => '0755',
    owner   => $puppi::params::configfile_owner,
    group   => $puppi::params::configfile_group,
    require => File['puppi_libdir'],
  }

  file { 'puppi_readmedir':
    ensure  => directory,
    path    => $puppi::params::readmedir,
    mode    => '0755',
    owner   => $puppi::params::configfile_owner,
    group   => $puppi::params::configfile_group,
    require => File['puppi_libdir'],
  }

  file { 'puppi_libdir':
    ensure  => directory,
    path    => $puppi::params::libdir,
    mode    => '0755',
    owner   => $puppi::params::configfile_owner,
    group   => $puppi::params::configfile_group,
    require => File['puppi_basedir'],
  }

  file { 'puppi_logdir':
    ensure  => directory,
    path    => $puppi::params::logdir,
    mode    => '0755',
    owner   => $puppi::params::configfile_owner,
    group   => $puppi::params::configfile_group,
    require => File['puppi_basedir'],
  }

  # MailPuppiCheck script
  file { '/usr/bin/mailpuppicheck':
    ensure  => 'present',
    mode    => '0750',
    owner   => $puppi::params::configfile_owner,
    group   => $puppi::params::configfile_group,
    source  => 'puppet:///modules/puppi/mailpuppicheck',
  }

  # Puppi common scripts
  file { 'puppi.scripts':
    ensure  => present,
    path    => "${puppi::params::scriptsdir}/",
    mode    => '0755',
    owner   => $puppi::params::configfile_owner,
    group   => $puppi::params::configfile_group,
    source  => 'puppet:///modules/puppi/scripts/',
    recurse => true,
#   purge   => true,
    ignore  => '.svn',
  }

  # Logs cleanup script
  if $::kernel == 'Linux' {
    if $puppi::logs_retention_days
    and $puppi::logs_retention_days != '0' {
      $purge_cron_ensure = 'present'
    } else {
      $purge_cron_ensure = 'absent'
    }

    file { 'puppi_cron_logs_purge':
      ensure  => $purge_cron_ensure,
      path    => '/etc/cron.daily/puppi_clean',
      mode    => '0755',
      owner   => 'root',
      group   => 'root',
      content => template('puppi/puppi_clean.erb'),
    }
  } 
}
# Define puppi::todo
#
# This define creates a basic todo file that simply contains informations
# on how to complete tasks that for time or other reasons could not be
# entirely automated by Puppet.
# The basic idea is to have a quick way to document and check if are completed
# some specific operations that are required to bring a new, puppettized system
# to full operative status.
# This can be useful for cases hard to automate with Puppet:
# - First setup and import of a database needed by an application (module)
# - Installation of a legacy application that involves user interaction
# - Run of any kind of setup/configuration/init command that can't be automated
# It can also be used as a quick reminder on things done by hand and not
# Puppettized for lack of time or skill.
#
# Use the command puppi todo to show the todo present in your node.
# The exit status can be:
# 0 - OK - The task to do has been accomplished because the command specified
#    as check_command returns true (exit status 0)
# 1- WARNING - User hasn't specified a check_command to verify if the todo as
#    been accomplished, so it can't be notified if the todo has been done
# 2- ERROR - The task to do has not been accomplished becuase the command
#    specified as check_command returns an error (exit status different from 0)
#
# == Usage:
# puppi::todo { "cacti_db_install":
#   description => "Manual cacti db installation" ,
# }
#
define puppi::todo (
  $description   = '',
  $notes         = '',
  $check_command = '',
  $run           = '' ) {

  require puppi
  require puppi::params

  $array_run = is_array($run) ? {
    false     => $run ? {
      ''      => [],
      default => split($run, ','),
    },
    default   => $run,
  }

  file { "${puppi::params::tododir}/${name}":
    ensure  => present,
    mode    => '0750',
    owner   => $puppi::params::configfile_owner,
    group   => $puppi::params::configfile_group,
    require => Class['puppi'],
    content => template('puppi/todo.erb'),
    tag     => 'puppi_todo',
  }

}
# Class: puppi::two
#
# Installs Puppi NextGen
#
class puppi::two {

  # The Puppi command
  package { 'puppi':
    ensure   => present,
    provider => 'gem',
  }

}
# Define puppi::ze
#
# The Puppi 2.0 define that transforms any class variable in data
# you can use with Puppi
#
# == Usage
# Basic Usage:
# puppi::ze { "openssh":
#   variables => get_class_args(),
# }
#
# puppi::ze { "openssh":
#   variables => get_class_args(),
#   filter    => '.*content.*|.*key.*',
# }
#
define puppi::ze (
  $variables,
  $helper = 'standard',
  $filter = '.*content.*|.*password.*',
  $ensure = 'present' ) {

  require puppi
  require puppi::params

  file { "puppize_${name}":
    ensure  => $ensure,
    path    => "${puppi::params::datadir}/${helper}_${name}.yml",
    mode    => '0644',
    owner   => $puppi::params::configfile_owner,
    group   => $puppi::params::configfile_group,
    content => inline_template("---\n<%= Hash[@variables].reject{ |k,v| k.to_s =~ /(${filter})/ }.keys.sort.map{|k| Array({k => @variables[k]}.to_yaml)[1..-1].join}.join(\"\n\") %>\n"),
  }

}
require "#{File.join(File.dirname(__FILE__),'..','spec_helper.rb')}"

describe 'puppi' do

  let(:node) { 'rspec.example42.com' }
  let(:node) { 'rspec.example42.com' }
  let(:facts) { { :ipaddress => '10.42.42.42' } }

  describe 'Test standard installation' do
    it { should contain_file('puppi').with_ensure('present') }
    it { should contain_file('puppi.conf').with_ensure('present') }
    it { should contain_file('puppi.scripts').with_ensure('present') }
    it { should contain_file('puppi_basedir').with_ensure('directory') }
    it { should contain_file('puppi_datadir').with_ensure('directory') }
  end

end
require "#{File.join(File.dirname(__FILE__),'..','spec_helper.rb')}"

describe 'puppi::check' do

  let(:title) { 'puppi::check' }
  let(:node) { 'rspec.example42.com' }
  let(:facts) { { :arch => 'i386' } }
  let(:params) {
    { 'enable'   =>  'true',
      'name'     =>  'get',
      'command'  =>  'echo',
      'priority' =>  '50',
      'project'  =>  'myapp',
    }
  }

  describe 'Test puppi check step file creation' do
    it 'should create a puppi::check step file' do
      should contain_file('Puppi_check_myapp_50_get').with_ensure('present')
    end
    it 'should populate correctly the puppi::check step file' do
      should contain_file('Puppi_check_myapp_50_get').with_content(/\/usr\/lib\/nagios\/plugins\/echo/)
    end
  end

end
require "#{File.join(File.dirname(__FILE__),'..','spec_helper.rb')}"

describe 'puppi::deploy' do

  let(:title) { 'puppi::deploy' }
  let(:node) { 'rspec.example42.com' }
  let(:params) {
    { 'enable'   =>  'true',
      'name'     =>  'get',
      'command'  =>  'echo',
      'priority' =>  '50',
      'project'  =>  'myapp',
    }
  }

  describe 'Test puppi deploy step file creation' do
    it 'should create a puppi::deploy step file' do
      should contain_file('/etc/puppi/projects/myapp/deploy/50-get').with_ensure('present')
    end
    it 'should populate correctly the puppi::deploy step file' do
      should contain_file('/etc/puppi/projects/myapp/deploy/50-get').with_content("su - root -c \"export project=myapp && /etc/puppi/scripts/echo \"\n")
    end
  end

end
require "#{File.join(File.dirname(__FILE__),'..','spec_helper.rb')}"

describe 'puppi::helper' do

  let(:title) { 'spec' }
  let(:node) { 'rspec.example42.com' }
  let(:params) {
    { 'template'   => 'puppi/helpers/standard.yml.erb'  }
  }

  describe 'Test puppi helper file creation' do
    it 'should create a puppi helper file' do
      should contain_file('puppi_helper_spec').with_ensure('present')
    end
    it 'should populate correctly the helper file' do
      should contain_file('puppi_helper_spec').with_content(/info/)
    end
  end

end
require "#{File.join(File.dirname(__FILE__),'..','spec_helper.rb')}"

describe 'puppi::info' do

  let(:title) { 'puppi::info' }
  let(:node) { 'rspec.example42.com' }
  let(:params) {
    { 'name'         =>  'sample',
      'description'  =>  'Sample Info',
      'templatefile' =>  'puppi/info.erb',
      'run'          =>  'myownscript',
    }
  }

  describe 'Test puppi info step file creation' do
    it 'should create a puppi::info step file' do
      should contain_file('/etc/puppi/info/sample').with_ensure('present')
    end
    it 'should populate correctly the puppi::info step file' do
      should contain_file('/etc/puppi/info/sample').with_content(/myownscript/)
    end
  end

end
require "#{File.join(File.dirname(__FILE__),'..','spec_helper.rb')}"

describe 'puppi::initialize' do

  let(:title) { 'puppi::initialize' }
  let(:node) { 'rspec.example42.com' }
  let(:params) {
    { 'enable'   =>  'true',
      'name'     =>  'get',
      'command'  =>  'echo',
      'priority' =>  '50',
      'project'  =>  'myapp',
    }
  }

  describe 'Test puppi initialize step file creation' do
    it 'should create a puppi::initialize step file' do
      should contain_file('/etc/puppi/projects/myapp/initialize/50-get').with_ensure('present')
    end
    it 'should populate correctly the puppi::initialize step file' do
      should contain_file('/etc/puppi/projects/myapp/initialize/50-get').with_content("su - root -c \"export project=myapp && /etc/puppi/scripts/echo \"\n")
    end
  end

end
require "#{File.join(File.dirname(__FILE__),'..','spec_helper.rb')}"

describe 'puppi::log' do

  let(:title) { 'mylog' }
  let(:node) { 'rspec.example42.com' }
  let(:params) {
    { 'log'         =>  '/var/log/mylog.log',
      'description' =>  'My Log',
    }
  }

  describe 'Test puppi log file creation' do
    it 'should create a puppi::log file' do
      should contain_file('/etc/puppi/logs/mylog').with_ensure('present')
    end
    it 'should populate correctly the puppi::log step file' do
      should contain_file('/etc/puppi/logs/mylog').with_content(/mylog.log/)
    end
  end

end
require "#{File.join(File.dirname(__FILE__),'..','spec_helper.rb')}"

describe 'puppi::report' do

  let(:title) { 'puppi::report' }
  let(:node) { 'rspec.example42.com' }
  let(:params) {
    { 'enable'   =>  'true',
      'name'     =>  'get',
      'command'  =>  'echo',
      'priority' =>  '50',
      'project'  =>  'myapp',
    }
  }

  describe 'Test puppi report step file creation' do
    it 'should create a puppi::report step file' do
      should contain_file('/etc/puppi/projects/myapp/report/50-get').with_ensure('present')
    end
    it 'should populate correctly the puppi::report step file' do
      should contain_file('/etc/puppi/projects/myapp/report/50-get').with_content("su - root -c \"export project=myapp && /etc/puppi/scripts/echo \"\n")
    end
  end

end
require "#{File.join(File.dirname(__FILE__),'..','spec_helper.rb')}"

describe 'puppi::report' do

  let(:title) { 'puppi::report' }
  let(:node) { 'rspec.example42.com' }
  let(:params) {
    { 'enable'   =>  'true',
      'name'     =>  'get',
      'command'  =>  'echo',
      'priority' =>  '50',
      'project'  =>  'myapp',
    }
  }

  describe 'Test puppi report step file creation' do
    it 'should create a puppi::report step file' do
      should contain_file('/etc/puppi/projects/myapp/report/50-get').with_ensure('present')
    end
    it 'should populate correctly the puppi::report step file' do
      should contain_file('/etc/puppi/projects/myapp/report/50-get').with_content("su - root -c \"export project=myapp && /etc/puppi/scripts/echo \"\n")
    end
  end

end
require "#{File.join(File.dirname(__FILE__),'..','spec_helper.rb')}"

describe 'puppi::rollback' do

  let(:title) { 'puppi::rollback' }
  let(:node) { 'rspec.example42.com' }
  let(:params) {
    { 'enable'   =>  'true',
      'name'     =>  'get',
      'command'  =>  'echo',
      'priority' =>  '50',
      'project'  =>  'myapp',
    }
  }

  describe 'Test puppi rollback step file creation' do
    it 'should create a puppi::rollback step file' do
      should contain_file('/etc/puppi/projects/myapp/rollback/50-get').with_ensure('present')
    end
    it 'should populate correctly the puppi::rollback step file' do
      should contain_file('/etc/puppi/projects/myapp/rollback/50-get').with_content("su - root -c \"export project=myapp && /etc/puppi/scripts/echo \"\n")
    end
  end

end
require "#{File.join(File.dirname(__FILE__),'..','spec_helper.rb')}"

describe 'puppi::run' do

  let(:title) { 'myapp' }
  let(:node) { 'rspec.example42.com' }
  let(:params) {
    { 
      'project'  =>  'myapp',
    }
  }

  describe 'Test puppi run exe creation' do
    it { should contain_exec('Run_Puppi_myapp').with_command(/puppi deploy myapp/) }
  end

end
require "#{File.join(File.dirname(__FILE__),'..','spec_helper.rb')}"

describe 'puppi::todo' do

  let(:title) { 'mytodo' }
  let(:node) { 'rspec.example42.com' }
  let(:params) {
    { 'notes'         =>  'Test Notes',
      'description'   =>  'Test Description',
      'check_command' =>  'check_test',
      'run'           =>  'test',
    }
  }

  describe 'Test puppi todo file creation' do
    it 'should create a puppi::todo file' do
      should contain_file('/etc/puppi/todo/mytodo').with_ensure('present')
    end
    it 'should populate correctly the puppi::todo step file' do
      should contain_file('/etc/puppi/todo/mytodo').with_content(/check_test/)
    end
  end

end
require "#{File.join(File.dirname(__FILE__),'..','spec_helper.rb')}"

describe 'puppi::ze' do

  let(:title) { 'sample' }
  let(:node) { 'rspec.example42.com' }
  let(:params) {
    { 'helper'     => 'mytest',
      'variables'  => { 'var1' => 'get', 'var2' => 'got' },
      'name'       => 'sample',
    }
  }

  describe 'Test puppi ze data file creation' do
    it 'should create a puppi::ze step file' do
      should contain_file('puppize_sample').with_ensure('present')
    end
  end

end
require "#{File.join(File.dirname(__FILE__),'..','spec_helper.rb')}"

describe 'any2bool' do

  describe 'Test Any2True' do
    it { should run.with_params(true).and_return(true) }
    it { should run.with_params('true').and_return(true) }
    it { should run.with_params('yes').and_return(true) }
    it { should run.with_params('y').and_return(true) }
  end

  describe 'Test Any2false' do
    it { should run.with_params(false).and_return(false) }
    it { should run.with_params('false').and_return(false) }
    it { should run.with_params('no').and_return(false) }
    it { should run.with_params('n').and_return(false) }
  end


end
require "#{File.join(File.dirname(__FILE__),'..','spec_helper.rb')}"

describe 'bool2ensure' do

  describe 'Test true2present' do
    it { should run.with_params(true).and_return('present') }
    it { should run.with_params('true').and_return('present') }
    it { should run.with_params('yes').and_return('present') }
    it { should run.with_params('y').and_return('present') }
  end

  describe 'Test false2absent' do
    it { should run.with_params(false).and_return('absent') }
    it { should run.with_params('false').and_return('absent') }
    it { should run.with_params('no').and_return('absent') }
    it { should run.with_params('n').and_return('absent') }
  end


end
require "#{File.join(File.dirname(__FILE__),'..','spec_helper.rb')}"

describe 'url_parse' do

  describe 'Test Url Components parsing' do
    it 'should return correct scheme' do
      should run.with_params('ftp://www.example.com/test','scheme').and_return('ftp') 
    end
    it 'should return correct userinfo' do
      should run.with_params('https://my_user:my_pass@www.example.com:8080/path/to/file.php?id=1&ret=0','userinfo').and_return('my_user:my_pass') 
    end
    it 'should return correct user' do
      should run.with_params('https://my_user:my_pass@www.example.com:8080/path/to/file.php?id=1&ret=0','user').and_return('my_user') 
    end
    it 'should return correct password' do
      should run.with_params('https://my_user:my_pass@www.example.com:8080/path/to/file.php?id=1&ret=0','password').and_return('my_pass') 
    end
    it 'should return correct host' do
      should run.with_params('https://my_user:my_pass@www.example.com:8080/path/to/file.php?id=1&ret=0','host').and_return('www.example.com') 
    end
    it 'should return correct port' do
      should run.with_params('https://my_user:my_pass@www.example.com:8080/path/to/file.php?id=1&ret=0','port').and_return(8080) 
    end
    it 'should return correct path' do
      should run.with_params('https://my_user:my_pass@www.example.com:8080/path/to/file.php?id=1&ret=0','path').and_return('/path/to/file.php') 
    end
    it 'should return correct query' do
      should run.with_params('https://my_user:my_pass@www.example.com:8080/path/to/file.php?id=1&ret=0','query').and_return('id=1&ret=0') 
    end
    it 'should return correct filename' do
      should run.with_params('https://my_user:my_pass@www.example.com:8080/path/to/file.php?id=1&ret=0','filename').and_return('file.php') 
    end
    it 'should return correct filetype' do
      should run.with_params('https://my_user:my_pass@www.example.com:8080/path/to/file.php?id=1&ret=0','filetype').and_return('.php') 
    end
    it 'should return correct filedir' do
      should run.with_params('https://my_user:my_pass@www.example.com:8080/path/to/file.php?id=1&ret=0','filedir').and_return('file') 
    end

  end

end

require 'puppetlabs_spec_helper/module_spec_helper'
:info:
  -
    :command: "<%= scope.lookupvar('puppi::params::info_package_query') %> %{package}"
    :description: "Package info"
  -
    :command: "<%= scope.lookupvar('puppi::params::info_package_list') %> %{package} | egrep '(/bin|^/etc|/sbin|log$)'"
    :description: "Interesting files from package"
  -
    :command: "head %{config_file}"
    :description: "Main configuration file"
  -
    :command: "ls -latr %{config_dir}"
    :description: "Configuration directory"
  -
    :command: "ls -latr %{data_dir}"
    :description: "Data directory"
  -
    :command: "ls -latr %{log_dir}"
    :description: "Logs directory"
  -
    :command: "tail %{log_file}"
    :description: "Latest log entries"
  -
    :command: "service %{service status}"
    :description: "Service status"
  -
    :command: "ps -adef | grep %{process} | grep -v grep | head -20"
    :description: "Running process"
  -
    :command: "netstat -natup | grep %{port} | head -20"
    :description: "Network connections"

:check:
  -
    :command: "service %{service} status"
    :description: "Service status"
  -
    :command: "check_tcp %{port}"
    :description: "Check listening port"
  -
    :command: "check_procs c 1: -C %{process}"
    :description: "Check process"

:log:
  -
    :command: "tail -f %{log_file}"
    :description: "Tailing logs"

#!/bin/bash
# <%= @description %>
# Script generated by Puppet. It's executed when you run:
# puppi info <%= @name %>
#
# Sources common header for Puppi scripts
. <%= scope.lookupvar('puppi::params::scriptsdir') %>/header || exit 10

echo_title "$HOSTNAME - <%= @description %>"
<% @array_run.each do |cmd| %>show_command "<%= cmd %>"
<% end %>
#!/bin/bash
# <%= @description %>
# Script generated by Puppet. It's executed when you run:
# puppi info <%= @name %>
#
# Sources common header for Puppi scripts
. <%= scope.lookupvar('puppi::params::scriptsdir') %>/header || exit 10

<% if @configdir != "" -%>
# Show config info
echo_title "$HOSTNAME - <%= @name %>: Configurations directory: <%= @configdir %>"
show_command "ls -latr <%= @configdir %>"
<% end -%>

<% if @datadir != "" -%>
# Show data dir
echo_title "$HOSTNAME - <%= @name %>: Application data are in: <% datadir.each do |item| %><%= item %><% end %>"
<% @datadir.each do |item| -%>
show_command "ls -latr <%= item %>"
<% end -%>
<% end -%>

<% if @bindir != "" -%>
# Show bin dir
echo_title "$HOSTNAME - <%= @name %>: Startup scripts are in: <% bindir.each do |item| %><%= item %><% end %>"
<% @bindir.each do |item| -%>
show_command "ls -latr <%= item %>"
<% end -%>
<% end -%>

<% if @logdir != "" -%>
# Show log dir
echo_title "$HOSTNAME - <%= @name %>: Logs are in: <% logdir.each do |item| %><%= item %><% end %>"
<% @logdir.each do |item| -%>
show_command "ls -latr <%= item %>"
show_command "tail -30 <%= item %>/catalina.out"
<% end -%>
<% end -%>

<% if @run != "" -%>
echo_title "$HOSTNAME - <%= @name %>: Extra info"
<% @run.each do |cmd| %>show_command "<%= cmd %>"
<% end -%>
<% end -%>


<% if @servicename != "" -%>
# Show service info
echo_title "$HOSTNAME - <%= @name %>: Services: <% @servicename.each do |item| %><%= item %><% end %>"
<% @servicename.each do |item| -%>
show_command "/etc/init.d/<%= item %> status"
<% end -%>
<% if @verbose == "yes" -%>
show_command "ps -adef | grep java | grep <%= @processname %>"
<% else -%>
show_command "ps -adef | grep java | grep <%= @processname %> | head -20"
<% end -%>
<% end -%>

<% if @httpport != "" -%>
# Show port info
echo_title "$HOSTNAME - <%= @name %>: httpport - <%= @httpport %>"
<% if @verbose == "yes" -%>
show_command "netstat -natup | grep ':<%= @httpport %> '"
<% else -%>
show_command "netstat -natup | grep ':<%= @httpport %> ' | head -20"
<% end -%>
<% end -%>

<% if @controlport != "" -%>
# Show port info
echo_title "$HOSTNAME - <%= @name %>: controlport - <%= @controlport %>"
<% if @verbose == "yes" -%>
show_command "netstat -natup | grep ':<%= @controlport %> '"
<% else -%>
show_command "netstat -natup | grep ':<%= @controlport %> ' | head -20"
<% end -%>
<% end -%>

<% if @ajpport != "" -%>
# Show port info
echo_title "$HOSTNAME - <%= @name %>: ajpport - <%= @ajpport %>"
<% if @verbose == "yes" -%>
show_command "netstat -natup | grep ':<%= @ajpport %> '"
<% else -%>
show_command "netstat -natup | grep ':<%= @ajpport %> ' | head -20"
<% end -%>
<% end -%>

#!/bin/bash
# <%= @description %>
# Script generated by Puppet. It's executed when you run:
# puppi info <%= @name %> 
#
# Sources common header for Puppi scripts
. <%= scope.lookupvar('puppi::params::scriptsdir') %>/header || exit 10

<% if @packagename != "" -%>
# Show packages info
echo_title "$HOSTNAME - <%= @name %>: Packages Installed: <% @packagename.each do |item| %><%= item %><% end %>"
<% @packagename.each do |item| -%>
show_command "<%= scope.lookupvar('puppi::params::info_package_query') %> <%= item %>"
<% if @verbose == "yes" -%>
show_command "<%= scope.lookupvar('puppi::params::info_package_list') %> <%= item %>"
<% else -%>
show_command "<%= scope.lookupvar('puppi::params::info_package_list') %> <%= item %> | egrep '(/bin|^/etc|/sbin|log$)'"
<% end -%>
<% end -%>
<% end -%>

<% if @configfile != "" -%>
# Show config info
echo_title "$HOSTNAME - <%= @name %>: Configuration Files managed: <% @configfile.each do |item| %><%= item %><% end %>"
<% @configfile.each do |item| -%>
<% if @verbose == "yes" -%>
show_command "cat <%= item %>"
<% else -%> 
show_command "head <%= item %>"
<% end -%>
<% end -%>
<% end -%>

<% if @datadir != "" -%>
# Show data dir
echo_title "$HOSTNAME - <%= @name %>: Application data are in: <% @datadir.each do |item| %><%= item %><% end %>"
<% @datadir.each do |item| -%>
show_command "ls -latr <%= item %>"
show_command "df <%= item %>"
<% end -%>
<% end -%>

<% if @logdir != "" -%>
# Show log dir
echo_title "$HOSTNAME - <%= @name %>: Logs are in: <% @logdir.each do |item| %><%= item %><% end %>"
<% @logdir.each do |item| -%>
show_command "ls -latr <%= item %>"
show_command "df <%= item %>"
<% end -%>
<% end -%>

<% if @logfile != "" -%>
# Show logs
echo_title "$HOSTNAME - <%= @name %>: Last log entries: <% @logfile.each do |item| %><%= item %><% end %>"
<% @logfile.each do |item| -%>
<% if @verbose == "yes" -%>
show_command "tail -30 <%= item %>"
<% else -%>
show_command "tail -10 <%= item %>"
<% end -%>
<% end -%>
<% end -%>

<% if @run != "" -%>
echo_title "$HOSTNAME - <%= @name %>: Extra info"
<% @run.each do |cmd| %>show_command "<%= cmd %>"
<% end -%>
<% end -%>


<% if @servicename != "" -%>
# Show service info
echo_title "$HOSTNAME - <%= @name %>: Services: <% @servicename.each do |item| %><%= item %><% end %>"
<% @servicename.each do |item| -%>
show_command "/etc/init.d/<%= item %> status"
<% end -%>
<% if @verbose == "yes" -%>
show_command "ps -adef | grep <%= @processname %> | grep -v grep"
<% else -%>
show_command "ps -adef | grep <%= @processname %> | grep -v grep | head -20"
<% end -%>
<% @port.each do |mport| -%>
<% if @verbose == "yes" -%>
show_command "netstat -natup | grep ':<%= mport %> '"
<% else -%>
show_command "netstat -natup | grep ':<%= mport %> ' | head -20"
<% end -%>
<% end -%>
<% end -%>
#!/bin/bash
# <%= @description %>
# Script generated by Puppet. It's executed when you run:
# puppi info <%= @name %>
#
# Sources common header for Puppi scripts
. <%= scope.lookupvar('puppi::params::scriptsdir') %>/header || exit 10

# Show Puppet info
echo_title "$HOSTNAME - <%= @name %>: Information on management with Puppet"
echo "Where to configure this node in Puppet:"
echo "manifests/nodes/<%= @site %>.pp - Node's definition"
echo "manifests/roles/role_<%= @role %>.pp - Role's definition"
echo "modules/<modulename>/manifests/init.pp - Main class for each module"
echo

# Show ReadMe file
echo_title "$HOSTNAME - <%= @name %>: ReadMe"
show_command "cat <%= scope.lookupvar('puppi::params::readmedir') %>/<%= @name %>"

<% if @autoreadme == "yes" %>
echo_title "$HOSTNAME - <%= @name %>: ReadMe Custom"
show_command "cat <%= scope.lookupvar('puppi::params::readmedir') %>/<%= @name %>-custom"
<% end %>

<% if @run != "" %>
echo_title "$HOSTNAME - <%= @name %>: Extra info"
<% @run.each do |cmd| %>show_command "<%= cmd %>"
<% end %>
<% end %>
#!/bin/bash
# <%= @description %>
# Script generated by Puppet. It's executed when you run:
# puppi info <%= @name %>
#
# Sources common header for Puppi scripts
. <%= scope.lookupvar('puppi::params::scriptsdir') %>/header || exit 10

# Show ReadMe file
echo_title "$HOSTNAME - <%= @name %>: ReadMe"
show_command "cat <%= scope.lookupvar('puppi::params::readmedir') %>/<%= @name %>"

<% if @autoreadme == "yes" %>
echo_title "$HOSTNAME - <%= @name %>: ReadMe Custom"
show_command "cat <%= scope.lookupvar('puppi::params::readmedir') %>/<%= @name %>-custom"
<% end %>

<% if @run != "" %>
echo_title "$HOSTNAME - <%= @name %>: Extra info"
<% @run.each do |cmd| %>show_command "<%= cmd %>"
<% end %>
<% end %>
#!/bin/bash
# File Managed by Puppet
export PATH=$PATH:/bin:/sbin:/usr/bin:usr/sbin
<% if scope.lookupvar('::operatingsystem') == 'Debian' or scope.lookupvar('::operatingsystem') == 'Ubuntu' -%>
apt-get update ; apt-get install -y <%= @packages %>
<% elsif scope.lookupvar('::operatingsystem') == 'Centos' or scope.lookupvar('::operatingsystem') == 'RedHat' -%>
yum install -y <%= @packages %>
<% end -%>
<% @array_log.each do |path| %><%= path %>
<% end %>
# File Managed by Puppet
# This is the base configuration file for project <%= scope.lookupvar('name') %>
# During a puppi deploy it's copied into the runtime configuration
#   used by the scripts executed by puppi 
#
# Do not edit this file. You can modify these variables:
# Permanently: directly on your puppi manifests (When you use the puppi:project:: defines)
# Temporarily: using the puppi option -o to override them.
#   example: puppi deploy $name -o "source=http://alt.com/file deploy_root=/var/tmp"

# Common variables for project defines
project="<%= @name %>"
source="<%= @source %>"
deploy_root="<%= @deploy_root %>"
user="<%= @user %>"
predeploy_customcommand="<%= @predeploy_customcommand %>"
postdeploy_customcommand="<%= @postdeploy_customcommand %>"
init_script="<%= @init_script %>"
disable_services="<%= @disable_services %>"
firewall_src_ip="<%= @firewall_src_ip %>"
firewall_dst_port="<%= @firewall_dst_port %>"
report_email="<%= @report_email %>"
enable="<%= @enable %>"

# Variables used by project::files
files_prefix="<%= @files_prefix %>"
source_baseurl="<%= @source_baseurl %>"

# Variables used by project::maven
document_root="<%= @document_root %>"
config_root="<%= @config_root %>"

# Variables added during runtime puppi operations
# General configuration file for Puppi tools
# This file is managed by Puppet

# Directory locations
basedir="<%= scope.lookupvar('puppi::params::basedir') %>"
checksdir="<%= scope.lookupvar('puppi::params::checksdir') %>"
workdir="<%= scope.lookupvar('puppi::params::workdir') %>"
projectsdir="<%= scope.lookupvar('puppi::params::projectsdir') %>"
scriptsdir="<%= scope.lookupvar('puppi::params::scriptsdir') %>"
libdir="<%= scope.lookupvar('puppi::params::libdir') %>"
archivedir="<%= scope.lookupvar('puppi::params::archivedir') %>"
logdir="<%= scope.lookupvar('puppi::params::logdir') %>"
logsdir="<%= scope.lookupvar('puppi::params::logsdir') %>"
infodir="<%= scope.lookupvar('puppi::params::infodir') %>"
tododir="<%= scope.lookupvar('puppi::params::tododir') %>"
#!/bin/bash
configfile="<%= scope.lookupvar('puppi::params::basedir') %>/puppi.conf"

# This is the actual command used to run the different scripts
# Use cat for debugging noop purposes 
# runcommand="cat"
runcommand=""

# Define defaults
verbosity="max"
show="yes"

# Define action tag
export tag=$(date +%Y%m%d-%H%M%S)

counter=0

# Load general configurations
if [ ! -f $configfile ] ; then
    echo "Config file: $configfile not found"
    exit 1
else
    . $configfile
    . $scriptsdir/functions
fi

# Main functions
check_host () {
    for command in $(ls -1 $checksdir) ; do
        title="$HOSTNAME check: $command"
        code=$(cat "$checksdir/$command")
        ask_interactive
        output=$($runcommand "$checksdir/$command" 2>&1)
        handle_result
    done
}

check () {
    for command in $(ls -1 $projectsdir/$project/check) ; do
        title="$HOSTNAME check: $command"
        code=$(cat "$projectsdir/$project/check/$command")
        ask_interactive
        output=$($runcommand "$projectsdir/$project/check/$command" 2>&1)
        handle_result
    done

    check_host
    # show_report
}

log () {
    tailcommand="tail"
    which colortail >/dev/null 2>&1  && tailcommand="colortail"

    if [ "x$project" != "xdefault" ] ; then
        if [ $logsdir/$project ] ; then
            alllog="$alllog $(cat $logsdir/$project)"
        else
            echo "WARNING: $logsdir/$project does not exist!"
            exit 1
        fi
    else
        if [ "$interactive" = "yes" ] ; then
            echo "Choose one or more log topics to show. Select the last number (done) to end selection"
            PS3="Type one number to add a log topic to the show list."
            all_choices=""
            select choice in $( ls $logsdir ) done
            do
                echo "You selected $choice [$REPLY]"
                [[ $choice == "done" ]] && break
                all_choices="$all_choices $choice"
                echo "Your choices: $all_choices"
            done
            for log in $all_choices ; do
                alllog="$alllog $(cat $logsdir/$log)"
            done
        else
            for log in $(ls $logsdir) ; do
                alllog="$alllog $(cat $logsdir/$log)"
            done
        fi
    fi

    # So, show something
    if [ ! -z "$counts" ] ; then
        if [ ! -z "$greppattern" ] ; then
            $tailcommand -n $counts $alllog | grep $greppattern
        else
            $tailcommand -n $counts $alllog
        fi
    else
        if [ ! -z "$greppattern" ] ; then
            $tailcommand -f $alllog | grep $greppattern
        else
            $tailcommand -f $alllog
        fi
    fi
}

info () {
    if [ "x$project" != "xdefault" ] ; then
        if [ $infodir/$project ] ; then
            $infodir/$project 
        else
            echo "WARNING: $infodir/$project does not exist!"
            exit 1
        fi
    else
        if [ "$interactive" = "yes" ] ; then
            echo "Choose one or more topics to show. Select the last number (done) to end selection"
            PS3="Type one number to add an info topic to the show list."
            all_choices=""
            select choice in $( ls $infodir ) done
            do
                echo "You selected $choice [$REPLY]"
                [[ $choice == "done" ]] && break
                all_choices="$all_choices $choice"
                echo "Your choices: $all_choices"
            done
            for info in $all_choices ; do
                if [ ! -z "$greppattern" ] ; then
                    $infodir/$info | grep $greppattern
                else
                    $infodir/$info
                fi
            done
        else
            for info in $(ls $infodir) ; do
                if [ ! -z "$greppattern" ] ; then
                    $infodir/$info | grep $greppattern
                else
                    $infodir/$info
                fi
            done
        fi
    fi
}


todo () {
    for todo in $(ls $tododir) ; do
        $tododir/$todo
    done
}


rollback () {
    if [ ! -z $rollbackversion ] ; then
        save_runtime_config "rollbackversion=$rollbackversion" || initerr=1
    else
        echo "Choose deploy to rollback:"
        ls -1 $archivedir/$project
        read rollbackversion
        save_runtime_config "rollbackversion=$rollbackversion" || initerr=1
    fi
    
    for command in $(ls -1 $projectsdir/$project/rollback) ; do
        title="$HOSTNAME Rollback: $command"
        code=$(cat "$projectsdir/$project/rollback/$command")
        ask_interactive
        output=$($runcommand "$projectsdir/$project/rollback/$command" 2>&1)
        handle_result
    done

    send_reports
    show_report
    [ "$result" = "OK" ] && exit 0
}

deploy () {
    for command in $(ls -1 $projectsdir/$project/deploy) ; do
        title="$HOSTNAME Deploy: $command"
        code=$(cat "$projectsdir/$project/deploy/$command")
        ask_interactive
        output=$($runcommand "$projectsdir/$project/deploy/$command" 2>&1)
        handle_result
        [ "$EXITCRIT" = "1" ] && [ "$force" != "yes" ] && break
        if [ "$DONTDEPLOY" = "1" ] ; then
             echo "No need to deploy: source file has not changed"
             echo "Type 'rm $archivedir/$project/md5sum' and run puppi again to force deployment" 
             exit 0
        fi
    done

    send_reports
    show_report
    [ "$result" = "OK" ] && exit 0
}

initialize () {
    for command in $(ls -1 $projectsdir/$project/initialize) ; do
        title="$HOSTNAME Init: $command"
        code=$(cat "$projectsdir/$project/initialize/$command")
        ask_interactive
        output=$($runcommand "$projectsdir/$project/initialize/$command" 2>&1)
        handle_result
        [ "$EXITCRIT" = "1" ] && [ "$force" != "yes" ] && break
    done

    send_reports
    show_report
    [ "$result" = "OK" ] && exit 0
}

configure () {
    for command in $(ls -1 $projectsdir/$project/configure) ; do
        title="$HOSTNAME Init: $command"
        code=$(cat "$projectsdir/$project/configure/$command")
        ask_interactive
        output=$($runcommand "$projectsdir/$project/configure/$command" 2>&1)
        handle_result
        [ "$EXITCRIT" = "1" ] && [ "$force" != "yes" ] && break
    done

    send_reports
    show_report
    [ "$result" = "OK" ] && exit 0
}

save_summary () {
    tagend=$(date +%Y%m%d-%H%M%S)

    result="OK"
    if [ "$EXITWARN" = "1" ] ; then
        result="WARNING"
    fi
    if [ "$EXITCRIT" = "1" ] ; then
        result="ERROR"
    fi

    echo "Report for $action on $project" > $logdir/$project/$tag/summary
    echo "Job start: $tag" >> $logdir/$project/$tag/summary
    echo "Job end: $tagend" >> $logdir/$project/$tag/summary
    echo "Job result: $result" >> $logdir/$project/$tag/summary
    echo "Actions executed:" >> $logdir/$project/$tag/summary
    cd $logdir/$project/$tag/
    for message in $(ls -1 $logdir/$project/$tag/ | grep -v summary ) ; do
        msg_title=$(head -1 $message)
        msg_code=$(head -2 $message | tail -1) 
        msg_result=$(head -3 $message | tail -1) 
        echo "[$msg_result] $msg_title : $msg_code" >> $logdir/$project/$tag/summary
    done

    # Copy runtime config in archive
    cp $workdir/$project/config $logdir/$project/$tag/

    # Write runtime config on Summary
    echo >> $logdir/$project/$tag/summary
    echo "RUNTIME CONFIGURATION" >> $logdir/$project/$tag/summary
    cat $workdir/$project/config | grep -vE "^#|^$"  >> $logdir/$project/$tag/summary

}

send_reports () {
    if [[ "x$report" == "xyes" ]] ; then
        save_summary
        for command in $(ls -1 $projectsdir/$project/report) ; do
            title="Reporting: $command"
            code=$(cat "$projectsdir/$project/report/$command")
            echo -n $title
            output=$($runcommand "$projectsdir/$project/report/$command" 2>&1)
            # handle_result # This breaks the overall exit code when deploy fails
        done
    fi
}

show_report () {
    echo
    echo "REPORT FOR PUPPI - STATUS $result"
    echo "Summary of operations is: $logdir/$project/$tag/summary "
    echo "Details are in: $logdir/$project/$tag/"
    echo "Temporary workdir has been: $workdir/$project/ (Will be rewritten at the next puppi run)"
    echo "Runtime config file is: $workdir/$project/config"
    echo "Files have been archived in: $archivedir/$project/$tag"
    test "$testmode" = "yes" && echo "This was a TEST RUN! Nothing has been done for real."
}


create_runtime_conf () {
    if [[ ( ! -e $projectsdir/$project ) && ( ! -e $infodir/$project ) && ( ! -e $logsdir/$project ) ]] ; then
        showhelp
        exit 1
    fi

    initerr=0

    # When project is unset we set it to default
    [ ! -z "$project" ] || export project="default"

    # Clean up and Create runtime configuration file 
#    command="00-$project-RuntimeConfig-Initialization"
#    title="Puppi setup: $command"
#    code="rm -rf $workdir/$project && touch $workdir/$project/config [...]"
#    echo -n $title

    echo $workdir | grep tmp >/dev/null 2>&1 || ( echo "Workdir must contain string tmp" ; exit 1 )
    rm -rf $workdir/$project || initerr=1

    mkdir -p $workdir/$project || initerr=1
    touch $workdir/$project/config || initerr=1

    test -r "$projectsdir/$project/config" && cp $projectsdir/$project/config $workdir/$project/
    chmod 644 $workdir/$project/config || initerr=1

    save_runtime_config "project=$project" || initerr=1
    save_runtime_config "tag=$tag" || initerr=1
    save_runtime_config "action=$action" || initerr=1

    storedir=$workdir/$project/store || initerr=1
    mkdir -p $storedir || initerr=1
    save_runtime_config "storedir=$storedir" || initerr=1

    predeploydir=$workdir/$project/deploy || initerr=1
    mkdir -p $predeploydir || initerr=1
    save_runtime_config "predeploydir=$predeploydir" || initerr=1

    save_runtime_config "force=$force" || initerr=1
    save_runtime_config "testmode=$testmode" || initerr=1
    save_runtime_config "interactive=$interactive" || initerr=1
    save_runtime_config "debug=$debug" || initerr=1
    save_runtime_config "report=$report" || initerr=1
    save_runtime_config "show=$show" || initerr=1
    save_runtime_config "counts=$counts" || initerr=1
    save_runtime_config "greppattern=$greppattern" || initerr=1

    for oopt in $(echo $options) ; do
        save_runtime_config "$(echo $oopt)" || initerr=1
    done
    
    echo $initerr | grep "0" 2>&1 > /dev/null
#    handle_result
}


showhelp () {
   echo "Usage: puppi <command> [project|topic] [options]"
   echo " "
   echo "Available commands:"
   echo "check [project] [-s <yes|no|fail>] - Run puppi checks host or project wide"
   echo "log [topic] [-i] [-g <pattern>] - Show system and application specific logs"
   echo "info [topic] [-i] [-g <pattern>] - Show informations about the system"
   echo "todo - Show todo's checklist of the system"
   echo "init <project> [-i] [-f] [-t] - First time project initialization and setup"
   echo "configure <project> [-i] [-f] [-t] - Project configuration deployment."
   echo "deploy <project> [-i] [-f] [-t] [-o ...] - Deploy the specified project"
   echo "rollback <project> [state] [-i] [-f] [-t] - Rollback the specified project. "
   echo " "
   echo "Available options:"
   echo "-f - Force puppi commands execution flow also on CRITICAL errors"
   echo "-i - Interactively ask confirmation for every step"
   echo "-t - Test mode. Just show the commands that should be executed"
   echo "-d <yes|full> - Debug mode. Show debug of what is done."
   echo "-r <yes|no|fail> - Enable reporting: yes/no/only on failures. Default depends on action"
   echo "-s <yes|no|fail> - Show output: yes/no/only for failures. Default: yes"
   echo "-g <pattern> - Grep command output with the selected pattern"
   echo "-o \"parameter=value parameter2=value2\" - Set manual options to override defaults"
   echo " "
   echo "Available deploy projects:"
   ls -1 $projectsdir
   echo 
   echo "Available info topics:"
   ls $infodir 
   echo 
   echo "Available log topics:"
   ls $logsdir
}

# Check Input
if [ "$#" = "0" ] ; then
    showhelp
    exit
fi

while [ $# -gt 0 ]; do
  case "$1" in
    deploy|init|configure)
      report="yes"
      export action=$1
      if [ -n "$2" ] ; then
        echo "$2" | egrep -q "^-.$"
        if [ "$?" != "0" ] ; then
          export project=$(shell_filter_strict $2)
          shift 2
        else
          shift
        fi
      else
        showhelp
        exit
        shift
      fi
    ;;
    rollback)
      report="yes"
      export action=$1
      if [ -n "$3" ] ; then
        echo "$3" | egrep -q "^-.$"
        if [ "$?" != "0" ] ; then
          export project=$(shell_filter_strict $2)
          export rollbackversion=$(shell_filter_strict $3)
          shift 3
        else
          shift 2
        fi
      elif [ -n "$2" ] ; then
        echo "$2" | egrep -q "^-.$"
        if [ "$?" != "0" ] ; then
          export project=$(shell_filter_strict $2)
          shift 2
        else
          shift
        fi
      else
        showhelp
        exit
        shift
      fi
    ;;
    check)
      report="no"
      export action="checkhost"
      if [ -n "$2" ] ; then
        echo "$2" | egrep -q "^-.$"
        if [ "$?" != "0" ] ; then
          export project=$(shell_filter_strict $2)
          export action="check"
          shift 2
        else
          shift
        fi
      else
        shift
      fi
    ;;
    log)
      report="no"
      export action="log"
      if [ -n "$2" ] ; then
        echo "$2" | egrep -q "^-.$"
        if [ "$?" != "0" ] ; then
          export project=$(shell_filter_strict $2)
          shift 2
        else 
          shift
        fi
      else
        shift
      fi
    ;;
    info)
      report="no"
      export action="info"
      if [ -n "$2" ] ; then
        echo "$2" | egrep -q "^-.$"
        if [ "$?" != "0" ] ; then
          export project=$(shell_filter_strict $2)
          shift 2
        else
          shift
        fi
      else
        shift
      fi
    ;;
    todo)
      report="no"
      export action="todo"
      shift ;;
    -i)
      interactive="yes"
      shift ;;
    -f)
      force="yes"
      shift ;;
    -t)
      testmode="yes"
      runcommand="cat"
      shift ;;
    -o)
      options="$2"
      shift 2;;
    -d)
      debug="$(shell_filter_strict $2)"
      shift 2;;
    -r)
      report="$(shell_filter_strict $2)"
      shift 2;;
    -s)
      show="$(shell_filter_strict $2)"
      shift 2;;
    -c)
      counts="$(shell_filter_strict $2)"
      shift 2;;
    -g)
      greppattern="$(shell_filter_strict $2)"
      # greppattern="$(shell_filter $2)" # This allows partial regexp usage
      # greppattern="$2" # This allows full regexp usage but is highly insecure if you sudo puppi
      shift 2;;
    *)
      showhelp
      exit
      ;;
  esac
done

# Action!
case $action in 
    check) check ;;
    checkhost) check_host ;;
    log) create_runtime_conf ; log ;;
    info) create_runtime_conf ; info ;;
    todo) create_runtime_conf ; todo ;;
    rollback) create_runtime_conf ; rollback ;;
    deploy) create_runtime_conf ; deploy ;;
    init) create_runtime_conf ; initialize ;;
    configure) create_runtime_conf ; configure ;;
esac
#!/bin/bash
# This scripts cleans puppi log files older than <%= scope.lookupvar('puppi::logs_retention_days') %>
seconds=$(( (RANDOM%60+1)*60 ))
sleep $seconds

if [ "<%= scope.lookupvar('puppi::params::logdir') %>" == "/" ] || [ "x<%= scope.lookupvar('puppi::params::logdir') %>" == "x" ]; then
  exit 1
fi
find <%= scope.lookupvar('puppi::params::logdir') %> -type f -mtime +<%= scope.lookupvar('puppi::logs_retention_days') %> -exec rm '{}' '+' >/dev/null 2>&1
find <%= scope.lookupvar('puppi::params::logdir') %> -type d -mtime +<%= scope.lookupvar('puppi::logs_retention_days') %> -exec rmdir '{}' '+' >/dev/null 2>&1
#!/bin/bash
# Script generated by Puppet. It's executed when you run:
# puppi todo <%= name %>
#
# Sources common header for Puppi scripts
. <%= scope.lookupvar('puppi::params::scriptsdir') %>/header || exit 10

echo_title "$HOSTNAME - <%= name %>"

<% if @description != "" -%>
cat <<EOF
<%= @description %>
EOF
<% end -%>

<% if @notes != "" -%>
cat <<EOF
<%= @notes %>
EOF
<% end -%>

<% if @run != "" -%>
<% array_run.each do |cmd| %>show_command "<%= cmd -%>"
<% end -%>
<% end -%>

<% if @check_command != "" -%>
<%= @check_command %>
if [ "x$?" = "x0" ] ; then
    echo_success
    result="OK"
else
    echo_failure
    result="CRITICAL"
    EXITCRIT="1"
fi
<% else -%>
echo_warning
result="WARNING"
EXITWARN="1"
<% end -%>

fixtures:
  repositories:
    stdlib:
        "repo": "git://github.com/puppetlabs/puppetlabs-stdlib.git"
        "ref": "3.2.1"
    vcsrepo: "git://github.com/puppetlabs/puppetlabs-vcsrepo.git"
  symlinks:
    apache: "#{source_dir}"
language: ruby
bundler_args: --without development debug acceptance
script: "bundle exec rake lint"
rvm:
  - 1.8.7
  - 1.9.3
env:
  matrix:
    - PUPPET_GEM_VERSION="~> 3.4.0"
    - PUPPET_GEM_VERSION="~> 3.5.0"
matrix:
  fast_finish: true
notifications:
  email: false
source 'https://rubygems.org'
if puppetversion = ENV['PUPPET_GEM_VERSION']
  gem 'puppet', puppetversion
else
  gem 'puppet', '~> 3.5'
end

group :development, :test do
    gem 'puppetlabs_spec_helper' , '~> 0.4.1'
    gem 'puppet-lint'
end

group :debug do
    gem 'pry'
end

group :acceptance do
    gem 'beaker-rspec'
    gem 'serverspec'
end
Copyright 2014 Daniele Sluijters

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
name 'daenney-pyenv'
version 'master'
source 'git://github.com/daenney/puppet-pyenv.git'
author 'daenney'
license 'Apache 2.0'
summary 'Puppet module for pyenv'
description 'Install and manage Pythons with pyenv'
project_page 'https://github.com/daenney/puppet-pyenv'

## Add dependencies, if any:
dependency 'puppetlabs/stdlib', '>= 3.2.1'
dependency 'puppetlabs/vcsrepo', '>= 0.2.0'
# pyenv

[Pyenv](https://github.com/yyuu/pyenv) provides a way to build and use
Pythons outside of your platforms package manager's purview.

#### Table of contents

1. [Overview - What is the pyenv module?](#overview)
2. [Module description - What is the purpose of this mdoule?](#module-description)
3. [Setup - The basics of getting started with pyenv](#setup)
    * [Beginning with pyenv - Installation](#beginning-with-pyenv)
    * [Installing a Python - Basic options for getting started](#installing-a-python)
    * [Relocating pyenv](#relocating-the-pyenv-installation)
4. [Usage - The classes and types available for configuration](#usage)
    * [Classes](#classes)
        * [Class: pyenv](#class-pyenv)
    * [Types](#types)
        * [Type: pyenv_python](#type-pyenv_python)

## Overview
The pyenv module allows you to install pyenv on a target system. The module
also provides a Puppet type called `pyenv_python` which will instruct pyenv
to build a Python for you.

This module only supports global installations of pyenv, meaning it will not
install into a user's home directory. Though it can be made to do so the types
that come with it do not support this work flow.

## Module description
Python is a often-used programming language ranging from simple scripts to
automate a repetitive task to powering large (web) applications. The problem we
often encounter is that a distribution only ships with one (outdated) Python
version. Pyenv remedies this situation by allow you to build your own Pythons
and use those instead.

## Setup
This modules will:

* Install pyenv for you. It will do so by checking out the latest tag at the
  time this module was written;
* Symlink pyenv so that it will be found when looking through `$PATH`;
* Install the necessary packages to ensure you can build Python;
* A type and provider to make Puppet build Pythons through pyenv.

This module requires:

* [puppetlabs/stdlib](https://forge.puppetlabs.com/puppetlabs/stdlib)
* [puppetlabs/vcsrepo](https://forge.puppetlabs.com/puppetlabs/vcsrepo)

### Beginning with pyenv
In order to install pyenv with the defaults:

```puppet
include ::pyenv
```

This will install pyenv for you in `/usr/local/pyenv` and symlink
`/usr/local/bin/pyenv` to `/usr/local/pyenv/bin/pyenv`.

### Installing a Python
Use the `pyenv_python` type to instruct Puppet to build a Python:

```puppet
pyenv_python { '3.4.0': }
```

The `pyenv_python` defaults to `ensure => present,`, therefor you do not need to
specify it yourself.

If you want to build a debug version of a Python add *-debug* to the name of
the Python:

```puppet
pyenv_python { '3.4.0-debug': }
```

### Relocation the pyenv installation
The module installs pyenv to `/usr/local/pyenv` by default and symlinks the
`pyenv` binary onto your path. This is needed so that the provider can find
`pyenv` and set up the `PYENV_ROOT` environment variable accordingly.

If you change the location of the pyenv checkout you must either:

* Make sure the symlink is changed too. This is done automatically if you
 set `symlink_pyenv` to true;
* Create a custom Fact called `pyenv_binary` with the location of
 `/path/to/checkout/bin/pyenv`.

The former of the two methods is preferred if at all possible.

If Puppet's `$PATH` does not by default include `/usr/local/bin` either add
that to it or change the `symlink_path` to a different location that is part of
Puppet's `$PATH`.

## Usage

### Classes and defined types

#### Class: `pyenv`
The pyenv module's primary and only class, `pyenv` sets up your system with pyenv
and the necessary packages to compile.

It takes the following parameters:

* `ensure_repo`: Whether to add or remove the repository
    * default: `present`
    * options: `present`, `absent`
* `repo_location`: Where to checkout the repository on the filesystem
    * default: `/usr/local/pyenv`
    * options: any absolute path
* `repo_revision`: The revision to checkout
    * default: `v0.4.0-20140404`
    * options: tag, commit SHA, branch
* `symlink_pyenv`: Create a symlink to the pyenv binary
    * default: `true`
    * options: `true`, `false`
* `symlink_path`: Where to symlink pyenv to
    * default: `/usr/local/bin`
    * options: any absolute path known to `$PATH`
* `manage_packages`: Install packages needed to compile Python
    * default: `true`
    * options: `true`, `false`
* `ensure_packages`: State of the packages to ensure
    * default: `latest`
    * options: any valid value for the ensure attribute of the package type
* `python_build_packages`: Array/list of packages to install
    * default: depends on what Facter returns for `osfamily`, see
      (params.pp)[params.pp]
    * options: an array of strings representing package names

### Types

#### Type: `pyenv_python`

`pyenv_python` allows you to build a Python which in turn will make it
available to someone wishing to use it.

It takes the following options:

* `name` (namevar): name of the Python to be installed, see `pyenv install -l`.
  If omitted the title of the resource will be used.
* `ensure`: state the Python should be in
    * default: `present`
    * options: valid values for ensure
* `keep`: keep the sources after compiling
    * default: `false`
    * options: `true`, `false`
* `virtualenv`: Install virtualenv in the new Python
    * default: `false`
    * options: `true`, `false`

Keep one thing in mind: if a Python was installed **without** setting `keep` to
`true` you cannot add it later, the provider will call the `fail()` method in
such cases.
require 'puppet-lint/tasks/puppet-lint'

# Be extremely pedantic
PuppetLint.configuration.fail_on_warnings = true

# Disable some idiotic checks
PuppetLint.configuration.send('disable_class_inherits_from_params_class')
PuppetLint.configuration.send('disable_class_parameter_defaults')
PuppetLint.configuration.send('disable_documentation')
require 'puppet/util/feature'

Puppet.features.add(:pyenv) {
  if not Facter.value('pyenv_binary').nil?
    File.executable?(Facter.value('pyenv_binary'))
  else
    true
  end
}
require 'pathname'
require 'fileutils'
require 'puppet/util'

Puppet::Type.type(:pyenv_python).provide(:pyenv) do

  defaultfor :feature => :posix
  confine :feature => :pyenv

  if not Facter.value(:pyenv_binary).nil?
    has_command(:pyenv, Facter.value(:pyenv_binary)) do
      PYENV_ROOT = File.dirname(File.dirname(Pathname.new(Facter.value(:pyenv_binary)).realpath.to_s))
      environment({ 'PYENV_ROOT' => PYENV_ROOT })
    end
  else
    has_command(:pyenv, 'pyenv') do
      WHICH = Puppet::Util.which('pyenv')
      PYENV_ROOT = WHICH ? File.dirname(File.dirname(Pathname.new(WHICH).realpath.to_s)) : '/usr/local/pyenv/'
      environment({ 'PYENV_ROOT' => PYENV_ROOT })
    end
  end

  def self.instances
    python_versions = pyenv('versions').split("\n").collect do |line|
      python_version = parse_line(line)
      next unless python_version

      # Yes Symbols instead of Booleans because we get Symbols from Puppet when
      # we use the virtualenv property. This is madness!
      virtualenv = :false
      if File.exists?("#{PYENV_ROOT}/versions/#{python_version}/bin/virtualenv")
        virtualenv = :true
      end

      # Yes Symbols instead of Booleans because we get Symbols from Puppet when
      # we use the keep property. This is madness!
      keep = :false
      if File.exists?("#{PYENV_ROOT}/sources/#{python_version}")
        keep = :true
      end

      new(
        :name       => python_version,
        :ensure     => :present,
        :virtualenv => virtualenv,
        :keep       => keep
      )
    end
    python_versions.compact!
  end

  def self.prefetch(resources)
    python_versions = instances
    resources.keys.each do |name|
      if provider = python_versions.find{ |key| key.name == name }
        resources[name].provider = provider
      end
    end
  end

  def self.parse_line(line)
    parsed = line.match(/([\w.-]{3,})/).to_a
    # We don't care about the system python so ignore that.
    # If we happen to have a .python-version in the current directory that
    # points to a Python which isn't installed a line with:
    # pyenv: version `whatever' is not installed end up in the output which we
    # want to ignore.
    if parsed[0] == 'system' or parsed[0] == 'pyenv'
      return nil
    else
      return parsed[0]
    end
  end

  def exists?
    @property_hash[:ensure] == :present
  end

  def create
    command = ['install']
    # Yes Symbols instead of Booleans because we get Symbols from Puppet when
    # we use the force or resource parameters. This is madness!
    if resource[:keep] == :true
      command.push('--keep')
    end
    if resource[:name].split('-').last == 'debug'
      command.push('--debug')
      command.push(resource[:name].split('-')[0..-1])
    else
      command.push(resource[:name])
    end
    notice("Going to build #{resource[:name]}. This may take some time...")
    pyenv(command)
    @property_hash[:ensure] = :present
    pyenv('rehash')
  end

  def destroy
    # the -f is needed to avoid user input prompt
    pyenv('uninstall', '-f', resource[:name])
    @property_hash.clear
    pyenv('rehash')
  end

  mk_resource_methods

  def virtualenv=(install)
    # Yes Symbols instead of Booleans because we get Symbols from Puppet when
    # we use the virtualenv property. This is madness!
    if install == :true and virtualenv == :false
      command = ["#{PYENV_ROOT}/versions/#{resource[:name]}/bin/pip",
                 'install', '-q', 'virtualenv', '>/dev/null 2>&1']
      `#{command.join(' ')}`
      if $?.success?
        @property_hash[:virtualenv] = :true
      else
        fail('failed to install virtualenv')
      end
      pyenv('rehash')
    elsif install == :false and virtualenv == :true
      command = ["#{PYENV_ROOT}/versions/#{resource[:name]}/bin/pip",
                 'uninstall', '-q', '-y', 'virtualenv', '>/dev/null 2>&1']
      `#{command.join(' ')}`
      if $?.success?
        @property_hash[:virtualenv] = :false
      else
        fail('failed to uninstall virtualenv')
      end
      pyenv('rehash')
    else
      # We can never hit this block as the newvalues on the virtualenv property
      # should prevent us from getting here in the first place. However, this
      # is Puppet so you never know.
      fail('go home puppet, you\'re drunk')
    end
  end

  def keep=(value)
    # Yes Symbols instead of Booleans because we get Symbols from Puppet when
    # we use the keep property. This is madness!
    if not keep and value == :true
      fail('cannot keep source of an already installed Python')
    elsif keep and value == :false
      FileUtils.rm_rf("#{PYENV_ROOT}/sources/#{resource[:name]}")
      @property_hash[:keep] = :false
    else
      # We can never hit this block as the newvalues on the keep property
      # should prevent us from getting here in the first place. However, this
      # is Puppet so you never know.
      fail('go home puppet, you\'re drunk')
    end
  end
end
Puppet::Type.newtype(:pyenv_python) do

  @doc = <<-EOS
    This type provides Puppet with the capabilities to manage Pythons by
    leveraging pyenv. Pyenv automatically installs pip for you.

    pyenv_python { '3.4.0':
      ensure => 'present',
    }

    If you want to build a debug version of a Python add '-debug' to the
    resource name/title.

    Should you also want to install virtualenv in your new Python:

    pyenv_python { '2.7.6':
      ensure     => 'present',
      virtualenv => true,
    }

  EOS

  ensurable do
    defaultvalues
    defaultto :present
  end

  newparam(:name, :namevar => true) do
    desc 'The Python that should be installed'
    newvalues(/[\w.-]{3,}/)
  end

  newproperty(:keep) do
    desc 'Keep source tree in $PYENV_ROOT/sources after installation'
    newvalues(true, false)
    defaultto false
  end

  newproperty(:virtualenv) do
    desc 'Keep source tree in $PYENV_ROOT/sources after installation'
    newvalues(true, false)
    defaultto false
  end

end
class pyenv(
  $ensure_repo           = 'present',
  $repo_location         = '/usr/local/pyenv',
  $repo_revision         = 'v0.4.0-20140404',
  $symlink_pyenv         = true,
  $symlink_path          = '/usr/local/bin',
  $manage_packages       = true,
  $ensure_packages       = 'latest',
  $python_build_packages = $::pyenv::params::python_build_packages,
) inherits ::pyenv::params {

  validate_absolute_path($repo_location)
  validate_re($ensure_repo, ['present', 'absent'])
  validate_string($repo_revision)
  validate_bool($symlink_pyenv)
  validate_absolute_path($symlink_path)
  validate_bool($manage_packages)
  validate_array($python_build_packages)

  vcsrepo { $repo_location:
    ensure   => $ensure_repo,
    owner    => 0,
    group    => 0,
    provider => 'git',
    source   => 'https://github.com/yyuu/pyenv.git',
    revision => $repo_revision,
  }

  if $symlink_path {
    file { "${symlink_path}/pyenv":
      target => "${repo_location}/bin/pyenv",
    }
  }

  if $manage_packages {
    if empty($python_build_packages) {
      warn('You have requested to install packages but
      $python_build_packages is empty')
    } else {
      package { $python_build_packages:
        ensure => $ensure_packages,
      }
    }
  }
}
class pyenv::params {
  case $::osfamily {
    'Debian': {
      $python_build_packages = [ 'make', 'build-essential', 'libssl-dev',
                                'zlib1g-dev', 'libbz2-dev', 'libreadline-dev',
                                'libsqlite3-dev', 'wget', 'curl', 'llvm']
    }
    'Redhat': {
      $python_build_packages = ['zlib-devel', 'bzip2', 'bzip2-devel',
                                'readline-devel', 'sqlite', 'sqlite-devel',
                                'openssl-devel']
    }
    default: {
      $python_build_packages = []
    }
  }

}
{
  "operatingsystem_support": [
    {
      "operatingsystem": "RedHat",
      "operatingsystemrelease": [
        "5",
        "6"
      ]
    },
    {
      "operatingsystem": "CentOS",
      "operatingsystemrelease": [
        "5",
        "6"
      ]
    },
    {
      "operatingsystem": "Debian",
      "operatingsystemrelease": [
        "6",
        "7"
      ]
    },
    {
      "operatingsystem": "Ubuntu",
      "operatingsystemrelease": [
        "10.04",
        "12.04"
      ]
    }
  ],
  "requirements": [
    {
      "name": "pe",
      "version_requirement": "3.2.x"
    },
    {
      "name": "puppet",
      "version_requirement": "3.x"
    }
  ],
  "name": "puppetlabs-ntp",
  "version": "3.0.3",
  "source": "git://github.com/puppetlabs/puppetlabs-ntp",
  "author": "Puppet Labs",
  "license": "Apache Version 2.0",
  "summary": "NTP Module",
  "description": "NTP Module for Debian, Ubuntu, CentOS, RHEL, OEL, Fedora, FreeBSD, ArchLinux and Gentoo.",
  "project_page": "http://github.com/puppetlabs/puppetlabs-ntp",
  "dependencies": [
    {
      "name": "puppetlabs/stdlib",
      "version_requirement": ">= 0.1.6"
    }
  ]
}
fixtures:
  repositories:
    "stdlib": "git://github.com/puppetlabs/puppetlabs-stdlib.git"
    "apt": "git://github.com/puppetlabs/puppetlabs-apt.git"
    "staging": "git://github.com/nanliu/puppet-staging.git"
    erlang:
      repo: "https://github.com/garethr/garethr-erlang.git"
  symlinks:
    "rabbitmq": "#{source_dir}"
default_set: 'centos-64-x64'
sets:
  'centos-59-x64':
    nodes:
      "main.foo.vm":
        prefab: 'centos-59-x64'
  'centos-64-x64':
    nodes:
      "main.foo.vm":
        prefab: 'centos-64-x64'
  'fedora-18-x64':
    nodes:
      "main.foo.vm":
        prefab: 'fedora-18-x64'
  'debian-607-x64':
    nodes:
      "main.foo.vm":
        prefab: 'debian-607-x64'
  'debian-70rc1-x64':
    nodes:
      "main.foo.vm":
        prefab: 'debian-70rc1-x64'
  'ubuntu-server-10044-x64':
    nodes:
      "main.foo.vm":
        prefab: 'ubuntu-server-10044-x64'
  'ubuntu-server-12042-x64':
    nodes:
      "main.foo.vm":
        prefab: 'ubuntu-server-12042-x64'
  'sles-11sp1-x64':
    nodes:
      "main.foo.vm":
        prefab: 'sles-11sp1-x64'
branches:
  only:
    - master
language: ruby
bundler_args: --without development
script: bundle exec rake spec SPEC_OPTS='--format documentation'
after_success:
  - git clone -q git://github.com/puppetlabs/ghpublisher.git .forge-releng
  - .forge-releng/publish
rvm:
  - 1.8.7
  - 1.9.3
  - 2.0.0
  - 2.1.1
env:
  matrix:
    - PUPPET_GEM_VERSION="~> 2.7.0" FACTER_GEM_VERSION="~> 1.7.0"
    - PUPPET_GEM_VERSION="~> 3.4.0"
    - PUPPET_GEM_VERSION="~> 3.5.0"
  global:
    - PUBLISHER_LOGIN=puppetlabs
    - secure: |-
        mSHk+9ReN6wxJ9sOgySOSKEjaXOdtT9B1BtvsOGcm/FQI3p57meid3B6z37r\nNv9PbxwGb
        mcZafMxNAfwr8nUb/bqxeXnZaGiY0E9pvg9aRr3g4knczn+siW+\nDkKlvM0rex2zzF0PDc
        495e61kP5cxcKNVdDJSiUPPK6fNGQ1xX8=
matrix:
  exclude:
    - rvm: 1.9.3
      env: PUPPET_GEM_VERSION="~> 2.7.0" FACTER_GEM_VERSION="~> 1.7.0"
    - rvm: 2.0.0
      env: PUPPET_GEM_VERSION="~> 2.7.0" FACTER_GEM_VERSION="~> 1.7.0"
    - rvm: 2.1.1
      env: PUPPET_GEM_VERSION="~> 2.7.0" FACTER_GEM_VERSION="~> 1.7.0"
    - rvm: 2.1.1
      env: PUPPET_GEM_VERSION="~> 3.4.0"
notifications:
  email: false
2014-05-16 - Version 4.0.0

Summary:

This release includes many new features and bug fixes.  With the exception of
erlang management this should be backwards compatible with 3.1.0.

Backwards-incompatible Changes:
- erlang_manage was removed.  You will need to manage erlang separately. See
the README for more information on how to configure this.

Features:
- Improved SSL support
- Add LDAP support
- Add ability to manage RabbitMQ repositories
- Add ability to manage Erlang kernel configuration options
- Improved handling of user tags
- Use nanliu-staging module instead of hardcoded 'curl'
- Switch to yum or zypper provider instead of rpm
- Add ability to manage STOMP plugin installation.
- Allow empty permission fields
- Convert existing system tests to beaker acceptance tests.

Bugfixes:
- exchanges no longer recreated on each puppet run if non-default vhost is used
- Allow port to be UNSET
- Re-added rabbitmq::server class
- Deprecated previously unused manage_service variable in favor of 
  service_manage
- Use correct key for rabbitmq apt::source
- config_mirrored_queues variable removed
  - It previously did nothing, will now at least throw a warning if you try to
    use it
- Remove unnecessary dependency on Class['rabbitmq::repo::rhel'] in
  rabbitmq::install


2013-09-14 - Version 3.1.0

Summary:

This release focuses on a few small (but critical) bugfixes as well as extends
the amount of custom RabbitMQ configuration you can do with the module.

Features:
- You can now change RabbitMQ 'Config Variables' via the parameter `config_variables`.
- You can now change RabbitMQ 'Environment Variables' via the parameter `environment_variables`.
- ArchLinux support added.

Fixes:
- Make use of the user/password parameters in rabbitmq_exchange{}
- Correct the read/write parameter order on set_permissions/list_permissions as
  they were reversed.
- Make the module pull down 3.1.5 by default.

* 2013-07-18 3.0.0
Summary:
This release heavily refactors the RabbitMQ and changes functionality in
several key ways.  Please pay attention to the new README.md file for
details of how to interact with the class now.  Puppet 3 and RHEL are
now fully supported.  The default version of RabbitMQ has changed to
a 3.x release.

Bugfixes:
- Improve travis testing options.
- Stop reimporting the GPG key on every run on RHEL and Debian.
- Fix documentation to make it clear you don't have to set provider => each time.
- Reference the standard rabbitmq port in the documentation instead of a custom port.
- Fixes to the README formatting.

Features:
- Refactor the module to fix RHEL support.  All interaction with the module
is now done through the main rabbitmq class.
- Add support for mirrored queues (Only on Debian family distributions currently)
- Add rabbitmq_exchange provider (using rabbitmqadmin)
- Add new `rabbitmq` class parameters:
  - `manage_service`: Boolean to choose if Puppet should manage the service. (For pacemaker/HA setups)
- Add SuSE support.

Incompatible Changes:
- Rabbitmq::server has been removed and is now rabbitmq::config.  You should
not use this class directly, only via the main rabbitmq class.

* 2013-04-11 2.1.0
- remove puppetversion from rabbitmq.config template
- add cluster support
- escape resource names in regexp

* 2012-07-31 Jeff McCune <jeff@puppetlabs.com> 2.0.2
- Re-release 2.0.1 with $EDITOR droppings cleaned up

* 2012-05-03 2.0.0
- added support for new-style admin users
- added support for rabbitmq 2.7.1

* 2011-06-14 Dan Bode <dan@Puppetlabs.com> 2.0.0rc1
- Massive refactor:
- added native types for user/vhost/user_permissions
- added apt support for vendor packages
- added smoke tests

* 2011-04-08 Jeff McCune <jeff@puppetlabs.com> 1.0.4
- Update module for RabbitMQ 2.4.1 and rabbitmq-plugin-stomp package.

2011-03-24 1.0.3
- Initial release to the forge.  Reviewed by Cody.  Whitespace is good.

2011-03-22 1.0.2
- Whitespace only fix again...  ack '\t' is my friend...

2011-03-22 1.0.1
- Whitespace only fix.

2011-03-22 1.0.0
- Initial Release.  Manage the package, file and service.
source 'https://rubygems.org'

group :development, :test do
  gem 'rake', '10.1.1',          :require => false
  gem 'rspec-puppet', '>=1.0.0', :require => false
  gem 'puppetlabs_spec_helper',  :require => false
  gem 'puppet-lint',             :require => false
  gem 'serverspec',              :require => false
  gem 'beaker',                  :require => false
  gem 'beaker-rspec',            :require => false
  gem 'pry',                     :require => false
end

if facterversion = ENV['FACTER_GEM_VERSION']
  gem 'facter', facterversion, :require => false
else
  gem 'facter', :require => false
end

if puppetversion = ENV['PUPPET_GEM_VERSION']
  gem 'puppet', puppetversion, :require => false
else
  gem 'puppet', :require => false
end

# vim:ft=ruby
                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!) The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright 2013 Puppet Labs

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
name    'puppetlabs-rabbitmq'
version '4.0.0'
source 'git://github.com/puppetlabs/puppetlabs-rabbitmq.git'
author 'puppetlabs'
license 'Apache'
summary 'RabbitMQ Puppet Module'
description 'This module manages RabbitMQ. Tested on Debian, Ubuntu, and RedHat'
project_page 'http://github.com/puppetlabs/puppetlabs-rabbitmq'

## Add dependencies, if any:
dependency 'puppetlabs/stdlib', '>= 2.0.0'
dependency 'puppetlabs/apt', '>= 1.0.0'
dependency 'nanliu/staging', '>= 0.3.1'
#rabbitmq

####Table of Contents

1. [Overview](#overview)
2. [Module Description - What the module does and why it is useful](#module-description)
3. [Setup - The basics of getting started with rabbitmq](#setup)
    * [What rabbitmq affects](#what-rabbitmq-affects)
    * [Setup requirements](#setup-requirements)
    * [Beginning with rabbitmq](#beginning-with-rabbitmq)
4. [Usage - Configuration options and additional functionality](#usage)
5. [Reference - An under-the-hood peek at what the module is doing and how](#reference)
5. [Limitations - OS compatibility, etc.](#limitations)
   * [RedHat module dependencies](#redhat-module-dependecies)
6. [Development - Guide for contributing to the module](#development)

##Overview

This module manages RabbitMQ (www.rabbitmq.com)

##Module Description
The rabbitmq module sets up rabbitmq and has a number of providers to manage
everything from vhosts to exchanges after setup.

This module has been tested against 2.7.1 and is known to not support
all features against earlier versions.

##Setup

###What rabbitmq affects

* rabbitmq repository files.
* rabbitmq package.
* rabbitmq configuration file.
* rabbitmq service.

###Beginning with rabbitmq

```puppet
include '::rabbitmq'
```

##Usage

All options and configuration can be done through interacting with the parameters
on the main rabbitmq class.  These are documented below.

##rabbitmq class

To begin with the rabbitmq class controls the installation of rabbitmq.  In here
you can control many parameters relating to the package and service, such as
disabling puppet support of the service:

```puppet
class { '::rabbitmq':
  service_manage    => false,
  port              => '5672',
  delete_guest_user => true,
}
```

### Environment Variables
To use RabbitMQ Environment Variables, use the parameters `environment_variables` e.g.:

```puppet
class { 'rabbitmq':
  port              => '5672',
  environment_variables   => {
    'RABBITMQ_NODENAME'     => 'node01',
    'RABBITMQ_SERVICENAME'  => 'RabbitMQ'
  }
}
```

### Variables Configurable in rabbitmq.config
To change RabbitMQ Config Variables in rabbitmq.config, use the parameters `config_variables` e.g.:

```puppet
class { 'rabbitmq':
  port              => '5672',
  config_variables   => {
    'hipe_compile'  => true,
    'frame_max'     => 131072,
    'log_levels'    => "[{connection, info}]"
  }
}
```

To change Erlang Kernel Config Variables in rabbitmq.config, use the parameters
`config_kernel_variables` e.g.:

```puppet
class { 'rabbitmq':
  port              => '5672',
  config_kernel_variables  => {
    'inet_dist_listen_min' => 9100,
    'inet_dist_listen_max' => 9105,
  }
}
```

### Clustering
To use RabbitMQ clustering facilities, use the rabbitmq parameters
`config_cluster`, `cluster_nodes`, and `cluster_node_type`, e.g.:

```puppet
class { 'rabbitmq':
  config_cluster    => true,
  cluster_nodes     => ['rabbit1', 'rabbit2'],
  cluster_node_type => 'ram',
}
```

**NOTE:** If you are using a version of RabbitMQ less than 3.0,
you still need to use `x-ha-policy: all` in your client
applications for any particular queue to take advantage of H/A via
mirrored queues.

If you are using a version of RabbitMQ >= 3.0 You should set the
'config_mirrored_queues' parameter if you plan
on using RabbitMQ Mirrored Queues within your cluster:

```puppet
class { 'rabbitmq':
  config_cluster         => true,
  config_mirrored_queues => true,
  cluster_nodes          => ['rabbit1', 'rabbit2'],
}
```

##Reference

##Classes

* rabbitmq: Main class for installation and service management.
* rabbitmq::config: Main class for rabbitmq configuration/management.
* rabbitmq::install: Handles package installation.
* rabbitmq::params: Different configuration data for different systems.
* rabbitmq::service: Handles the rabbitmq service.
* rabbitmq::repo::apt: Handles apt repo for Debian systems.
* rabbitmq::repo::rhel: Handles yum repo for Redhat systems.

###Parameters

####`admin_enable`

If enabled sets up the management interface/plugin for RabbitMQ.

####`cluster_disk_nodes`

DEPRECATED AND REPLACED BY CLUSTER_NODES.

####`cluster_node_type`

Choose between disk and ram nodes.

####`cluster_nodes`

An array of nodes for clustering.

####`config`

The file to use as the rabbitmq.config template.

####`config_cluster`

Boolean to enable or disable clustering support.

####`config_mirrored_queues`

DEPRECATED

Configuring queue mirroring should be done by setting the according policy for
the queue. You can read more about it
[here](http://www.rabbitmq.com/ha.html#genesis)

####`config_path`

The path to write the RabbitMQ configuration file to.

####`config_stomp`

Boolean to enable or disable stomp.

####`delete_guest_user`

Boolean to decide if we should delete the default guest user.

####`env_config`

The template file to use for rabbitmq_env.config.

####`env_config_path`

The path to write the rabbitmq_env.config file to.

####`erlang_cookie`

The erlang cookie to use for clustering - must be the same between all nodes.

####`config_variables`

To set config variables in rabbitmq.config

####`node_ip_address`

The value of RABBITMQ_NODE_IP_ADDRESS in rabbitmq_env.config

####`environment_variables`

RabbitMQ Environment Variables in rabbitmq_env.config

####`package_ensure`

Determines the ensure state of the package.  Set to installed by default, but could
be changed to latest.

####`package_name`

The name of the package to install.

####`package_provider`

What provider to use to install the package.

####`package_source`

Where should the package be installed from?

####`plugin_dir`

Location of RabbitMQ plugins.

####`port`

The RabbitMQ port.

####`management_port`

The port for the RabbitMQ management interface.

####`service_ensure`

The state of the service.

####`service_manage`

Determines if the service is managed.

####`service_name`

The name of the service to manage.

####`ssl`

Configures the service for using SSL.

####`ssl_only`

Configures the service to only use SSL.  No cleartext TCP listeners will be created.
Requires that ssl => true also.

####`stomp_port`

The port to use for Stomp.

####`stomp_ensure`

Boolean to install the stomp plugin.

####`wipe_db_on_cookie_change`

Boolean to determine if we should DESTROY AND DELETE the RabbitMQ database.

####`version`

Sets the version to install.

##Native Types

### rabbitmq\_user

query all current users: `$ puppet resource rabbitmq_user`

```
rabbitmq_user { 'dan':
  admin    => true,
  password => 'bar',
}
```
Optional parameter tags will set further rabbitmq tags like monitoring, policymaker, etc.
To set the administrator tag use admin-flag.
```puppet
rabbitmq_user { 'dan':
  admin    => true,
  password => 'bar',
  tags     => ['monitoring', 'tag1'],
}
```


### rabbitmq\_vhost

query all current vhosts: `$ puppet resource rabbitmq_vhost`

```puppet
rabbitmq_vhost { 'myhost':
  ensure => present,
}
```

### rabbitmq\_exchange

```puppet
rabbitmq_exchange { 'myexchange@myhost':
  user     => 'dan',
  password => 'bar',
  type     => 'topic',
  ensure   => present,
}
```

### rabbitmq\_user\_permissions

```puppet
rabbitmq_user_permissions { 'dan@myhost':
  configure_permission => '.*',
  read_permission      => '.*',
  write_permission     => '.*',
}
```

### rabbitmq\_plugin

query all currently enabled plugins `$ puppet resource rabbitmq_plugin`

```puppet
rabbitmq_plugin {'rabbitmq_stomp':
  ensure => present,
}
```

##Limitations

This module has been built on and tested against Puppet 2.7 and higher.

The module has been tested on:

* RedHat Enterprise Linux 5/6
* Debian 6/7
* CentOS 5/6
* Ubuntu 12.04

Testing on other platforms has been light and cannot be guaranteed.

### Module dependencies
To have a suitable erlang version installed on RedHat and Debian systems,
you have to install another puppet module from http://forge.puppetlabs.com/garethr/erlang with:

    puppet module install garethr-erlang

This module handles the packages for erlang.
To use the module, add the following snippet to your site.pp or an appropriate profile class:

For RedHat systems:

    include 'erlang'
    class { 'erlang': epel_enable => true}

For Debian systems:

    include 'erlang'
    package { 'erlang-base':
      ensure => 'latest',
    }

##Development

Puppet Labs modules on the Puppet Forge are open projects, and community
contributions are essential for keeping them great. We can’t access the
huge number of platforms and myriad of hardware, software, and deployment
configurations that Puppet is intended to serve.

We want to keep it as easy as possible to contribute changes so that our
modules work in your environment. There are a few guidelines that we need
contributors to follow so that we can have a chance of keeping on top of things.

You can read the complete module contribution guide [on the Puppet Labs wiki.](http://projects.puppetlabs.com/projects/module-site/wiki/Module_contributing)

### Authors
* Jeff McCune <jeff@puppetlabs.com>
* Dan Bode <dan@puppetlabs.com>
* RPM/RHEL packages by Vincent Janelle <randomfrequency@gmail.com>
* Puppetlabs Module Team
require 'puppetlabs_spec_helper/rake_tasks'
require 'puppet-lint/tasks/puppet-lint'

PuppetLint.configuration.fail_on_warnings
PuppetLint.configuration.send('disable_80chars')
PuppetLint.configuration.send('disable_class_inherits_from_params_class')
PuppetLint.configuration.send('disable_class_parameter_defaults')
PuppetLint.configuration.send('disable_documentation')
PuppetLint.configuration.send('disable_single_quote_string_with_variables')
PuppetLint.configuration.ignore_paths = ["spec/**/*.pp", "pkg/**/*.pp"]
provider TODO -
  - password should be a property and not a param
     - what if we tried to log in as that user?
  - can permissions from list_user_permissions contain whitespace?
  - what about defaultfor :true?
  - prefetching for performance
  - rabbit plugin should require rabbitmq class
  - rabbitmq class should be renamed server??
  - service name should default to -server
  - cannot find stomp package
Files
=====

Puppet comes with both a client and server for copying files around. The file
serving function is provided as part of the central Puppet daemon,
puppetmasterd, and the client function is used through the source attribute of
file objects. Learn more at
http://projects.puppetlabs.com/projects/puppet/wiki/File_Serving_Configuration

You can use managed files like this:

    class myclass {
      package { mypackage: ensure => latest }
      service { myservice: ensure => running }
      file { "/etc/myfile":
        source => "puppet://$servername/modules/mymodule/myfile"
      }
    }

The files are searched for in:

    $modulepath/mymodule/files/myfile
# Fact: rabbitmq_erlang_cookie
#
# Purpose: To determine the current erlang cookie value.
#
# Resolution: Returns the cookie.
Facter.add(:rabbitmq_erlang_cookie) do
  confine :osfamily => %w[Debian RedHat Suse]

  setcode do
    if File.exists?('/var/lib/rabbitmq/.erlang.cookie')
      File.read('/var/lib/rabbitmq/.erlang.cookie')
    else
      nil
    end
  end
end
require 'puppet'
Puppet::Type.type(:rabbitmq_exchange).provide(:rabbitmqadmin) do

  commands :rabbitmqctl => '/usr/sbin/rabbitmqctl'
  has_command(:rabbitmqadmin, '/usr/local/bin/rabbitmqadmin') do
    environment( { 'HOME' => '' })
  end
  defaultfor :feature => :posix

  def should_vhost
    if @should_vhost
      @should_vhost
    else
      @should_vhost = resource[:name].split('@')[1]
    end
  end

  def self.all_vhosts
    vhosts = []
    parse_command(rabbitmqctl('list_vhosts')).collect do |vhost|
        vhosts.push(vhost)
    end
    vhosts
  end

  def self.all_exchanges(vhost)
    exchanges = []
    parse_command(rabbitmqctl('list_exchanges', '-p', vhost, 'name', 'type'))
  end

  def self.parse_command(cmd_output)
    # first line is:
    # Listing exchanges/vhosts ...
    # while the last line is
    # ...done.
    #
    cmd_output.split(/\n/)[1..-2]
  end

  def self.instances
    resources = []
    all_vhosts.each do |vhost|
        all_exchanges(vhost).collect do |line|
            name, type = line.split()
            if type.nil?
                # if name is empty, it will wrongly get the type's value.
                # This way type will get the correct value
                type = name
                name = ''
            end
            exchange = {
              :type   => type,
              :ensure => :present,
              :name   => "%s@%s" % [name, vhost],
            }
            resources << new(exchange) if exchange[:type]
        end
    end
    resources
  end

  def self.prefetch(resources)
    packages = instances
    resources.keys.each do |name|
      if provider = packages.find{ |pkg| pkg.name == name }
        resources[name].provider = provider
      end
    end
  end

  def exists?
    @property_hash[:ensure] == :present
  end

  def create
    vhost_opt = should_vhost ? "--vhost=#{should_vhost}" : ''
    name = resource[:name].split('@')[0]
    rabbitmqadmin('declare', 'exchange', vhost_opt, "--user=#{resource[:user]}", "--password=#{resource[:password]}", "name=#{name}", "type=#{resource[:type]}")
    @property_hash[:ensure] = :present
  end

  def destroy
    vhost_opt = should_vhost ? "--vhost=#{should_vhost}" : ''
    name = resource[:name].split('@')[0]
    rabbitmqadmin('delete', 'exchange', vhost_opt, "--user=#{resource[:user]}", "--password=#{resource[:password]}", "name=#{name}")
    @property_hash[:ensure] = :absent
  end

end
Puppet::Type.type(:rabbitmq_plugin).provide(:rabbitmqplugins) do

  if Puppet::PUPPETVERSION.to_f < 3
    if Facter.value(:osfamily) == 'RedHat'
      commands :rabbitmqplugins => '/usr/lib/rabbitmq/bin/rabbitmq-plugins'
    else
      commands :rabbitmqplugins => 'rabbitmq-plugins'
    end
  else
    if Facter.value(:osfamily) == 'RedHat'
      has_command(:rabbitmqplugins, '/usr/lib/rabbitmq/bin/rabbitmq-plugins') do
        environment :HOME => "/tmp"
      end
    else
      has_command(:rabbitmqplugins, 'rabbitmq-plugins') do
        environment :HOME => "/tmp"
      end
    end
  end

  defaultfor :feature => :posix

  def self.instances
    rabbitmqplugins('list', '-E').split(/\n/).map do |line|
      if line.split(/\s+/)[1] =~ /^(\S+)$/
        new(:name => $1)
      else
        raise Puppet::Error, "Cannot parse invalid plugins line: #{line}"
      end
    end
  end

  def create
    rabbitmqplugins('enable', resource[:name])
  end

  def destroy
    rabbitmqplugins('disable', resource[:name])
  end

  def exists?
    rabbitmqplugins('list', '-E').split(/\n/).detect do |line|
      line.split(/\s+/)[1].match(/^#{resource[:name]}$/)
    end
  end

end
require 'puppet'
require 'set'
Puppet::Type.type(:rabbitmq_user).provide(:rabbitmqctl) do

  if Puppet::PUPPETVERSION.to_f < 3
    commands :rabbitmqctl => 'rabbitmqctl'
  else
     has_command(:rabbitmqctl, 'rabbitmqctl') do
       environment :HOME => "/tmp"
     end
  end

  defaultfor :feature => :posix

  def self.instances
    rabbitmqctl('list_users').split(/\n/)[1..-2].collect do |line|
      if line =~ /^(\S+)(\s+\[.*?\]|)$/
        new(:name => $1)
      else
        raise Puppet::Error, "Cannot parse invalid user line: #{line}"
      end
    end
  end

  def create
    rabbitmqctl('add_user', resource[:name], resource[:password])
    if resource[:admin] == :true
      make_user_admin()
    end
    if !resource[:tags].nil?
      set_user_tags(resource[:tags])
    end
  end

  def destroy
    rabbitmqctl('delete_user', resource[:name])
  end

  def exists?
    rabbitmqctl('list_users').split(/\n/)[1..-2].detect do |line|
      line.match(/^#{Regexp.escape(resource[:name])}(\s+(\[.*?\]|\S+)|)$/)
    end
  end

 
  def tags
    get_user_tags.entries.sort
  end


  def tags=(tags)
    if ! tags.nil?
      set_user_tags(tags)
    end
  end

  def admin
    if usertags = get_user_tags
      (:true if usertags.include?('administrator')) || :false
    else
      raise Puppet::Error, "Could not match line '#{resource[:name]} (true|false)' from list_users (perhaps you are running on an older version of rabbitmq that does not support admin users?)"
    end
  end

  def admin=(state)
    if state == :true
      make_user_admin()
    else
      usertags = get_user_tags
      usertags.delete('administrator')
      rabbitmqctl('set_user_tags', resource[:name], usertags.entries.sort)
    end
  end

  def set_user_tags(tags)
    is_admin = get_user_tags().member?("administrator") \
               || resource[:admin] == :true
    usertags = Set.new(tags)
    if is_admin
      usertags.add("administrator")
    end
    rabbitmqctl('set_user_tags', resource[:name], usertags.entries.sort)
  end

  def make_user_admin
    usertags = get_user_tags
    usertags.add('administrator')
    rabbitmqctl('set_user_tags', resource[:name], usertags.entries.sort)
  end

  private
  def get_user_tags
    match = rabbitmqctl('list_users').split(/\n/)[1..-2].collect do |line|
      line.match(/^#{Regexp.escape(resource[:name])}\s+\[(.*?)\]/)
    end.compact.first
    Set.new(match[1].split(/, /)) if match
  end
end
Puppet::Type.type(:rabbitmq_user_permissions).provide(:rabbitmqctl) do

  if Puppet::PUPPETVERSION.to_f < 3
    commands :rabbitmqctl => 'rabbitmqctl'
  else
     has_command(:rabbitmqctl, 'rabbitmqctl') do
       environment :HOME => "/tmp"
     end
  end

  defaultfor :feature=> :posix

  # cache users permissions
  def self.users(name, vhost)
    @users = {} unless @users
    unless @users[name]
      @users[name] = {}
      rabbitmqctl('list_user_permissions', name).split(/\n/)[1..-2].each do |line|
        if line =~ /^(\S+)\s+(\S*)\s+(\S*)\s+(\S*)$/
          @users[name][$1] =
            {:configure => $2, :read => $4, :write => $3}
        else
          raise Puppet::Error, "cannot parse line from list_user_permissions:#{line}"
        end
      end
    end
    @users[name][vhost]
  end

  def users(name, vhost)
    self.class.users(name, vhost)
  end

  def should_user
    if @should_user
      @should_user
    else
      @should_user = resource[:name].split('@')[0]
    end
  end

  def should_vhost
    if @should_vhost
      @should_vhost
    else
      @should_vhost = resource[:name].split('@')[1]
    end
  end

  def create
    resource[:configure_permission] ||= "''"
    resource[:read_permission]      ||= "''"
    resource[:write_permission]     ||= "''"
    rabbitmqctl('set_permissions', '-p', should_vhost, should_user, resource[:configure_permission], resource[:write_permission], resource[:read_permission]) 
  end

  def destroy
    rabbitmqctl('clear_permissions', '-p', should_vhost, should_user)
  end

  # I am implementing prefetching in exists b/c I need to be sure
  # that the rabbitmq package is installed before I make this call.
  def exists?
    users(should_user, should_vhost)
  end

  def configure_permission
    users(should_user, should_vhost)[:configure]
  end

  def configure_permission=(perm)
    set_permissions
  end

  def read_permission
    users(should_user, should_vhost)[:read]
  end

  def read_permission=(perm)
    set_permissions
  end

  def write_permission
    users(should_user, should_vhost)[:write]
  end

  def write_permission=(perm)
    set_permissions
  end

  # implement memoization so that we only call set_permissions once
  def set_permissions
    unless @permissions_set
      @permissions_set = true
      resource[:configure_permission] ||= configure_permission
      resource[:read_permission]      ||= read_permission
      resource[:write_permission]     ||= write_permission
      rabbitmqctl('set_permissions', '-p', should_vhost, should_user,
        resource[:configure_permission], resource[:write_permission],
        resource[:read_permission]
      )
    end
  end

end
Puppet::Type.type(:rabbitmq_vhost).provide(:rabbitmqctl) do

  if Puppet::PUPPETVERSION.to_f < 3
    commands :rabbitmqctl => 'rabbitmqctl'
  else
     has_command(:rabbitmqctl, 'rabbitmqctl') do
       environment :HOME => "/tmp"
     end
  end

  def self.instances
    rabbitmqctl('list_vhosts').split(/\n/)[1..-2].map do |line|
      if line =~ /^(\S+)$/
        new(:name => $1)
      else
        raise Puppet::Error, "Cannot parse invalid user line: #{line}"
      end
    end
  end

  def create
    rabbitmqctl('add_vhost', resource[:name])
  end

  def destroy
    rabbitmqctl('delete_vhost', resource[:name])
  end

  def exists?
    out = rabbitmqctl('list_vhosts').split(/\n/)[1..-2].detect do |line|
      line.match(/^#{Regexp.escape(resource[:name])}$/)
    end
  end

end
Puppet::Type.newtype(:rabbitmq_exchange) do
  desc 'Native type for managing rabbitmq exchanges'

  ensurable do
    defaultto(:present)
    newvalue(:present) do
      provider.create
    end
    newvalue(:absent) do
      provider.destroy
    end
  end

  newparam(:name, :namevar => true) do
    desc 'Name of exchange'
    newvalues(/^\S*@\S+$/)
  end

  newparam(:type) do
    desc 'Exchange type to be set *on creation*'
    newvalues(/^\S+$/)
  end

  newparam(:user) do
    desc 'The user to use to connect to rabbitmq'
    defaultto('guest')
    newvalues(/^\S+$/)
  end

  newparam(:password) do
    desc 'The password to use to connect to rabbitmq'
    defaultto('guest')
    newvalues(/\S+/)
  end

  validate do
    if self[:ensure] == :present and self[:type].nil?
      raise ArgumentError, "must set type when creating exchange for #{self[:name]} whose type is #{self[:type]}"
    end
  end

  autorequire(:rabbitmq_vhost) do
    [self[:name].split('@')[1]]
  end

  autorequire(:rabbitmq_user) do
    [self[:user]]
  end

  autorequire(:rabbitmq_user_permissions) do
    ["#{self[:user]}@#{self[:name].split('@')[1]}"]
  end

end
Puppet::Type.newtype(:rabbitmq_plugin) do
  desc 'manages rabbitmq plugins'

  ensurable do
    defaultto(:present)
    newvalue(:present) do
      provider.create
    end
    newvalue(:absent) do
      provider.destroy
    end
  end

  newparam(:name, :namevar => true) do
    'name of the plugin to enable'
    newvalues(/^\S+$/)
  end

end
Puppet::Type.newtype(:rabbitmq_user) do
  desc 'Native type for managing rabbitmq users'

  ensurable do
    defaultto(:present)
    newvalue(:present) do
      provider.create
    end
    newvalue(:absent) do
      provider.destroy
    end
  end

  autorequire(:service) { 'rabbitmq-server' }

  newparam(:name, :namevar => true) do
    desc 'Name of user'
    newvalues(/^\S+$/)
  end

  # newproperty(:password) do
  newparam(:password) do
    desc 'User password to be set *on creation*'
  end

  newproperty(:admin) do
    desc 'rather or not user should be an admin'
    newvalues(/true|false/)
    munge do |value|
      # converting to_s incase its a boolean
      value.to_s.to_sym
    end
    defaultto :false
  end

  newproperty(:tags, :array_matching => :all) do
    desc 'additional tags for the user'
  end

  validate do
    if self[:ensure] == :present and ! self[:password]
      raise ArgumentError, 'must set password when creating user' unless self[:password]
    end
  end

end
Puppet::Type.newtype(:rabbitmq_user_permissions) do
  desc 'Type for managing rabbitmq user permissions'

  ensurable do
    defaultto(:present)
    newvalue(:present) do
      provider.create
    end
    newvalue(:absent) do
      provider.destroy
    end
  end

  autorequire(:service) { 'rabbitmq-server' }

  newparam(:name, :namevar => true) do
    desc 'combination of user@vhost to grant privileges to'
    newvalues(/^\S+@\S+$/)
  end

  newproperty(:configure_permission) do
    desc 'regexp representing configuration permissions'
    validate do |value|
      resource.validate_permissions(value)
    end
  end

  newproperty(:read_permission) do
    desc 'regexp representing read permissions'
    validate do |value|
      resource.validate_permissions(value)
    end
  end

  newproperty(:write_permission) do
    desc 'regexp representing write permissions'
    validate do |value|
      resource.validate_permissions(value)
    end
  end

  autorequire(:rabbitmq_vhost) do
    [self[:name].split('@')[1]]
  end

  autorequire(:rabbitmq_user) do
    [self[:name].split('@')[0]]
  end

  # I may want to dissalow whitespace
  def validate_permissions(value)
    begin
      Regexp.new(value)
    rescue RegexpError
      raise ArgumentError, "Invalid regexp #{value}"
    end
  end

end
Puppet::Type.newtype(:rabbitmq_vhost) do
  desc 'manages rabbitmq vhosts'

  ensurable do
    defaultto(:present)
    newvalue(:present) do
      provider.create
    end
    newvalue(:absent) do
      provider.destroy
    end
  end

  newparam(:name, :namevar => true) do
    'name of the vhost to add'
    newvalues(/^\S+$/)
  end

end
class rabbitmq::config {

  $cluster_disk_nodes         = $rabbitmq::cluster_disk_nodes
  $cluster_node_type          = $rabbitmq::cluster_node_type
  $cluster_nodes              = $rabbitmq::cluster_nodes
  $config                     = $rabbitmq::config
  $config_cluster             = $rabbitmq::config_cluster
  $config_path                = $rabbitmq::config_path
  $config_stomp               = $rabbitmq::config_stomp
  $default_user               = $rabbitmq::default_user
  $default_pass               = $rabbitmq::default_pass
  $env_config                 = $rabbitmq::env_config
  $env_config_path            = $rabbitmq::env_config_path
  $erlang_cookie              = $rabbitmq::erlang_cookie
  $node_ip_address            = $rabbitmq::node_ip_address
  $plugin_dir                 = $rabbitmq::plugin_dir
  $port                       = $rabbitmq::port
  $service_name               = $rabbitmq::service_name
  $ssl                        = $rabbitmq::ssl
  $ssl_only                   = $rabbitmq::ssl_only
  $ssl_cacert                 = $rabbitmq::ssl_cacert
  $ssl_cert                   = $rabbitmq::ssl_cert
  $ssl_key                    = $rabbitmq::ssl_key
  $ssl_management_port        = $rabbitmq::ssl_management_port
  $ssl_stomp_port             = $rabbitmq::ssl_stomp_port
  $ssl_verify                 = $rabbitmq::ssl_verify
  $ssl_fail_if_no_peer_cert   = $rabbitmq::ssl_fail_if_no_peer_cert
  $stomp_port                 = $rabbitmq::stomp_port
  $wipe_db_on_cookie_change   = $rabbitmq::wipe_db_on_cookie_change
  $config_variables           = $rabbitmq::config_variables
  $config_kernel_variables    = $rabbitmq::config_kernel_variables
  $cluster_partition_handling = $rabbitmq::cluster_partition_handling
  $default_env_variables      =  {
    'RABBITMQ_NODE_PORT'        => $port,
    'RABBITMQ_NODE_IP_ADDRESS'  => $node_ip_address
  }

  # Handle env variables.
  $environment_variables = merge($default_env_variables, $rabbitmq::environment_variables)

  # Handle deprecated option.
  if $cluster_disk_nodes != [] {
    notify { 'cluster_disk_nodes':
      message => 'WARNING: The cluster_disk_nodes is deprecated.
       Use cluster_nodes instead.',
    }
    $r_cluster_nodes = $cluster_disk_nodes
  } else {
    $r_cluster_nodes = $cluster_nodes
  }

  file { '/etc/rabbitmq':
    ensure  => directory,
    owner   => '0',
    group   => '0',
    mode    => '0644',
  }

  file { '/etc/rabbitmq/ssl':
    ensure  => directory,
    owner   => '0',
    group   => '0',
    mode    => '0644',
  }

  file { 'rabbitmq.config':
    ensure  => file,
    path    => $config_path,
    content => template($config),
    owner   => '0',
    group   => '0',
    mode    => '0644',
    notify  => Class['rabbitmq::service'],
  }

  file { 'rabbitmq-env.config':
    ensure  => file,
    path    => $env_config_path,
    content => template($env_config),
    owner   => '0',
    group   => '0',
    mode    => '0644',
    notify  => Class['rabbitmq::service'],
  }


  if $config_cluster {

    file { 'erlang_cookie':
      ensure  => 'present',
      path    => '/var/lib/rabbitmq/.erlang.cookie',
      owner   => 'rabbitmq',
      group   => 'rabbitmq',
      mode    => '0400',
      content => $erlang_cookie,
      replace => true,
      before  => File['rabbitmq.config'],
      notify  => Class['rabbitmq::service'],
    }

    # rabbitmq_erlang_cookie is a fact in this module.
    if $erlang_cookie != $::rabbitmq_erlang_cookie {
      # Safety check.
      if $wipe_db_on_cookie_change {
        exec { 'wipe_db':
          command    => "puppet resource service ${service_name} ensure=stopped; rm -rf /var/lib/rabbitmq/mnesia",
          path       => '/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin',
        }
        File['erlang_cookie'] {
          require => Exec['wipe_db'],
        }
      } else {
        fail("ERROR: The current erlang cookie is ${::rabbitmq_erlang_cookie} and needs to change to ${erlang_cookie}. In order to do this the RabbitMQ database needs to be wiped.  Please set the parameter called wipe_db_on_cookie_change to true to allow this to happen automatically.")
      }
    }

  }


}

  #
class rabbitmq(
  $admin_enable               = $rabbitmq::params::admin_enable,
  $cluster_disk_nodes         = $rabbitmq::params::cluster_disk_nodes,
  $cluster_node_type          = $rabbitmq::params::cluster_node_type,
  $cluster_nodes              = $rabbitmq::params::cluster_nodes,
  $config                     = $rabbitmq::params::config,
  $config_cluster             = $rabbitmq::params::config_cluster,
  $config_mirrored_queues     = $rabbitmq::params::config_mirrored_queues,
  $config_path                = $rabbitmq::params::config_path,
  $config_stomp               = $rabbitmq::params::config_stomp,
  $default_user               = $rabbitmq::params::default_user,
  $default_pass               = $rabbitmq::params::default_pass,
  $delete_guest_user          = $rabbitmq::params::delete_guest_user,
  $env_config                 = $rabbitmq::params::env_config,
  $env_config_path            = $rabbitmq::params::env_config_path,
  $erlang_cookie              = $rabbitmq::params::erlang_cookie,
  $management_port            = $rabbitmq::params::management_port,
  $node_ip_address            = $rabbitmq::params::node_ip_address,
  $package_apt_pin            = $rabbitmq::params::package_apt_pin,
  $package_ensure             = $rabbitmq::params::package_ensure,
  $package_gpg_key            = $rabbitmq::params::package_gpg_key,
  $package_name               = $rabbitmq::params::package_name,
  $package_provider           = $rabbitmq::params::package_provider,
  $package_source             = $rabbitmq::params::package_source,
  $manage_repos               = $rabbitmq::params::manage_repos,
  $plugin_dir                 = $rabbitmq::params::plugin_dir,
  $port                       = $rabbitmq::params::port,
  $service_ensure             = $rabbitmq::params::service_ensure,
  $service_manage             = $rabbitmq::params::service_manage,
  $service_name               = $rabbitmq::params::service_name,
  $ssl                        = $rabbitmq::params::ssl,
  $ssl_only                   = $rabbitmq::params::ssl_only,
  $ssl_cacert                 = $rabbitmq::params::ssl_cacert,
  $ssl_cert                   = $rabbitmq::params::ssl_cert,
  $ssl_key                    = $rabbitmq::params::ssl_key,
  $ssl_management_port        = $rabbitmq::params::ssl_management_port,
  $ssl_stomp_port             = $rabbitmq::params::ssl_stomp_port,
  $ssl_verify                 = $rabbitmq::params::ssl_verify,
  $ssl_fail_if_no_peer_cert   = $rabbitmq::params::ssl_fail_if_no_peer_cert,
  $stomp_ensure               = $rabbitmq::params::stomp_ensure,
  $ldap_auth                  = $rabbitmq::params::ldap_auth,
  $ldap_server                = $rabbitmq::params::ldap_server,
  $ldap_user_dn_pattern       = $rabbitmq::params::ldap_user_dn_pattern,
  $ldap_use_ssl               = $rabbitmq::params::ldap_use_ssl,
  $ldap_port                  = $rabbitmq::params::ldap_port,
  $ldap_log                   = $rabbitmq::params::ldap_log,
  $stomp_port                 = $rabbitmq::params::stomp_port,
  $version                    = $rabbitmq::params::version,
  $wipe_db_on_cookie_change   = $rabbitmq::params::wipe_db_on_cookie_change,
  $cluster_partition_handling = $rabbitmq::params::cluster_partition_handling,
  $environment_variables      = $rabbitmq::params::environment_variables,
  $config_variables           = $rabbitmq::params::config_variables,
  $config_kernel_variables    = $rabbitmq::params::config_kernel_variables,
) inherits rabbitmq::params {

  validate_bool($admin_enable)
  # Validate install parameters.
  validate_re($package_apt_pin, '^(|\d+)$')
  validate_string($package_ensure)
  validate_string($package_gpg_key)
  validate_string($package_name)
  validate_string($package_provider)
  validate_bool($manage_repos)
  validate_re($version, '^\d+\.\d+\.\d+(-\d+)*$') # Allow 3 digits and optional -n postfix.
  # Validate config parameters.
  validate_array($cluster_disk_nodes)
  validate_re($cluster_node_type, '^(ram|disc)$')
  validate_array($cluster_nodes)
  validate_string($config)
  validate_absolute_path($config_path)
  validate_bool($config_cluster)
  validate_bool($config_mirrored_queues)
  validate_bool($config_stomp)
  validate_string($default_user)
  validate_string($default_pass)
  validate_bool($delete_guest_user)
  validate_string($env_config)
  validate_absolute_path($env_config_path)
  validate_string($erlang_cookie)
  validate_re($management_port, '\d+')
  validate_string($node_ip_address)
  validate_absolute_path($plugin_dir)
  validate_re($port, ['\d+','UNSET'])
  validate_re($stomp_port, '\d+')
  validate_bool($wipe_db_on_cookie_change)
  # Validate service parameters.
  validate_re($service_ensure, '^(running|stopped)$')
  validate_bool($service_manage)
  validate_string($service_name)
  validate_bool($ssl)
  validate_bool($ssl_only)
  validate_string($ssl_cacert)
  validate_string($ssl_cert)
  validate_string($ssl_key)
  validate_string($ssl_management_port)
  validate_re($ssl_management_port, '\d+')
  validate_string($ssl_stomp_port)
  validate_re($ssl_stomp_port, '\d+')
  validate_bool($stomp_ensure)
  validate_bool($ldap_auth)
  validate_string($ldap_server)
  validate_string($ldap_user_dn_pattern)
  validate_bool($ldap_use_ssl)
  validate_re($ldap_port, '\d+')
  validate_bool($ldap_log)
  validate_hash($environment_variables)
  validate_hash($config_variables)
  validate_hash($config_kernel_variables)

  if $ssl_only and ! $ssl {
    fail('$ssl_only => true requires that $ssl => true')
  }

  include '::rabbitmq::install'
  include '::rabbitmq::config'
  include '::rabbitmq::service'
  include '::rabbitmq::management'

  if $rabbitmq::manage_repos == true {
    case $::osfamily {
      'RedHat', 'SUSE':
        { include '::rabbitmq::repo::rhel' }
      'Debian':
        { include '::rabbitmq::repo::apt' }
      default:
        { }
    }
  }

  if $admin_enable and $service_manage {
    include '::rabbitmq::install::rabbitmqadmin'

    rabbitmq_plugin { 'rabbitmq_management':
      ensure  => present,
      require => Class['rabbitmq::install'],
      notify  => Class['rabbitmq::service'],
      provider => 'rabbitmqplugins'
    }

    Class['::rabbitmq::service'] -> Class['::rabbitmq::install::rabbitmqadmin']
  }

  if $stomp_ensure {
    rabbitmq_plugin { 'rabbitmq_stomp':
      ensure  => $stomp_ensure,
      require => Class['rabbitmq::install'],
      notify  => Class['rabbitmq::service'],
      provider => 'rabbitmqplugins'
    }
  }

  if ($ldap_auth) {
    rabbitmq_plugin { 'rabbitmq_auth_backend_ldap':
      ensure   => present,
      require  => Class['rabbitmq::install'],
      notify   => Class['rabbitmq::service'],
      provider => 'rabbitmqplugins',
    }
  }

  # Anchor this as per #8040 - this ensures that classes won't float off and
  # mess everything up.  You can read about this at:
  # http://docs.puppetlabs.com/puppet/2.7/reference/lang_containment.html#known-issues
  anchor { 'rabbitmq::begin': }
  anchor { 'rabbitmq::end': }

  Anchor['rabbitmq::begin'] -> Class['::rabbitmq::install']
    -> Class['::rabbitmq::config'] ~> Class['::rabbitmq::service']
    -> Class['::rabbitmq::management'] -> Anchor['rabbitmq::end']

  # Make sure the various providers have their requirements in place.
  Class['::rabbitmq::install'] -> Rabbitmq_plugin<| |>
  Class['::rabbitmq::install::rabbitmqadmin'] -> Rabbitmq_exchange<| |>

}
class rabbitmq::install {

  $package_ensure   = $rabbitmq::package_ensure
  $package_name     = $rabbitmq::package_name
  $package_provider = $rabbitmq::package_provider
  $package_source   = $rabbitmq::package_source

  package { 'rabbitmq-server':
    ensure   => $package_ensure,
    name     => $package_name,
    provider => $package_provider,
    notify   => Class['rabbitmq::service'],
  }

  if $package_source {
    Package['rabbitmq-server'] {
      source  => $package_source,
    }
  }

}
#
class rabbitmq::install::rabbitmqadmin {

  $management_port = $rabbitmq::management_port

  staging::file { 'rabbitmqadmin':
    target  => '/var/lib/rabbitmq/rabbitmqadmin',
    source  => "http://localhost:${management_port}/cli/rabbitmqadmin",
    require => [
      Class['rabbitmq::service'],
      Rabbitmq_plugin['rabbitmq_management']
    ],
  }

  file { '/usr/local/bin/rabbitmqadmin':
    owner   => 'root',
    group   => 'root',
    source  => '/var/lib/rabbitmq/rabbitmqadmin',
    mode    => '0755',
    require => Staging::File['rabbitmqadmin'],
  }

}
#
class rabbitmq::management {

  $delete_guest_user = $rabbitmq::delete_guest_user

  if $delete_guest_user {
    rabbitmq_user{ 'guest':
      ensure   => absent,
      provider => 'rabbitmqctl',
    }
  }

  if $rabbitmq::config_mirrored_queues {
    rabbitmq::policy { 'ha-all':
      pattern  => '.*',
      definition => '{"ha-mode":"all","ha-sync-mode":"automatic"}'
    }
  }
}
  # Class: rabbitmq::params
#
#   The RabbitMQ Module configuration settings.
#
class rabbitmq::params {

  case $::osfamily {
    'Archlinux': {
      $package_ensure   = 'installed'
      $package_name     = 'rabbitmq'
      $service_name     = 'rabbitmq'
      $package_source   = ''
      $version          = '3.1.3-1'
      $base_version     = regsubst($version,'^(.*)-\d$','\1')
      # This must remain at the end as we need $base_version and $version defined first
    }
    'Debian': {
      $package_ensure   = 'installed'
      $package_name     = 'rabbitmq-server'
      $service_name     = 'rabbitmq-server'
      $package_provider = 'apt'
      $package_source   = ''
      $version          = '3.1.5'
    }
    'RedHat': {
      $package_ensure   = 'installed'
      $package_name     = 'rabbitmq-server'
      $service_name     = 'rabbitmq-server'
      $package_provider = 'yum'
      $version          = '3.1.5-1'
      $base_version     = regsubst($version,'^(.*)-\d$','\1')
      # This must remain at the end as we need $base_version and $version defined first.
      $package_source   = "http://www.rabbitmq.com/releases/rabbitmq-server/v${base_version}/rabbitmq-server-${version}.noarch.rpm"
    }
    'SUSE': {
      $package_ensure   = 'installed'
      $package_name     = 'rabbitmq-server'
      $service_name     = 'rabbitmq-server'
      $package_provider = 'zypper'
      $version          = '3.1.5-1'
      $base_version     = regsubst($version,'^(.*)-\d$','\1')
      # This must remain at the end as we need $base_version and $version defined first.
      $package_source   = "http://www.rabbitmq.com/releases/rabbitmq-server/v${base_version}/rabbitmq-server-${version}.noarch.rpm"
    }
    default: {
      fail("The ${module_name} module is not supported on an ${::osfamily} based system.")
    }
  }

  #install
  $admin_enable               = true
  $management_port            = '15672'
  $package_apt_pin            = ''
  $package_gpg_key            = 'http://www.rabbitmq.com/rabbitmq-signing-key-public.asc'
  $manage_repos               = true
  $service_ensure             = 'running'
  $service_manage             = true
  #config
  $cluster_disk_nodes         = []
  $cluster_node_type          = 'disc'
  $cluster_nodes              = []
  $config                     = 'rabbitmq/rabbitmq.config.erb'
  $config_cluster             = false
  $config_mirrored_queues     = false
  $config_path                = '/etc/rabbitmq/rabbitmq.config'
  $config_stomp               = false
  $default_user               = 'guest'
  $default_pass               = 'guest'
  $delete_guest_user          = false
  $env_config                 = 'rabbitmq/rabbitmq-env.conf.erb'
  $env_config_path            = '/etc/rabbitmq/rabbitmq-env.conf'
  $erlang_cookie              = 'EOKOWXQREETZSHFNTPEY'
  $node_ip_address            = 'UNSET'
  $plugin_dir                 = "/usr/lib/rabbitmq/lib/rabbitmq_server-${version}/plugins"
  $port                       = '5672'
  $ssl                        = false
  $ssl_only                   = false
  $ssl_cacert                 = 'UNSET'
  $ssl_cert                   = 'UNSET'
  $ssl_key                    = 'UNSET'
  $ssl_management_port        = '5671'
  $ssl_stomp_port             = '6164'
  $ssl_verify                 = 'verify_none'
  $ssl_fail_if_no_peer_cert   = 'false'
  $stomp_ensure               = false
  $ldap_auth                  = false
  $ldap_server                = 'ldap'
  $ldap_user_dn_pattern       = 'cn=${username},ou=People,dc=example,dc=com'
  $ldap_use_ssl               = false
  $ldap_port                  = '389'
  $ldap_log                   = false
  $stomp_port                 = '6163'
  $wipe_db_on_cookie_change   = false
  $cluster_partition_handling = 'ignore'
  $environment_variables      = {}
  $config_variables           = {}
  $config_kernel_variables    = {}
}
define rabbitmq::policy (
  $pattern,
  $definition,
  $vhost    = '/',
  $priority = 0,
) {

  exec { "rabbitmq policy: ${title}":
    command => "rabbitmqctl set_policy -p ${vhost} '${name}' '${pattern}' '${definition}' ${priority}",
    unless  => "rabbitmqctl list_policies | grep -qE '^${vhost}\\s+${name}\\s+${pattern}\\s+${definition}\\s+${priority}$'",
    path    => ['/bin','/sbin','/usr/bin','/usr/sbin'],
    require => Class['rabbitmq::service'],
    before  => Anchor['rabbitmq::end']
  }
}
# requires
#   puppetlabs-apt
#   puppetlabs-stdlib
class rabbitmq::repo::apt(
  $location    = 'http://www.rabbitmq.com/debian/',
  $release     = 'testing',
  $repos       = 'main',
  $include_src = false,
  $key         = '056E8E56',
  $key_source  = 'http://www.rabbitmq.com/rabbitmq-signing-key-public.asc',
  ) {

  $pin = $rabbitmq::package_apt_pin

  Class['rabbitmq::repo::apt'] -> Package<| title == 'rabbitmq-server' |>

  apt::source { 'rabbitmq':
    location    => $location,
    release     => $release,
    repos       => $repos,
    include_src => $include_src,
    key         => $key,
    key_source  => $key_source,
  }

  if $pin {
    validate_re($pin, '\d\d\d')
    apt::pin { 'rabbitmq':
      packages => 'rabbitmq-server',
      priority => $pin,
    }
  }
}
class rabbitmq::repo::rhel {

  $package_gpg_key = $rabbitmq::package_gpg_key

  Class['rabbitmq::repo::rhel'] -> Package<| title == 'rabbitmq-server' |>

  exec { "rpm --import ${package_gpg_key}":
    path   => ['/bin','/usr/bin','/sbin','/usr/sbin'],
    onlyif => 'test `rpm -qa | grep gpg-pubkey-056e8e56-468e43f2 | wc -l` -eq 0',
  }

}
# Class: rabbitmq::server
#
# This module manages the installation and config of the rabbitmq server
#   it has only been tested on certain version of debian-ish systems
# Parameters:
#  [*port*] - port where rabbitmq server is hosted
#  [*delete_guest_user*] - rather or not to delete the default user
#  [*version*] - version of rabbitmq-server to install
#  [*package_name*] - name of rabbitmq package
#  [*service_name*] - name of rabbitmq service
#  [*service_ensure*] - desired ensure state for service
#  [*stomp_port*] - port stomp should be listening on
#  [*node_ip_address*] - ip address for rabbitmq to bind to
#  [*config*] - contents of config file
#  [*env_config*] - contents of env-config file
#  [*config_cluster*] - whether to configure a RabbitMQ cluster
#  [*config_mirrored_queues*] - DEPRECATED (doesn't do anything)
#  [*cluster_disk_nodes*] - DEPRECATED (use cluster_nodes instead)
#  [*cluster_nodes*] - which nodes to cluster with (including the current one)
#  [*cluster_node_type*] - Type of cluster node (disc or ram)
#  [*erlang_cookie*] - erlang cookie, must be the same for all nodes in a cluster
#  [*wipe_db_on_cookie_change*] - whether to wipe the RabbitMQ data if the specified
#    erlang_cookie differs from the current one. This is a sad parameter: actually,
#    if the cookie indeed differs, then wiping the database is the *only* thing you
#    can do. You're only required to set this parameter to true as a sign that you
#    realise this.
# Requires:
#  stdlib
# Sample Usage:
#
# This module is used as backward compability layer for modules
# which require rabbitmq::server instead of rabbitmq class.
# It's still common uasge in many modules.
#
#
# [Remember: No empty lines between comments and class definition]
class rabbitmq::server(
  $port                     = $rabbitmq::params::port,
  $delete_guest_user        = $rabbitmq::params::delete_guest_user,
  $package_name             = $rabbitmq::params::package_name,
  $version                  = $rabbitmq::params::version,
  $service_name             = $rabbitmq::params::service_name,
  $service_ensure           = $rabbitmq::params::service_ensure,
  $service_manage           = $rabbitmq::params::service_manage,
  $config_stomp             = $rabbitmq::params::config_stomp,
  $stomp_port               = $rabbitmq::params::stomp_port,
  $config_cluster           = $rabbitmq::params::config_cluster,
  $cluster_disk_nodes       = $rabbitmq::params::cluster_disk_nodes,
  $cluster_nodes            = $rabbitmq::params::cluster_nodes,
  $cluster_node_type        = $rabbitmq::params::cluster_node_type,
  $node_ip_address          = $rabbitmq::params::node_ip_address,
  $config                   = $rabbitmq::params::config,
  $env_config               = $rabbitmq::params::env_config,
  $erlang_cookie            = $rabbitmq::params::erlang_cookie,
  $wipe_db_on_cookie_change = $rabbitmq::params::wipe_db_on_cookie_change,
  # DEPRECATED
  $manage_service           = undef,
  $config_mirrored_queues   = undef,
) inherits rabbitmq::params {

  if $manage_service != undef {
    warning('The $manage_service parameter is deprecated; please use $service_manage instead')
    $_service_manage = $manage_service
  } else {
    $_service_manage = $service_manage
  }

  if $config_mirrored_queues != undef {
    warning('The $config_mirrored_queues parameter is deprecated in this class, use the rabbitmq class')
  }

  anchor {'before::rabbimq::class':
    before => Class['rabbitmq'],
  }

  anchor {'after::rabbimq::class':
    require => Class['rabbitmq'],
  }

  class { 'rabbitmq':
    port                      => $port,
    delete_guest_user         => $delete_guest_user,
    package_name              => $package_name,
    version                   => $version,
    service_name              => $service_name,
    service_ensure            => $service_ensure,
    service_manage            => $_service_manage,
    config_stomp              => $config_stomp,
    stomp_port                => $stomp_port,
    config_cluster            => $config_cluster,
    cluster_disk_nodes        => $cluster_disk_nodes,
    cluster_nodes             => $cluster_nodes,
    cluster_node_type         => $cluster_node_type,
    node_ip_address           => $node_ip_address,
    config                    => $config,
    env_config                => $env_config,
    erlang_cookie             => $erlang_cookie,
    wipe_db_on_cookie_change  => $wipe_db_on_cookie_change,
  }
}
# Class: rabbitmq::service
#
#   This class manages the rabbitmq server service itself.
#
# Parameters:
#
# Actions:
#
# Requires:
#
# Sample Usage:
#
class rabbitmq::service(
  $service_ensure = $rabbitmq::service_ensure,
  $service_manage = $rabbitmq::service_manage,
  $service_name   = $rabbitmq::service_name,
) inherits rabbitmq {

  validate_re($service_ensure, '^(running|stopped)$')
  validate_bool($service_manage)

  if ($service_manage) {
    if $service_ensure == 'running' {
      $ensure_real = 'running'
      $enable_real = true
    } else {
      $ensure_real = 'stopped'
      $enable_real = false
    }

    service { 'rabbitmq-server':
      ensure     => $ensure_real,
      enable     => $enable_real,
      hasstatus  => true,
      hasrestart => true,
      name       => $service_name,
    }
  }

}
Specs
=====

The Puppet project uses RSpec for testing.

For more information on RSpec, see http://rspec.info/

require 'spec_helper_acceptance'

describe 'rabbitmq class:' do
  case fact('osfamily')
  when 'RedHat'
    package_name = 'rabbitmq-server'
    service_name = 'rabbitmq-server'
  when 'SUSE'
    package_name = 'rabbitmq-server'
    service_name = 'rabbitmq-server'
  when 'Debian'
    package_name = 'rabbitmq-server'
    service_name = 'rabbitmq-server'
  when 'Archlinux'
    package_name = 'rabbitmq'
    service_name = 'rabbitmq'
  end

  context "default class inclusion" do
    it 'should run successfully' do
      pp = <<-EOS
      class { 'rabbitmq': }
      if $::osfamily == 'RedHat' {
        class { 'erlang': epel_enable => true}
        Class['erlang'] -> Class['rabbitmq']
      }
      EOS

      # Apply twice to ensure no errors the second time.
      apply_manifest(pp, :catch_failures => true)
      expect(apply_manifest(pp, :catch_changes => true).exit_code).to be_zero
    end

    describe package(package_name) do
      it { should be_installed }      
    end

    describe service(service_name) do
      it { should be_enabled }
      it { should be_running }
    end
  end

  context "disable and stop service" do
    it 'should run successfully' do
      pp = <<-EOS
      class { 'rabbitmq':
        service_ensure => 'stopped',
      }
      if $::osfamily == 'RedHat' {
        class { 'erlang': epel_enable => true}
        Class['erlang'] -> Class['rabbitmq']
      }
      EOS

      apply_manifest(pp, :catch_failures => true)
    end

    describe service(service_name) do
      it { should_not be_enabled }
      it { should_not be_running }
    end
  end

  context "service is unmanaged" do
    it 'should run successfully' do
      pp_pre = <<-EOS
      class { 'rabbitmq': }
      if $::osfamily == 'RedHat' {
        class { 'erlang': epel_enable => true}
        Class['erlang'] -> Class['rabbitmq']
      }
      EOS

      pp = <<-EOS
      class { 'rabbitmq':
        service_manage => false,
        service_ensure  => 'stopped',
      }
      if $::osfamily == 'RedHat' {
        class { 'erlang': epel_enable => true}
        Class['erlang'] -> Class['rabbitmq']
      }
      EOS

      
      apply_manifest(pp_pre, :catch_failures => true)
      apply_manifest(pp, :catch_failures => true)
    end

    describe service(service_name) do
      it { should be_enabled }
      it { should be_running }
    end
  end
end
require 'spec_helper_acceptance'

describe 'rabbitmq clustering' do
  context 'rabbitmq::config_cluster => true' do
    it 'should run successfully' do
      pp = <<-EOS
      class { 'rabbitmq': 
        config_cluster           => true,
        cluster_nodes            => ['rabbit1', 'rabbit2'],
        cluster_node_type        => 'ram',
        wipe_db_on_cookie_change => true,
      }
      if $::osfamily == 'RedHat' {
        class { 'erlang': epel_enable => true}
        Class['erlang'] -> Class['rabbitmq']
      }
      EOS
 
      apply_manifest(pp, :catch_failures => true)
    end

    describe file('/etc/rabbitmq/rabbitmq.config') do
      it { should be_file }
      it { should contain 'cluster_nodes' }
      it { should contain 'rabbit@rabbit1' }
      it { should contain 'rabbit@rabbit2' }
      it { should contain 'ram' }
    end

    describe file('/var/lib/rabbitmq/.erlang.cookie') do
      it { should be_file }
    end
  end
end
require 'spec_helper_acceptance'

describe 'rabbitmq with delete_guest_user' do
  context 'delete_guest_user' do
    it 'should run successfully' do
      pp = <<-EOS
      class { 'rabbitmq': 
        port              => '5672',
        delete_guest_user => true,
      }
      if $::osfamily == 'RedHat' {
        class { 'erlang': epel_enable => true}
        Class['erlang'] -> Class['rabbitmq']
      }
      EOS

      apply_manifest(pp, :catch_failures => true)
      shell('rabbitmqctl list_users > /tmp/rabbitmqctl_users')
    end

    describe file('/tmp/rabbitmqctl_users') do
      it { should be_file }
      it { should_not contain 'guest' }
    end
  end
end
HOSTS:
  centos-64-x64:
    roles:
      - master
    platform: el-6-x86_64
    box : centos-64-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  log_level: debug
  type: git
HOSTS:
  ubuntu-server-1310-x64:
    roles:
      - master
    platform: ubuntu-13.10-amd64
    box : ubuntu-server-1310-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/ubuntu-1310-x64-virtualbox-nocm.box
    hypervisor : vagrant
CONFIG:
  log_level   : debug
  type: git
HOSTS:
  ubuntu-server-1404-x64:
    roles:
      - master
    platform: ubuntu-14.04-amd64
    box : trusty-server-cloudimg-amd64-vagrant-disk1
    box_url : https://cloud-images.ubuntu.com/vagrant/trusty/current/trusty-server-cloudimg-amd64-vagrant-disk1.box
    hypervisor : vagrant
CONFIG:
  log_level   : debug
  type: git
require 'spec_helper_acceptance'

describe 'rabbitmq::install::rabbitmqadmin class' do
  context 'does nothing if service is unmanaged' do
    it 'should run successfully' do
      pp = <<-EOS
      class { 'rabbitmq':
        admin_enable   => true,
        service_manage => false,
      }
      if $::osfamily == 'RedHat' {
        class { 'erlang': epel_enable => true}
        Class['erlang'] -> Class['rabbitmq']
      }
      EOS

      shell('rm -f /var/lib/rabbitmq/rabbitmqadmin')
      apply_manifest(pp, :catch_failures => true)
    end

    describe file('/var/lib/rabbitmq/rabbitmqadmin') do
      it { should_not be_file }
    end
  end

  context 'downloads the cli tools' do
    it 'should run successfully' do
      pp = <<-EOS
      class { 'rabbitmq':
        admin_enable   => true,
        service_manage => true,
      }
      if $::osfamily == 'RedHat' {
        class { 'erlang': epel_enable => true}
        Class['erlang'] -> Class['rabbitmq']
      }
      EOS

      apply_manifest(pp, :catch_failures => true)
    end

    describe file('/var/lib/rabbitmq/rabbitmqadmin') do
      it { should be_file }
    end
  end
end
require 'spec_helper_acceptance'

describe 'rabbitmq server:' do
  case fact('osfamily')
  when 'RedHat'
    package_name = 'rabbitmq-server'
    service_name = 'rabbitmq-server'
  when 'SUSE'
    package_name = 'rabbitmq-server'
    service_name = 'rabbitmq-server'
  when 'Debian'
    package_name = 'rabbitmq-server'
    service_name = 'rabbitmq-server'
  when 'Archlinux'
    package_name = 'rabbitmq'
    service_name = 'rabbitmq'
  end

  context "default class inclusion" do
    it 'should run successfully' do
      pp = <<-EOS
      class { 'rabbitmq::server': }
      if $::osfamily == 'RedHat' {
        class { 'erlang': epel_enable => true}
        Class['erlang'] -> Class['rabbitmq::server']
      }
      EOS

      # Apply twice to ensure no errors the second time.
      apply_manifest(pp, :catch_failures => true)
      expect(apply_manifest(pp, :catch_changes => true).exit_code).to be_zero
    end

    describe package(package_name) do
      it { should be_installed }      
    end

    describe service(service_name) do
      it { should be_enabled }
      it { should be_running }
    end
  end

  context "disable and stop service" do
    it 'should run successfully' do
      pp = <<-EOS
      class { 'rabbitmq::server':
        service_ensure => 'stopped',
      }
      if $::osfamily == 'RedHat' {
        class { 'erlang': epel_enable => true}
        Class['erlang'] -> Class['rabbitmq::server']
      }
      EOS

      apply_manifest(pp, :catch_failures => true)
    end

    describe service(service_name) do
      it { should_not be_enabled }
      it { should_not be_running }
    end
  end

  context "service is unmanaged" do
    it 'should run successfully' do
      pp_pre = <<-EOS
      class { 'rabbitmq::server': }
      if $::osfamily == 'RedHat' {
        class { 'erlang': epel_enable => true}
        Class['erlang'] -> Class['rabbitmq::server']
      }
      EOS

      pp = <<-EOS
      class { 'rabbitmq::server':
        service_manage => false,
        service_ensure  => 'stopped',
      }
      if $::osfamily == 'RedHat' {
        class { 'erlang': epel_enable => true}
        Class['erlang'] -> Class['rabbitmq::server']
      }
      EOS

      
      apply_manifest(pp_pre, :catch_failures => true)
      apply_manifest(pp, :catch_failures => true)
    end

    describe service(service_name) do
      it { should be_enabled }
      it { should be_running }
    end
  end
end
require 'spec_helper'

describe 'rabbitmq' do

  context 'on unsupported distributions' do
    let(:facts) {{ :osfamily => 'Unsupported' }}

    it 'we fail' do
      expect { subject }.to raise_error(/not supported on an Unsupported/)
    end
  end

  context 'on Debian' do
    let(:facts) {{ :osfamily => 'Debian', :lsbdistid => 'Debian', :lsbdistcodename => 'squeeze' }}
    it 'includes rabbitmq::repo::apt' do
      should contain_class('rabbitmq::repo::apt')
    end

    describe 'apt::source default values' do
      let(:facts) {{ :osfamily => 'Debian' }}
      it 'should add a repo with defaults values' do
        contain_file('/etc/apt/sources.list.d/rabbitmq.list')\
          .with_content(%r|deb http\://www\.rabbitmq.com/debian/ testing main|)
      end
    end

    describe 'apt::source custom values' do
      let(:params) {
        { :location => 'http://www.foorepo.com/debian',
          :release => 'unstable',
          :repos => 'main'
        }}
      it 'should add a repo with custom new values' do
        contain_file('/etc/apt/sources.list.d/rabbitmq.list')\
          .with_content(%r|deb http\://www\.foorepo.com/debian/ unstable main|)
      end
    end
  end

  context 'on Debian' do
    let(:params) {{ :manage_repos => false }}
    let(:facts) {{ :osfamily => 'Debian', :lsbdistid => 'Debian', :lsbdistcodename => 'squeeze' }}
    it 'does not include rabbitmq::repo::apt when manage_repos is false' do
      should_not contain_class('rabbitmq::repo::apt')
    end
  end

  context 'on Redhat' do
    let(:facts) {{ :osfamily => 'RedHat' }}
    it 'includes rabbitmq::repo::rhel' do
      should contain_class('rabbitmq::repo::rhel')
    end
  end

  context 'on Redhat' do
    let(:params) {{ :manage_repos => false }}
    let(:facts) {{ :osfamily => 'RedHat' }}
    it 'does not include rabbitmq::repo::rhel when manage_repos is false' do
      should_not contain_class('rabbitmq::repo::rhel')
    end
  end

  ['Debian', 'RedHat', 'SUSE', 'Archlinux'].each do |distro|
    context "on #{distro}" do
      let(:facts) {{
        :osfamily => distro,
        :rabbitmq_erlang_cookie => 'EOKOWXQREETZSHFNTPEY',
        :lsbdistcodename => 'squeeze',
        :lsbdistid => 'Debian'
      }}

      it { should contain_class('rabbitmq::install') }
      it { should contain_class('rabbitmq::config') }
      it { should contain_class('rabbitmq::service') }


      context 'with admin_enable set to true' do
        let(:params) {{ :admin_enable => true }}
        context 'with service_manage set to true' do
          it 'we enable the admin interface by default' do
            should contain_class('rabbitmq::install::rabbitmqadmin')
            should contain_rabbitmq_plugin('rabbitmq_management').with(
              'require' => 'Class[Rabbitmq::Install]',
              'notify'  => 'Class[Rabbitmq::Service]'
            )
          end
        end
        context 'with service_manage set to false' do
          let(:params) {{ :admin_enable => true, :service_manage => false }}
          it 'should do nothing' do
            should_not contain_class('rabbitmq::install::rabbitmqadmin')
            should_not contain_rabbitmq_plugin('rabbitmq_management')
          end
        end
      end

      context 'deprecated parameters' do
        describe 'cluster_disk_nodes' do
          let(:params) {{ :cluster_disk_nodes => ['node1', 'node2'] }}

          it { should contain_notify('cluster_disk_nodes') }
        end
      end

      describe 'manages configuration directory correctly' do
        it { should contain_file('/etc/rabbitmq').with(
          'ensure' => 'directory'
        )}
      end

      describe 'manages configuration file correctly' do
        it { should contain_file('rabbitmq.config') }
      end

      context 'configures config_cluster' do
        let(:facts) {{ :osfamily => distro, :rabbitmq_erlang_cookie => 'ORIGINAL', :lsbdistid => 'Debian' }}
        let(:params) {{
          :config_cluster           => true,
          :cluster_nodes            => ['hare-1', 'hare-2'],
          :cluster_node_type        => 'ram',
          :erlang_cookie            => 'TESTCOOKIE',
          :wipe_db_on_cookie_change => false
        }}

        describe 'with defaults' do
          it 'fails' do
            expect{subject}.to raise_error(/^ERROR: The current erlang cookie is ORIGINAL/)
          end
        end

        describe 'with wipe_db_on_cookie_change set' do
          let(:params) {{
            :config_cluster           => true,
            :cluster_nodes            => ['hare-1', 'hare-2'],
            :cluster_node_type        => 'ram',
            :erlang_cookie            => 'TESTCOOKIE',
            :wipe_db_on_cookie_change => true
          }}
          it 'wipes the database' do
            should contain_exec('wipe_db')
            should contain_file('erlang_cookie')
          end
        end

        describe 'correctly when cookies match' do
          let(:params) {{
            :config_cluster           => true,
            :cluster_nodes            => ['hare-1', 'hare-2'],
            :cluster_node_type        => 'ram',
            :erlang_cookie            => 'ORIGINAL',
            :wipe_db_on_cookie_change => true
          }}
          it 'and doesnt wipe anything' do
            should contain_file('erlang_cookie')
          end
        end

        describe 'and sets appropriate configuration' do
          let(:params) {{
            :config_cluster           => true,
            :cluster_nodes            => ['hare-1', 'hare-2'],
            :cluster_node_type        => 'ram',
            :erlang_cookie            => 'ORIGINAL',
            :wipe_db_on_cookie_change => true
          }}
          it 'for cluster_nodes' do
            should contain_file('rabbitmq.config').with({
              'content' => /cluster_nodes.*\['rabbit@hare-1', 'rabbit@hare-2'\], ram/,
            })
          end

          it 'for erlang_cookie' do
            should contain_file('erlang_cookie').with({
              'content' => 'ORIGINAL',
            })
          end
        end
      end

      describe 'rabbitmq-env configuration' do
        let(:params) {{ :environment_variables => {
          'RABBITMQ_NODE_IP_ADDRESS'    => '1.1.1.1',
          'RABBITMQ_NODE_PORT'          => '5656',
          'RABBITMQ_NODENAME'           => 'HOSTNAME',
          'RABBITMQ_SERVICENAME'        => 'RabbitMQ',
          'RABBITMQ_CONSOLE_LOG'        => 'RabbitMQ.debug',
          'RABBITMQ_CTL_ERL_ARGS'       => 'verbose',
          'RABBITMQ_SERVER_ERL_ARGS'    => 'v',
          'RABBITMQ_SERVER_START_ARGS'  => 'debug'
        }}}
        it 'should set environment variables' do
          should contain_file('rabbitmq-env.config') \
            .with_content(/RABBITMQ_NODE_IP_ADDRESS=1.1.1.1/) \
            .with_content(/RABBITMQ_NODE_PORT=5656/) \
            .with_content(/RABBITMQ_NODENAME=HOSTNAME/) \
            .with_content(/RABBITMQ_SERVICENAME=RabbitMQ/) \
            .with_content(/RABBITMQ_CONSOLE_LOG=RabbitMQ.debug/) \
            .with_content(/RABBITMQ_CTL_ERL_ARGS=verbose/) \
            .with_content(/RABBITMQ_SERVER_ERL_ARGS=v/) \
            .with_content(/RABBITMQ_SERVER_START_ARGS=debug/)
        end
      end

      context 'delete_guest_user' do
        describe 'should do nothing by default' do
          it { should_not contain_rabbitmq_user('guest') }
        end

        describe 'delete user when delete_guest_user set' do
          let(:params) {{ :delete_guest_user => true }}
          it 'removes the user' do
            should contain_rabbitmq_user('guest').with(
              'ensure'   => 'absent',
              'provider' => 'rabbitmqctl'
            )
          end
        end
      end

      context 'configuration setting' do
        describe 'node_ip_address when set' do
          let(:params) {{ :node_ip_address => '172.0.0.1' }}
          it 'should set RABBITMQ_NODE_IP_ADDRESS to specified value' do
            contain_file('rabbitmq-env.config').with({
              'content' => 'RABBITMQ_NODE_IP_ADDRESS=172.0.0.1',
            })
          end
        end

        describe 'stomp by default' do
          it 'should not specify stomp parameters in rabbitmq.config' do
            contain_file('rabbitmq.config').without({
              'content' => /stomp/,})
          end
        end
        describe 'stomp when set' do
          let(:params) {{ :config_stomp => true, :stomp_port => 5679 }}
          it 'should specify stomp port in rabbitmq.config' do
            contain_file('rabbitmq.config').with({
              'content' => /rabbitmq_stomp.*tcp_listeners, \[5679\]/,
            })
          end
        end
        describe 'stomp when set with ssl' do
          let(:params) {{ :config_stomp => true, :stomp_port => 5679, :ssl_stomp_port => 5680 }}
          it 'should specify stomp port and ssl stomp port in rabbitmq.config' do
            contain_file('rabbitmq.config').with({
              'content' => /rabbitmq_stomp.*tcp_listeners, \[5679\].*ssl_listeners, \[5680\]/,
            })
          end
        end
      end

      describe 'configuring ldap authentication' do
        let :params do
          { :config_stomp         => true,
            :ldap_auth            => true,
            :ldap_server          => 'ldap.example.com',
            :ldap_user_dn_pattern => 'ou=users,dc=example,dc=com',
            :ldap_use_ssl         => false,
            :ldap_port            => '389',
            :ldap_log             => true
          }
        end

        it { should contain_rabbitmq_plugin('rabbitmq_auth_backend_ldap') }

        it 'should contain ldap parameters' do
          verify_contents(subject, 'rabbitmq.config', 
                          ['[', '  {rabbit, [', '    {auth_backends, [rabbit_auth_backend_internal, rabbit_auth_backend_ldap]},', '  ]}',
                            '  {rabbitmq_auth_backend_ldap, [', '    {other_bind, anon},',
                            '    {servers, ["ldap.example.com"]},',
                            '    {user_dn_pattern, "ou=users,dc=example,dc=com"},', '    {use_ssl, false},',
                            '    {port, 389},', '    {log, true}'])
        end
      end

      describe 'configuring ldap authentication' do
        let :params do
          { :config_stomp         => false,
            :ldap_auth            => true,
            :ldap_server          => 'ldap.example.com',
            :ldap_user_dn_pattern => 'ou=users,dc=example,dc=com',
            :ldap_use_ssl         => false,
            :ldap_port            => '389',
            :ldap_log             => true
          }
        end

        it { should contain_rabbitmq_plugin('rabbitmq_auth_backend_ldap') }

        it 'should contain ldap parameters' do
          verify_contents(subject, 'rabbitmq.config', 
                          ['[', '  {rabbit, [', '    {auth_backends, [rabbit_auth_backend_internal, rabbit_auth_backend_ldap]},', '  ]}',
                            '  {rabbitmq_auth_backend_ldap, [', '    {other_bind, anon},',
                            '    {servers, ["ldap.example.com"]},',
                            '    {user_dn_pattern, "ou=users,dc=example,dc=com"},', '    {use_ssl, false},',
                            '    {port, 389},', '    {log, true}'])
        end
      end

      describe 'default_user and default_pass set' do
        let(:params) {{ :default_user => 'foo', :default_pass => 'bar' }}
        it 'should set default_user and default_pass to specified values' do
          contain_file('rabbitmq.config').with({
            'content' => /default_user, <<"foo">>.*default_pass, <<"bar">>/,
          })
        end
      end

      describe 'ssl options' do
        let(:params) {
          { :ssl => true,
            :ssl_management_port => 3141,
            :ssl_cacert => '/path/to/cacert',
            :ssl_cert => '/path/to/cert',
            :ssl_key => '/path/to/key'
        } }

        it 'should set ssl options to specified values' do
          contain_file('rabbitmq.config').with({
            'content' => %r|ssl_listeners, \[3141\].*
            ssl_options, \[{cacertfile,"/path/to/cacert".*
            certfile="/path/to/cert".*
            keyfile,"/path/to/key|,
          })
        end
      end

      describe 'ssl options with ssl_only' do
        let(:params) {
          { :ssl => true,
            :ssl_only => true,
            :ssl_management_port => 3141,
            :ssl_cacert => '/path/to/cacert',
            :ssl_cert => '/path/to/cert',
            :ssl_key => '/path/to/key'
        } }

        it 'should set ssl options to specified values' do
          contain_file('rabbitmq.config').with({
            'content' => %r|tcp_listeners, \[\].*
            ssl_listeners, \[3141\].*
            ssl_options, \[{cacertfile,"/path/to/cacert".*
            certfile="/path/to/cert".*
            keyfile,"/path/to/key|,
          })
        end
      end

      describe 'config_variables options' do
        let(:params) {{ :config_variables => {
            'hipe_compile'                  => true,
            'vm_memory_high_watermark'      => 0.4,
            'frame_max'                     => 131072,
            'collect_statistics'            => "none",
            'auth_mechanisms'               => "['PLAIN', 'AMQPLAIN']",
        }}}
        it 'should set environment variables' do
          should contain_file('rabbitmq.config') \
            .with_content(/\{hipe_compile, true\}/) \
            .with_content(/\{vm_memory_high_watermark, 0.4\}/) \
            .with_content(/\{frame_max, 131072\}/) \
            .with_content(/\{collect_statistics, none\}/) \
            .with_content(/\{auth_mechanisms, \['PLAIN', 'AMQPLAIN'\]\}/)
        end
      end

      describe 'config_kernel_variables options' do
        let(:params) {{ :config_kernel_variables => {
            'inet_dist_listen_min'      => 9100,
            'inet_dist_listen_max'      => 9105,
        }}}
        it 'should set config variables' do
          should contain_file('rabbitmq.config') \
            .with_content(/\{inet_dist_listen_min, 9100\}/) \
            .with_content(/\{inet_dist_listen_max, 9105\}/) 
        end
      end

      context 'delete_guest_user' do
        describe 'should do nothing by default' do
          it { should_not contain_rabbitmq_user('guest') }
        end

        describe 'delete user when delete_guest_user set' do
          let(:params) {{ :delete_guest_user => true }}
          it 'removes the user' do
            should contain_rabbitmq_user('guest').with(
              'ensure'   => 'absent',
              'provider' => 'rabbitmqctl'
            )
          end
        end
      end

      ##
      ## rabbitmq::service
      ##
      describe 'service with default params' do
        it { should contain_service('rabbitmq-server').with(
          'ensure'     => 'running',
          'enable'     => 'true',
          'hasstatus'  => 'true',
          'hasrestart' => 'true'
        )}
      end

      describe 'service with ensure stopped' do
        let :params do
          { :service_ensure => 'stopped' }
        end

        it { should contain_service('rabbitmq-server').with(
          'ensure'    => 'stopped',
          'enable'    => false
        ) }
      end

      describe 'service with ensure neither running neither stopped' do
        let :params do
          { :service_ensure => 'foo' }
        end

        it 'should raise an error' do
          expect {
            should contain_service('rabbitmq-server').with(
              'ensure' => 'stopped' )
          }.to raise_error(Puppet::Error, /validate_re\(\): "foo" does not match "\^\(running\|stopped\)\$"/)
        end
      end

      describe 'service with service_manage equal to false' do
        let :params do
          { :service_manage => false }
        end

        it { should_not contain_service('rabbitmq-server') }
      end

    end
  end

  ##
  ## rabbitmq::install
  ##
  context "on RHEL" do
    let(:facts) {{ :osfamily => 'RedHat' }}
    let(:params) {{ :package_source => 'http://www.rabbitmq.com/releases/rabbitmq-server/v3.2.3/rabbitmq-server-3.2.3-1.noarch.rpm' }}
    it 'installs the rabbitmq package' do
      should contain_package('rabbitmq-server').with(
        'ensure'   => 'installed',
        'name'     => 'rabbitmq-server',
        'provider' => 'yum',
        'source'   => 'http://www.rabbitmq.com/releases/rabbitmq-server/v3.2.3/rabbitmq-server-3.2.3-1.noarch.rpm'
      )
    end
  end

  context "on Debian" do
    let(:facts) {{ :osfamily => 'Debian', :lsbdistid => 'Debian', :lsbdistcodename => 'precise' }}
    it 'installs the rabbitmq package' do
      should contain_package('rabbitmq-server').with(
        'ensure'   => 'installed',
        'name'     => 'rabbitmq-server',
        'provider' => 'apt'
      )
    end
  end

  context "on Archlinux" do
    let(:facts) {{ :osfamily => 'Archlinux' }}
    it 'installs the rabbitmq package' do
      should contain_package('rabbitmq-server').with(
        'ensure'   => 'installed',
        'name'     => 'rabbitmq')
    end
  end

  describe 'repo management on Debian' do
    let(:facts)  {{ :osfamily => 'Debian', :lsbdistid => 'Debian' }}

    context 'with no pin' do
      let(:params) {{ :package_apt_pin => '' }}
      describe 'it sets up an apt::source' do

        it { should contain_apt__source('rabbitmq').with(
          'location'    => 'http://www.rabbitmq.com/debian/',
          'release'     => 'testing',
          'repos'       => 'main',
          'include_src' => false,
          'key'         => '056E8E56'
        ) }
      end
    end

    context 'with pin' do
      let(:params) {{ :package_apt_pin => '700' }}
      describe 'it sets up an apt::source and pin' do

        it { should contain_apt__source('rabbitmq').with(
          'location'    => 'http://www.rabbitmq.com/debian/',
          'release'     => 'testing',
          'repos'       => 'main',
          'include_src' => false,
          'key'         => '056E8E56'
        ) }

        it { should contain_apt__pin('rabbitmq').with(
          'packages' => 'rabbitmq-server',
          'priority' => '700'
        ) }

      end
    end
  end

  ['RedHat', 'SuSE'].each do |distro|
    describe "repo management on #{distro}" do
      describe 'imports the key' do
        let(:facts) {{ :osfamily => distro }}
        let(:params) {{ :package_gpg_key => 'http://www.rabbitmq.com/rabbitmq-signing-key-public.asc' }}

        it { should contain_exec("rpm --import #{params[:package_gpg_key]}").with(
          'path' => ['/bin','/usr/bin','/sbin','/usr/sbin']
        ) }
      end
    end
  end

end
s
mtime
require 'puppetlabs_spec_helper/module_spec_helper'
require 'beaker-rspec'

UNSUPPORTED_PLATFORMS = []

unless ENV['RS_PROVISION'] == 'no' or ENV['BEAKER_provision'] == 'no'
  if hosts.first.is_pe?
    install_pe
  else
    install_puppet
  end
  hosts.each do |host|
    on hosts, "mkdir -p #{host['distmoduledir']}"
  end
end

RSpec.configure do |c|
  # Project root
  proj_root = File.expand_path(File.join(File.dirname(__FILE__), '..'))

  # Readable test descriptions
  c.formatter = :documentation
  c.before :suite do
    puppet_module_install(:source => proj_root, :module_name => 'rabbitmq')
    hosts.each do |host|

      shell("/bin/touch #{default['puppetpath']}/hiera.yaml")
      shell('puppet module install puppetlabs-stdlib', { :acceptable_exit_codes => [0,1] })
      if fact('osfamily') == 'Debian'
        shell('puppet module install puppetlabs-apt', { :acceptable_exit_codes => [0,1] })
      end
      shell('puppet module install nanliu-staging', { :acceptable_exit_codes => [0,1] })
      if fact('osfamily') == 'RedHat'
        shell('puppet module install garethr-erlang', { :acceptable_exit_codes => [0,1] })
      end
    end
  end
end

require 'spec_helper'

describe 'rabbitmq_erlang_cookie', :type => :fact do
  before(:each) { Facter.clear }

  it 'works correctly' do
    Facter.fact(:osfamily).stubs(:value).returns('RedHat')
    File.stubs(:exists?).with('/var/lib/rabbitmq/.erlang.cookie').returns(true)
    File.stubs(:read).with('/var/lib/rabbitmq/.erlang.cookie').returns('THISISACOOKIE')
    Facter.fact(:rabbitmq_erlang_cookie).value.should == 'THISISACOOKIE'
  end

  it 'fails if file doesnt exist' do
    Facter.fact(:osfamily).stubs(:value).returns('RedHat')
    File.stubs(:exists?).with('/var/lib/rabbitmq/.erlang.cookie').returns(false)
    Facter.fact(:rabbitmq_erlang_cookie).value.should == nil
  end

end
require 'puppet'
require 'mocha'
RSpec.configure do |config|
  config.mock_with :mocha
end
provider_class = Puppet::Type.type(:rabbitmq_exchange).provider(:rabbitmqadmin)
describe provider_class do
  before :each do
    @resource = Puppet::Type::Rabbitmq_exchange.new(
      {:name => 'amq.direct@/',
       :type => :topic}
    )
    @provider = provider_class.new(@resource)
  end

  it 'should return instances' do
    provider_class.expects(:rabbitmqctl).with('list_vhosts').returns <<-EOT
Listing vhosts ...
/
...done.
EOT
    provider_class.expects(:rabbitmqctl).with('list_exchanges', '-p', '/', 'name', 'type').returns <<-EOT
Listing exchanges ...
        direct
	amq.direct      direct
	amq.fanout      fanout
	amq.headers     headers
	amq.match       headers
	amq.rabbitmq.log        topic
	amq.rabbitmq.trace      topic
	amq.topic       topic
	...done.
EOT
    instances = provider_class.instances
    instances.size.should == 8
  end

  it 'should call rabbitmqadmin to create' do
    @provider.expects(:rabbitmqadmin).with('declare', 'exchange', '--vhost=/', '--user=guest', '--password=guest', 'name=amq.direct', 'type=topic')
    @provider.create
  end

  it 'should call rabbitmqadmin to destroy' do
    @provider.expects(:rabbitmqadmin).with('delete', 'exchange', '--vhost=/', '--user=guest', '--password=guest', 'name=amq.direct')
    @provider.destroy
  end

  context 'specifying credentials' do
    before :each do
      @resource = Puppet::Type::Rabbitmq_exchange.new(
        {:name => 'amq.direct@/',
        :type => :topic,
        :user => 'colin',
        :password => 'secret',
        }
      )
      @provider = provider_class.new(@resource)
    end

    it 'should call rabbitmqadmin to create' do
      @provider.expects(:rabbitmqadmin).with('declare', 'exchange', '--vhost=/', '--user=colin', '--password=secret', 'name=amq.direct', 'type=topic')
      @provider.create
    end
  end
end
require 'puppet'
require 'mocha'
RSpec.configure do |config|
  config.mock_with :mocha
end
provider_class = Puppet::Type.type(:rabbitmq_user).provider(:rabbitmqctl)
describe provider_class do
  before :each do
    @resource = Puppet::Type::Rabbitmq_user.new(
      {:name => 'foo', :password => 'bar'}
    )
    @provider = provider_class.new(@resource)
  end
  it 'should match user names' do
    @provider.expects(:rabbitmqctl).with('list_users').returns <<-EOT
Listing users ...
foo
...done.
EOT
    @provider.exists?.should == 'foo'
  end
  it 'should match user names with 2.4.1 syntax' do
    @provider.expects(:rabbitmqctl).with('list_users').returns <<-EOT
Listing users ...
foo bar
...done.
EOT
    @provider.exists?.should == 'foo bar'
  end
  it 'should not match if no users on system' do
    @provider.expects(:rabbitmqctl).with('list_users').returns <<-EOT
Listing users ...
...done.
EOT
    @provider.exists?.should be_nil
  end
  it 'should not match if no matching users on system' do
    @provider.expects(:rabbitmqctl).with('list_users').returns <<-EOT
Listing users ...
fooey
...done.
EOT
    @provider.exists?.should be_nil
  end
  it 'should match user names from list' do
    @provider.expects(:rabbitmqctl).with('list_users').returns <<-EOT
Listing users ...
one
two three
foo
bar
...done.
EOT
    @provider.exists?.should == 'foo'
  end
  it 'should create user and set password' do
    @resource[:password] = 'bar'
    @provider.expects(:rabbitmqctl).with('add_user', 'foo', 'bar')
    @provider.create
  end
  it 'should create user, set password and set to admin' do
    @resource[:password] = 'bar'
    @resource[:admin] = 'true'
    @provider.expects(:rabbitmqctl).with('add_user', 'foo', 'bar')
    @provider.expects(:rabbitmqctl).with('list_users').returns <<-EOT
Listing users ...
foo   []
icinga  [monitoring]
kitchen []
kitchen2        [abc, def, ghi]
...done.
EOT
    @provider.expects(:rabbitmqctl).with('set_user_tags', 'foo', ['administrator'])
    @provider.create
  end
  it 'should call rabbitmqctl to delete' do
    @provider.expects(:rabbitmqctl).with('delete_user', 'foo')
    @provider.destroy
  end
  it 'should be able to retrieve admin value' do
    @provider.expects(:rabbitmqctl).with('list_users').returns <<-EOT
Listing users ...
foo [administrator]
...done.
EOT
    @provider.admin.should == :true
    @provider.expects(:rabbitmqctl).with('list_users').returns <<-EOT
Listing users ...
one [administrator]
foo []
...done.
EOT
    @provider.admin.should == :false
  end
  it 'should fail if admin value is invalid' do
    @provider.expects(:rabbitmqctl).with('list_users').returns <<-EOT
Listing users ...
foo fail
...done.
EOT
    expect { @provider.admin }.to raise_error(Puppet::Error, /Could not match line/)
  end
  it 'should be able to set admin value' do
    @provider.expects(:rabbitmqctl).with('list_users').returns <<-EOT
Listing users ...
foo   []
icinga  [monitoring]
kitchen []
kitchen2        [abc, def, ghi]
...done.
EOT
    @provider.expects(:rabbitmqctl).with('set_user_tags', 'foo', ['administrator'])
    @provider.admin=:true
  end
  it 'should not interfere with existing tags on the user when setting admin value' do
    @provider.expects(:rabbitmqctl).with('list_users').returns <<-EOT
Listing users ...
foo   [bar, baz]
icinga  [monitoring]
kitchen []
kitchen2        [abc, def, ghi]
...done.
EOT
    @provider.expects(:rabbitmqctl).with('set_user_tags', 'foo', ['bar','baz', 'administrator'].sort) 
    @provider.admin=:true
  end
  it 'should be able to unset admin value' do
    @provider.expects(:rabbitmqctl).with('list_users').returns <<-EOT
Listing users ...
foo     [administrator]
guest   [administrator]
icinga  []
...done.
EOT
    @provider.expects(:rabbitmqctl).with('set_user_tags', 'foo', [])
    @provider.admin=:false
  end
  it 'should not interfere with existing tags on the user when unsetting admin value' do
    @provider.expects(:rabbitmqctl).with('list_users').returns <<-EOT
Listing users ...
foo   [administrator, bar, baz]
icinga  [monitoring]
kitchen []
kitchen2        [abc, def, ghi]
...done.
EOT
    @provider.expects(:rabbitmqctl).with('set_user_tags', 'foo', ['bar','baz'].sort) 
    @provider.admin=:false
  end

  it 'should clear all tags on existing user' do
    @provider.expects(:rabbitmqctl).with('list_users').returns <<-EOT
Listing users ...
one [administrator]
foo [tag1,tag2]
icinga  [monitoring]
kitchen []
kitchen2        [abc, def, ghi]
...done.
EOT
    @provider.expects(:rabbitmqctl).with('set_user_tags', 'foo', [])
    @provider.tags=[]
  end

  it 'should set multiple tags' do
    @provider.expects(:rabbitmqctl).with('list_users').returns <<-EOT
Listing users ...
one [administrator]
foo []
icinga  [monitoring]
kitchen []
kitchen2        [abc, def, ghi]
...done.
EOT
    @provider.expects(:rabbitmqctl).with('set_user_tags', 'foo', ['tag1','tag2'])
    @provider.tags=['tag1','tag2']
  end

  it 'should clear tags while keep admin tag' do
    @resource[:admin]  = true
    @provider.expects(:rabbitmqctl).with('list_users').returns <<-EOT
Listing users ...
one [administrator]
foo [administrator, tag1, tag2]
icinga  [monitoring]
kitchen []
kitchen2        [abc, def, ghi]
...done.
EOT
    @provider.expects(:rabbitmqctl).with('set_user_tags', 'foo', ["administrator"])
    @provider.tags=[]
  end

  it 'should change tags while keep admin tag' do
    @resource[:admin]  = true
    @provider.expects(:rabbitmqctl).with('list_users').returns <<-EOT
Listing users ...
one [administrator]
foo [administrator, tag1, tag2]
icinga  [monitoring]
kitchen []
kitchen2        [abc, def, ghi]
...done.
EOT
    @provider.expects(:rabbitmqctl).with('set_user_tags', 'foo', ["administrator","tag1","tag3","tag7"])
    @provider.tags=['tag1','tag7','tag3']
  end

  it 'should create user with tags and without admin' do
    @resource[:tags] = [ "tag1", "tag2" ]
    @provider.expects(:rabbitmqctl).with('add_user', 'foo', 'bar')
    @provider.expects(:rabbitmqctl).with('set_user_tags', 'foo', ["tag1","tag2"])
    @provider.expects(:rabbitmqctl).with('list_users').returns <<-EOT
Listing users ...
foo []
...done.
EOT
    @provider.create
  end

  it 'should create user with tags and with admin' do
    @resource[:tags] = [ "tag1", "tag2" ]
    @resource[:admin]  = true
    @provider.expects(:rabbitmqctl).with('add_user', 'foo', 'bar')
    @provider.expects(:rabbitmqctl).with('list_users').twice.returns <<-EOT
Listing users ...
foo []
...done.
EOT
    @provider.expects(:rabbitmqctl).with('set_user_tags', 'foo', ["administrator"])
    @provider.expects(:rabbitmqctl).with('set_user_tags', 'foo', ["administrator","tag1","tag2"])
    @provider.create
  end
  

end
require 'puppet'
require 'mocha'
RSpec.configure do |config|
  config.mock_with :mocha
end
describe 'Puppet::Type.type(:rabbitmq_user_permissions).provider(:rabbitmqctl)' do
  before :each do
    @provider_class = Puppet::Type.type(:rabbitmq_user_permissions).provider(:rabbitmqctl)
    @resource = Puppet::Type::Rabbitmq_user_permissions.new(
      {:name => 'foo@bar'}
    )
    @provider = @provider_class.new(@resource)
  end
  after :each do
    @provider_class.instance_variable_set(:@users, nil)
  end
  it 'should match user permissions from list' do
    @provider.class.expects(:rabbitmqctl).with('list_user_permissions', 'foo').returns <<-EOT
Listing users ...
bar 1 2 3
...done.
EOT
    @provider.exists?.should == {:configure=>"1", :write=>"2", :read=>"3"}
  end
  it 'should match user permissions with empty columns' do
    @provider.class.expects(:rabbitmqctl).with('list_user_permissions', 'foo').returns <<-EOT
Listing users ...
bar			3
...done.
EOT
    @provider.exists?.should == {:configure=>"", :write=>"", :read=>"3"}
  end
  it 'should not match user permissions with more than 3 columns' do
    @provider.class.expects(:rabbitmqctl).with('list_user_permissions', 'foo').returns <<-EOT
Listing users ...
bar 1 2 3 4
...done.
EOT
    expect { @provider.exists? }.to raise_error(Puppet::Error, /cannot parse line from list_user_permissions/)
  end
  it 'should not match an empty list' do
    @provider.class.expects(:rabbitmqctl).with('list_user_permissions', 'foo').returns <<-EOT
Listing users ...
...done.
EOT
    @provider.exists?.should == nil
  end
  it 'should create default permissions' do
    @provider.instance_variable_set(:@should_vhost, "bar")
    @provider.instance_variable_set(:@should_user, "foo")
    @provider.expects(:rabbitmqctl).with('set_permissions', '-p', 'bar', 'foo', "''", "''", "''")
    @provider.create 
  end
  it 'should destroy permissions' do
    @provider.instance_variable_set(:@should_vhost, "bar")
    @provider.instance_variable_set(:@should_user, "foo")
    @provider.expects(:rabbitmqctl).with('clear_permissions', '-p', 'bar', 'foo')
    @provider.destroy 
  end
  {:configure_permission => '1', :write_permission => '2', :read_permission => '3'}.each do |k,v|
    it "should be able to retrieve #{k}" do
      @provider.class.expects(:rabbitmqctl).with('list_user_permissions', 'foo').returns <<-EOT
Listing users ...
bar 1 2 3
...done.
EOT
      @provider.send(k).should == v
    end
  end
  {:configure_permission => '1', :write_permission => '2', :read_permission => '3'}.each do |k,v|
    it "should be able to retrieve #{k} after exists has been called" do
      @provider.class.expects(:rabbitmqctl).with('list_user_permissions', 'foo').returns <<-EOT
Listing users ...
bar 1 2 3
...done.
EOT
      @provider.exists?
      @provider.send(k).should == v
    end
  end
  {:configure_permission => ['foo', '2', '3'],
   :read_permission      => ['1', '2', 'foo'],
   :write_permission     => ['1', 'foo', '3']
  }.each do |perm, columns|
    it "should be able to sync #{perm}" do
      @provider.class.expects(:rabbitmqctl).with('list_user_permissions', 'foo').returns <<-EOT
Listing users ...
bar 1 2 3
...done.
EOT
      @provider.resource[perm] = 'foo'
      @provider.expects(:rabbitmqctl).with('set_permissions', '-p', 'bar', 'foo', *columns)
      @provider.send("#{perm}=".to_sym, 'foo')
    end
  end
  it 'should only call set_permissions once' do
    @provider.class.expects(:rabbitmqctl).with('list_user_permissions', 'foo').returns <<-EOT
Listing users ...
bar 1 2 3
...done.
EOT
    @provider.resource[:configure_permission] = 'foo'
    @provider.resource[:read_permission] = 'foo'
    @provider.expects(:rabbitmqctl).with('set_permissions', '-p', 'bar', 'foo', 'foo', '2', 'foo').once
    @provider.configure_permission='foo'
    @provider.read_permission='foo'
  end
end

require 'puppet'
require 'mocha'
RSpec.configure do |config|
  config.mock_with :mocha
end
provider_class = Puppet::Type.type(:rabbitmq_vhost).provider(:rabbitmqctl)
describe provider_class do
  before :each do
    @resource = Puppet::Type::Rabbitmq_vhost.new(
      {:name => 'foo'}
    )
    @provider = provider_class.new(@resource)
  end
  it 'should match vhost names' do
    @provider.expects(:rabbitmqctl).with('list_vhosts').returns <<-EOT
Listing vhosts ...
foo
...done.
EOT
    @provider.exists?.should == 'foo'
  end
  it 'should not match if no vhosts on system' do
    @provider.expects(:rabbitmqctl).with('list_vhosts').returns <<-EOT
Listing vhosts ...
...done.
EOT
    @provider.exists?.should be_nil
  end
  it 'should not match if no matching vhosts on system' do
    @provider.expects(:rabbitmqctl).with('list_vhosts').returns <<-EOT
Listing vhosts ...
fooey
...done.
EOT
    @provider.exists?.should be_nil
  end
  it 'should call rabbitmqctl to create' do
    @provider.expects(:rabbitmqctl).with('add_vhost', 'foo')
    @provider.create
  end
  it 'should call rabbitmqctl to create' do
    @provider.expects(:rabbitmqctl).with('delete_vhost', 'foo')
    @provider.destroy
  end
end
require 'puppet'
require 'puppet/type/rabbitmq_exchange'
describe Puppet::Type.type(:rabbitmq_exchange) do
  before :each do
    @exchange = Puppet::Type.type(:rabbitmq_exchange).new(
      :name => 'foo@bar',
      :type => :topic
    )
  end
  it 'should accept an exchange name' do
    @exchange[:name] = 'dan@pl'
    @exchange[:name].should == 'dan@pl'
  end
  it 'should require a name' do
    expect {
      Puppet::Type.type(:rabbitmq_exchange).new({})
    }.to raise_error(Puppet::Error, 'Title or name must be provided')
  end
  it 'should not allow whitespace in the name' do
    expect {
      @exchange[:name] = 'b r'
    }.to raise_error(Puppet::Error, /Valid values match/)
  end
  it 'should not allow names without @' do
    expect {
      @exchange[:name] = 'b_r'
    }.to raise_error(Puppet::Error, /Valid values match/)
  end

  it 'should accept an exchange type' do
    @exchange[:type] = :direct
    @exchange[:type].should == :direct
  end
  it 'should require a type' do
    expect {
      Puppet::Type.type(:rabbitmq_exchange).new(:name => 'foo@bar')
    }.to raise_error(/.*must set type when creating exchange.*/)
  end
  it 'should not require a type when destroying' do
    expect {
            Puppet::Type.type(:rabbitmq_exchange).new(:name => 'foo@bar', :ensure => :absent)
    }.to_not raise_error
  end

  it 'should accept a user' do
    @exchange[:user] = :root
    @exchange[:user].should == :root
  end

  it 'should accept a password' do
    @exchange[:password] = :PaSsw0rD
    @exchange[:password].should == :PaSsw0rD
  end
end
require 'puppet'
require 'puppet/type/rabbitmq_user_permissions'
describe Puppet::Type.type(:rabbitmq_user_permissions) do
  before :each do
    @perms = Puppet::Type.type(:rabbitmq_user_permissions).new(:name => 'foo@bar')
  end
  it 'should accept a valid hostname name' do
    @perms[:name] = 'dan@bar'
    @perms[:name].should == 'dan@bar'
  end
  it 'should require a name' do
    expect {
      Puppet::Type.type(:rabbitmq_user_permissions).new({})
    }.to raise_error(Puppet::Error, 'Title or name must be provided')
  end
  it 'should fail when names dont have a @' do
    expect {
      @perms[:name] = 'bar'
    }.to raise_error(Puppet::Error, /Valid values match/)
  end
  [:configure_permission, :read_permission, :write_permission].each do |param|
    it 'should not default to anything' do
       @perms[param].should == nil
    end
    it "should accept a valid regex for #{param}" do
      @perms[param] = '.*?'
      @perms[param].should == '.*?'  
    end
    it "should accept an empty string for #{param}" do
      @perms[param] = ''
      @perms[param].should == ''  
    end
    it "should not accept invalid regex for #{param}" do
      expect {
        @perms[param] = '*'
      }.to raise_error(Puppet::Error, /Invalid regexp/)
    end
  end
  {:rabbitmq_vhost => 'dan@test', :rabbitmq_user => 'test@dan'}.each do |k,v|
    it "should autorequire #{k}" do
      if k == :rabbitmq_vhost
        vhost = Puppet::Type.type(k).new(:name => "test")
      else
        vhost = Puppet::Type.type(k).new(:name => "test", :password => 'pass')
      end
      perm  = Puppet::Type.type(:rabbitmq_user_permissions).new(:name => v)
      config = Puppet::Resource::Catalog.new :testing do |conf|
        [vhost, perm].each { |resource| conf.add_resource resource }
      end
      rel = perm.autorequire[0]
      rel.source.ref.should == vhost.ref
      rel.target.ref.should == perm.ref
    end
  end
end
require 'puppet'
require 'puppet/type/rabbitmq_user'
describe Puppet::Type.type(:rabbitmq_user) do
  before :each do
    @user = Puppet::Type.type(:rabbitmq_user).new(:name => 'foo', :password => 'pass')
  end
  it 'should accept a user name' do
    @user[:name] = 'dan'
    @user[:name].should == 'dan'
    @user[:admin].should == :false
  end
  it 'should accept a password' do
    @user[:password] = 'foo'
    @user[:password].should == 'foo'
  end
  it 'should require a password' do
    expect {
      Puppet::Type.type(:rabbitmq_user).new(:name => 'foo')
    }.to raise_error(/must set password/)
  end
  it 'should require a name' do
    expect {
      Puppet::Type.type(:rabbitmq_user).new({})
    }.to raise_error(Puppet::Error, 'Title or name must be provided')
  end
  it 'should not allow whitespace in the name' do
    expect {
      @user[:name] = 'b r'
    }.to raise_error(Puppet::Error, /Valid values match/)
  end
  [true, false, 'true', 'false'].each do |val|
    it "admin property should accept #{val}" do
      @user[:admin] = val
      @user[:admin].should == val.to_s.to_sym
    end
  end
  it 'should not accept non-boolean values for admin' do
    expect {
      @user[:admin] = 'yes'
    }.to raise_error(Puppet::Error, /Invalid value/)
  end
end
require 'puppet'
require 'puppet/type/rabbitmq_vhost'
describe Puppet::Type.type(:rabbitmq_vhost) do
  before :each do
    @vhost = Puppet::Type.type(:rabbitmq_vhost).new(:name => 'foo')
  end
  it 'should accept a vhost name' do
    @vhost[:name] = 'dan'
    @vhost[:name].should == 'dan'
  end
  it 'should require a name' do
    expect {
      Puppet::Type.type(:rabbitmq_vhost).new({})
    }.to raise_error(Puppet::Error, 'Title or name must be provided')
  end
  it 'should not allow whitespace in the name' do
    expect {
      @vhost[:name] = 'b r'
    }.to raise_error(Puppet::Error, /Valid values match/)
  end
end
Templates
=========

Puppet supports templates and templating via ERB, which is part of the Ruby
standard library and is used for many other projects including Ruby on Rails.
Templates allow you to manage the content of template files, for example
configuration files that cannot yet be managed as a Puppet type. Learn more at
http://projects.puppetlabs.com/projects/puppet/wiki/Puppet_Templating

You can use templates like this: 

    class myclass {
      package { mypackage: ensure => latest }
      service { myservice: ensure => running }
      file { "/etc/myfile":
        content => template("mymodule/myfile.erb")
      }
    }

The templates are searched for in:

    $templatedir/mymodule/myfile.erb
    $modulepath/mymodule/templates/myfile.erb
<%- @environment_variables.keys.sort.each do |key| -%>
<%- if @environment_variables[key] != 'UNSET' -%>
<%= key %>=<%= @environment_variables[key] %>
<%- end -%>
<%- end -%>
% This file managed by Puppet
% Template Path: <%= @module_name %>/templates/rabbitmq.config
[
  {rabbit, [
<% if @ldap_auth -%>
    {auth_backends, [rabbit_auth_backend_internal, rabbit_auth_backend_ldap]},
<% end -%>
<% if @config_cluster -%>
    {cluster_nodes, {[<%= @r_cluster_nodes.map { |n| "\'rabbit@#{n}\'" }.join(', ') %>], <%= @cluster_node_type %>}},
    {cluster_partition_handling, <%= @cluster_partition_handling %>},
<% end -%>
<%- if @ssl_only -%>
    {tcp_listeners, []},
<%- end -%>
<%- if @ssl -%>
    {ssl_listeners, [<%= @ssl_management_port %>]},
    {ssl_options, [{cacertfile,"<%= @ssl_cacert %>"},
                    {certfile,"<%= @ssl_cert %>"},
                    {keyfile,"<%= @ssl_key %>"},
                    {verify,<%= @ssl_verify %>},
                    {fail_if_no_peer_cert,<%= @ssl_fail_if_no_peer_cert %>}]},
<%- end -%>
<% if @config_variables -%>
<%- @config_variables.keys.sort.each do |key| -%>
    {<%= key %>, <%= @config_variables[key] %>},
<%- end -%>
<%- end -%>
    {default_user, <<"<%= @default_user %>">>},
    {default_pass, <<"<%= @default_pass %>">>}
  ]}<% if @config_kernel_variables -%>,
  {kernel, [
    <%= @config_kernel_variables.sort.map{|k,v| "{#{k}, #{v}}"}.join(",\n    ") %>
  ]}
<%- end -%>
<% if @config_stomp -%>,
% Configure the Stomp Plugin listening port
  {rabbitmq_stomp, [
    {tcp_listeners, [<%= @stomp_port %>]}
  <%- if @ssl_stomp_port -%>,
    {ssl_listeners, [<%= @ssl_stomp_port %>]}
  <%- end -%>
  ]}
<% end -%>
<%- if @ldap_auth -%>,
% Configure the LDAP authentication plugin
  {rabbitmq_auth_backend_ldap, [
    {other_bind, anon},
    {servers, ["<%= @ldap_server %>"]},
    {user_dn_pattern, "<%= @ldap_user_dn_pattern %>"},
    {use_ssl, <%= @ldap_use_ssl %>},
    {port, <%= @ldap_port %>},
    {log, <%= @ldap_log %>}
  ]}
<%- end -%>
].
% EOF
# install first the garethr-erlang module. See README.md
include 'erlang'

class { 'erlang': epel_enable => true}
Class['erlang'] -> Class['rabbitmq']
class { 'rabbitmq::repo::apt':
  pin => '900',
}->
class { 'rabbitmq::server':
  delete_guest_user => true,
#  version           => '2.4.1',
}->
rabbitmq_user { 'dan':
  admin    => true,
  password => 'pass',
  provider => 'rabbitmqctl',
}->
rabbitmq_vhost { 'myhost':
  provider => 'rabbitmqctl',
}
rabbitmq_user_permissions { 'dan@myhost':
  configure_permission => '.*',
  read_permission      => '.*',
  write_permission     => '.*',
  provider             => 'rabbitmqctl',
}
rabbitmq_user { 'blah7':
  password => 'foo',
}
rabbitmq_vhost { 'test5': }
rabbitmq_user_permissions { 'blah7@test5':
  configure_permission => 'config2',
  read_permission      => 'ready',
  #write_permission     => 'ready',
}
class { 'rabbitmq::server':
    config_stomp => true,
}

$rabbitmq_plugins = [ 'amqp_client', 'rabbitmq_stomp' ]

rabbitmq_plugin { $rabbitmq_plugins:
  ensure   => present,
  require  => Class['rabbitmq::server'],
  provider => 'rabbitmqplugins',
}
# requires pupetlabs-apt
include rabbitmq::repo::apt
class { 'rabbitmq::server':
  port              => '5672',
  delete_guest_user => true,
  version           => 'latest',
}
class { 'rabbitmq::service': }
node default {

  $rabbitmq_plugins = [ 'amqp_client', 'rabbitmq_stomp' ]

  class { 'rabbitmq::server':
    config => '[ {rabbit_stomp, [{tcp_listeners, [1234]} ]} ].',
  }

  # Required for MCollective
  rabbitmq_plugin { $rabbitmq_plugins:
    ensure   => present,
    require  => Class['rabbitmq::server'],
    provider => 'rabbitmqplugins',
  }
}

rabbitmq_user { ['blah2', 'blah3', 'blah4']:
  password => 'phoey!',
  #provider => 'rabbitmqctl',
}
rabbitmq_vhost { ['fooey', 'blah']: }
language: ruby
rvm:
- 1.8.7
- 1.9.3
script:
- git clone -q git://github.com/puppetlabs/ghpublisher.git .forge-releng
- .forge-releng/publish
branches:
  only:
  - master
env:
  global:
  - PUBLISHER_LOGIN=fsalum
  - secure: "DENnYQVOgU9VOxYGjKsCdsoCNeZ42yf751SFhK9s7Fmu790KiQvnY7Vjs+Sj\nrQ3xYXProkMYtx+KVbtzQo02oSYRF+sVYyBza3066bir0GK1YPdgrpT9Q3vo\nuT4+kfaeJK8StiBRWvPlyY3QrDbVsnIuQ+NxBFxjnZdDg350G8Q="
  matrix:
  - PUPPET_VERSION=2.7.25
  - PUPPET_VERSION=3.1.1
  - PUPPET_VERSION=3.2.4
  - PUPPET_VERSION=3.3.2
  - PUPPET_VERSION=3.4.2
notifications:
  email: false
gemfile: Gemfile
## fsalum-redis changelog

Release notes for the fsalum-redis module.


#### 0.0.11 - 2014-02-19

* system_sysctl parameter for redis class (@tehmaspc)

#### 0.0.10 - 2014-02-19

* Allow conf_bind to be unset (@stevelacey)
* Changing default of glueoutputbuf to UNSET (@tehmaspc)

#### 0.0.9 - 2014-01-09

* Add quotes around all instances of UNSET (@charlesdunbar)

#### 0.0.8 - 2013-12-20

* Setting mode permission for conf_dir (@KlavsKlavsen)

#### 0.0.7 - 2013-12-11

* Add glueoutputbuf config option (@kryptx)
* Add support for Amazon Linux AMI (@mattboston)

#### 0.0.6 - 2013-08-01

* Install package before poking config (@doismellburning)

#### 0.0.5 - 2013-06-06

* Fix Puppet 3.2.1 deprecation warnings (@ripienaar)
* Fix duplicate entry for logrotate on Debian/RHEL using different paths (@arthurfurlan)
* Add $conf_nosave parameter (@fsalum)
* Minor changes to params variables (@fsalum)
* Update CHANGELOG format


#### 0.0.4 - 2013-04-18

* Creates conf_dir directory if it doesn't exist


#### 0.0.3 - 2013-02-25

* Fixing redis.conf less options on Debian


#### 0.0.2 - 2013-02-25

* Fixing redis.conf location for Debian


#### 0.0.1 - 2013-02-25

* Initial Forge release
source :rubygems

puppetversion = ENV.key?('PUPPET_VERSION') ? "= #{ENV['PUPPET_VERSION']}" : ['>= 2.7']

gem 'rake'
gem 'puppet-lint'
gem 'puppet', puppetversion
Copyright (C) 2012 Felipe Salum

Felipe Salum can be contacted at: fsalum@gmail.com

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
name    'fsalum-redis'
version '0.0.11'
source 'git://github.com/fsalum/puppet-redis.git'
author 'Felipe Salum'
license 'Apache License, Version 2.0'
summary 'Puppet module for Redis Server'
description 'Module to install and configure a Redis server'
project_page 'https://github.com/fsalum/puppet-redis'

## Add dependencies, if any:

# https://forge.puppetlabs.com/thias/sysctl
dependency 'thias/sysctl', '0.3.0'
Redis Module for Puppet
=======================
[![Build Status](https://secure.travis-ci.org/fsalum/puppet-redis.png)](http://travis-ci.org/fsalum/puppet-redis)

This module installs and manages a Redis server. All redis.conf options are
accepted in the parameterized class.

Operating System

Tested on CentOS 6.3 and Debian Squeeze.

Quick Start

Use the default parameters:

    class { 'redis': }

To change the port and listening network interface:

    class { 'redis':
      conf_port => '6379',
      conf_bind => '0.0.0.0',
    }

Parameters

Check the [init.pp](https://github.com/fsalum/puppet-redis/blob/master/manifests/init.pp) file for a complete list of parameters accepted.

To enable and set important Linux kernel sysctl parameters as described in the [Redis Admin Guide](http://redis.io/topics/admin) - use the following configuration option:

    class { 'redis':
      system_sysctl => true
    }

By default, this sysctl parameter will not be enabled. Furthermore, you will need the sysctl module defined in the [Modulefile](https://github.com/fsalum/puppet-redis/blob/master/Modulefile) file.

Copyright and License

Copyright (C) 2012 Felipe Salum

Felipe Salum can be contacted at: fsalum@gmail.com

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
require 'puppet-lint/tasks/puppet-lint'

PuppetLint.configuration.send("disable_80chars")
PuppetLint.configuration.send('disable_class_parameter_defaults')

task :default => :lint
VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vbguest.auto_update = false
  config.hostmanager.enabled = false

  config.vm.define 'redis' do |node|
      node.vm.box = "centos65"
      node.vm.hostname = "redis.local"
      node.vm.network :private_network, ip: "192.168.100.100"
      node.vm.provision :shell, :inline => "yum install -y git && gem install librarian-puppet --no-ri --no-rdoc"
      node.vm.provision :shell, :inline => "cd /vagrant ; librarian-puppet install --clean --path /etc/puppet/modules"
      node.vm.provision :puppet do |puppet|
        puppet.manifests_path = ["vm", "/etc/puppet/modules/redis/tests"]
        puppet.manifest_file  = "init.pp"
      end
  end

end
# == Class: redis
#
# Install and configure a Redis server
#
# === Parameters
#
# All the redis.conf parameters can be passed to the class.
# See below for a complete list of parameters accepted.
#
# Check the README.md file for any further information about parameters for this class.
#
# === Examples
#
#  class { redis:
#    conf_port => '6380',
#    conf_bind => '0.0.0.0',
#  }
#
# === Authors
#
# Felipe Salum <fsalum@gmail.com>
#
# === Copyright
#
# Copyright 2013 Felipe Salum, unless otherwise noted.
#
class redis (
  $package_ensure                   = 'present',
  $service_ensure                   = 'running',
  $service_enable                   = true,
  $system_sysctl                    = false,
  $conf_daemonize                   = 'yes',
  $conf_pidfile                     = 'UNSET',
  $conf_port                        = '6379',
  $conf_bind                        = '127.0.0.1',
  $conf_timeout                     = '0',
  $conf_loglevel                    = 'notice',
  $conf_logfile                     = 'UNSET',
  $conf_syslog_enabled              = 'UNSET',
  $conf_syslog_ident                = 'UNSET',
  $conf_syslog_facility             = 'UNSET',
  $conf_databases                   = '16',
  $conf_save                        = 'UNSET',
  $conf_nosave                      = 'UNSET',
  $conf_rdbcompression              = 'yes',
  $conf_dbfilename                  = 'dump.rdb',
  $conf_dir                         = '/var/lib/redis/',
  $conf_slaveof                     = 'UNSET',
  $conf_masterauth                  = 'UNSET',
  $conf_slave_server_stale_data     = 'yes',
  $conf_repl_ping_slave_period      = '10',
  $conf_repl_timeout                = '60',
  $conf_requirepass                 = 'UNSET',
  $conf_maxclients                  = 'UNSET',
  $conf_maxmemory                   = 'UNSET',
  $conf_maxmemory_policy            = 'UNSET',
  $conf_maxmemory_samples           = 'UNSET',
  $conf_appendonly                  = 'no',
  $conf_appendfilename              = 'UNSET',
  $conf_appendfsync                 = 'everysec',
  $conf_no_appendfsync_on_rewrite   = 'no',
  $conf_auto_aof_rewrite_percentage = '100',
  $conf_auto_aof_rewrite_min_size   = '64mb',
  $conf_slowlog_log_slower_than     = '10000',
  $conf_slowlog_max_len             = '1024',
  $conf_vm_enabled                  = 'no',
  $conf_vm_swap_file                = '/tmp/redis.swap',
  $conf_vm_max_memory               = '0',
  $conf_vm_page_size                = '32',
  $conf_vm_pages                    = '134217728',
  $conf_vm_max_threads              = '4',
  $conf_hash_max_zipmap_entries     = '512',
  $conf_hash_max_zipmap_value       = '64',
  $conf_list_max_ziplist_entries    = '512',
  $conf_list_max_ziplist_value      = '64',
  $conf_set_max_intset_entries      = '512',
  $conf_zset_max_ziplist_entries    = '128',
  $conf_zset_max_ziplist_value      = '64',
  $conf_activerehashing             = 'yes',
  $conf_include                     = 'UNSET',
  $conf_glueoutputbuf               = 'UNSET',
) {

  include redis::params

  $conf_template  = $redis::params::conf_template
  $conf_redis     = $redis::params::conf
  $conf_logrotate = $redis::params::conf_logrotate
  $package        = $redis::params::package
  $service        = $redis::params::service

  $conf_pidfile_real = $conf_pidfile ? {
    'UNSET' => $::redis::params::pidfile,
    default => $conf_pidfile,
  }

  $conf_logfile_real = $conf_logfile ? {
    'UNSET' => $::redis::params::logfile,
    default => $conf_logfile,
  }

  package { 'redis':
    ensure => $package_ensure,
    name   => $package,
  }

  service { 'redis':
    ensure     => $service_ensure,
    name       => $service,
    enable     => $service_enable,
    hasrestart => true,
    hasstatus  => true,
    require    => Package['redis'],
  }

  file { $conf_redis:
    path    => $conf_redis,
    content => template("redis/${conf_template}"),
    owner   => root,
    group   => root,
    mode    => '0644',
    require => Package['redis'],
    notify  => Service['redis'],
  }

  file { $conf_logrotate:
    path    => $conf_logrotate,
    content => template('redis/redis.logrotate.erb'),
    owner   => root,
    group   => root,
    mode    => '0644',
  }

  exec { $conf_dir:
    path    => '/bin:/usr/bin:/sbin:/usr/sbin',
    command => "mkdir -p ${conf_dir}",
    user    => root,
    group   => root,
    creates => $conf_dir,
    before  => Service['redis'],
    require => Package['redis'],
    notify  => Service['redis'],
  }

  file { $conf_dir:
    ensure  => directory,
    owner   => redis,
    group   => redis,
    mode    => 0755,
    before  => Service['redis'],
    require => Exec[$conf_dir],
  }

  if ( $system_sysctl == true ) {
    # add necessary kernel parameters
    # see the redis admin guide here: http://redis.io/topics/admin
    sysctl { 'vm.overcommit_memory': value => '1' }
  }

}
# Class: redis::params
#
# This class configures parameters for the puppet-redis module.
#
# Parameters:
#
# Actions:
#
# Requires:
#
# Sample Usage:
#
class redis::params {

  case $::operatingsystem {
    'centos', 'redhat', 'fedora', 'amazon': {
      $package        = 'redis'
      $service        = 'redis'
      $conf           = '/etc/redis.conf'
      $conf_template  = 'redis.rhel.conf.erb'
      $conf_logrotate = '/etc/logrotate.d/redis'
      $pidfile        = '/var/run/redis/redis.pid'
      $logfile        = '/var/log/redis/redis.log'
    }
    'ubuntu', 'debian': {
      $package        = 'redis-server'
      $service        = 'redis-server'
      $conf           = '/etc/redis/redis.conf'
      $conf_template  = 'redis.debian.conf.erb'
      $conf_logrotate = '/etc/logrotate.d/redis-server'
      $pidfile        = '/var/run/redis/redis-server.pid'
      $logfile        = '/var/log/redis/redis-server.log'
    }
    default: {
      fail("Unsupported osfamily: ${::osfamily} operatingsystem: ${::operatingsystem}, module ${module_name} only support osfamily RedHat and Debian")
    }
  }

}
dir = File.expand_path(File.dirname(__FILE__))
$LOAD_PATH.unshift File.join(dir, 'lib')

require 'mocha'
require 'puppet'
require 'rspec'
require 'spec/autorun'

Spec::Runner.configure do |config|
    config.mock_with :mocha
end

# We need this because the RAL uses 'should' as a method.  This
# allows us the same behaviour but with a different method name.
class Object
    alias :must :should
end
# Redis configuration file example

# By default Redis does not run as a daemon. Use 'yes' if you need it.
# Note that Redis will write a pid file in /var/run/redis.pid when daemonized.
daemonize <%= @conf_daemonize %>

# When run as a daemon, Redis write a pid file in /var/run/redis.pid by default.
# You can specify a custom pid file location here.
pidfile <%= @conf_pidfile_real %>

# Accept connections on the specified port, default is 6379
port <%= @conf_port %>

# If you want you can bind a single interface, if the bind option is not
# specified all the interfaces will listen for connections.
#
<% if @conf_bind != 'UNSET' %>
bind <%= @conf_bind %>
<% end %>

# Close the connection after a client is idle for N seconds (0 to disable)
timeout <%= @conf_timeout %>

# Set server verbosity to 'debug'
# it can be one of:
# debug (a lot of information, useful for development/testing)
# notice (moderately verbose, what you want in production probably)
# warning (only very important / critical messages are logged)
loglevel <%= @conf_loglevel %>

# Specify the log file name. Also 'stdout' can be used to force
# the demon to log on the standard output. Note that if you use standard
# output for logging but daemonize, logs will be sent to /dev/null
logfile <%= @conf_logfile_real %>

# Set the number of databases. The default database is DB 0, you can select
# a different one on a per-connection basis using SELECT <dbid> where
# dbid is a number between 0 and 'databases'-1
databases <%= @conf_databases %>

################################ SNAPSHOTTING  #################################
#
# Save the DB on disk:
#
#   save <seconds> <changes>
#
#   Will save the DB if both the given number of seconds and the given
#   number of write operations against the DB occurred.
#
#   In the example below the behaviour will be to save:
#   after 900 sec (15 min) if at least 1 key changed
#   after 300 sec (5 min) if at least 10 keys changed
#   after 60 sec if at least 10000 keys changed
<% if @conf_nosave != 'UNSET' %>
#do not persist to disk:
#save 900 1
#save 300 10
#save 60 10000
<% else %>
  <% if @conf_save != 'UNSET' %>
  save <%= @conf_save %>
  <% else %>
  save 900 1
  save 300 10
  save 60 10000
  <% end %>
<% end %>

# Compress string objects using LZF when dump .rdb databases?
# For default that's set to 'yes' as it's almost always a win.
# If you want to save some CPU in the saving child set it to 'no' but
# the dataset will likely be bigger if you have compressible values or keys.
rdbcompression <%= @conf_rdbcompression %>

# The filename where to dump the DB
dbfilename <%= @conf_dbfilename %>

# For default save/load DB in/from the working directory
# Note that you must specify a directory not a file name.
dir <%= @conf_dir %>

################################# REPLICATION #################################

# Master-Slave replication. Use slaveof to make a Redis instance a copy of
# another Redis server. Note that the configuration is local to the slave
# so for example it is possible to configure the slave to save the DB with a
# different interval, or to listen to another port, and so on.
#
# slaveof <masterip> <masterport>
<% if @conf_slaveof != 'UNSET' %>
slaveof <%= @conf_slaveof %>
<% end %>

# If the master is password protected (using the "requirepass" configuration
# directive below) it is possible to tell the slave to authenticate before
# starting the replication synchronization process, otherwise the master will
# refuse the slave request.
#
# masterauth <master-password>
<% if @conf_masterauth != 'UNSET' %>
masterauth <%= @conf_masterauth %>
<% end %>


################################## SECURITY ###################################

# Require clients to issue AUTH <PASSWORD> before processing any other
# commands.  This might be useful in environments in which you do not trust
# others with access to the host running redis-server.
#
# This should stay commented out for backward compatibility and because most
# people do not need auth (e.g. they run their own servers).
#
# requirepass foobared
<% if @conf_requirepass != 'UNSET' %>
requirepass <%= @conf_requirepass %>
<% end %>


################################### LIMITS ####################################

# Set the max number of connected clients at the same time. By default there
# is no limit, and it's up to the number of file descriptors the Redis process
# is able to open. The special value '0' means no limts.
# Once the limit is reached Redis will close all the new connections sending
# an error 'max number of clients reached'.
#
# maxclients 128
<% if @conf_maxclients != 'UNSET' %>
maxclients <%= @conf_maxclients %>
<% end %>

# Don't use more memory than the specified amount of bytes.
# When the memory limit is reached Redis will try to remove keys with an
# EXPIRE set. It will try to start freeing keys that are going to expire
# in little time and preserve keys with a longer time to live.
# Redis will also try to remove objects from free lists if possible.
#
# If all this fails, Redis will start to reply with errors to commands
# that will use more memory, like SET, LPUSH, and so on, and will continue
# to reply to most read-only commands like GET.
#
# WARNING: maxmemory can be a good idea mainly if you want to use Redis as a
# 'state' server or cache, not as a real DB. When Redis is used as a real
# database the memory usage will grow over the weeks, it will be obvious if
# it is going to use too much memory in the long run, and you'll have the time
# to upgrade. With maxmemory after the limit is reached you'll start to get
# errors for write operations, and this may even lead to DB inconsistency.
#
# maxmemory <bytes>
<% if @conf_maxmemory != 'UNSET' %>
maxmemory <%= @conf_maxmemory %>
<% end %>

############################## APPEND ONLY MODE ###############################

# By default Redis asynchronously dumps the dataset on disk. If you can live
# with the idea that the latest records will be lost if something like a crash
# happens this is the preferred way to run Redis. If instead you care a lot
# about your data and don't want to that a single record can get lost you should
# enable the append only mode: when this mode is enabled Redis will append
# every write operation received in the file appendonly.log. This file will
# be read on startup in order to rebuild the full dataset in memory.
#
# Note that you can have both the async dumps and the append only file if you
# like (you have to comment the "save" statements above to disable the dumps).
# Still if append only mode is enabled Redis will load the data from the
# log file at startup ignoring the dump.rdb file.
#
# The name of the append only file is "appendonly.log"
#
# IMPORTANT: Check the BGREWRITEAOF to check how to rewrite the append
# log file in background when it gets too big.

appendonly <%= @conf_appendonly %>

# The fsync() call tells the Operating System to actually write data on disk
# instead to wait for more data in the output buffer. Some OS will really flush
# data on disk, some other OS will just try to do it ASAP.
#
# Redis supports three different modes:
#
# no: don't fsync, just let the OS flush the data when it wants. Faster.
# always: fsync after every write to the append only log . Slow, Safest.
# everysec: fsync only if one second passed since the last fsync. Compromise.
#
# The default is "always" that's the safer of the options. It's up to you to
# understand if you can relax this to "everysec" that will fsync every second
# or to "no" that will let the operating system flush the output buffer when
# it want, for better performances (but if you can live with the idea of
# some data loss consider the default persistence mode that's snapshotting).

appendfsync <%= @conf_appendfsync %>
# appendfsync everysec
# appendfsync no

############################### ADVANCED CONFIG ###############################

# Glue small output buffers together in order to send small replies in a
# single TCP packet. Uses a bit more CPU but most of the times it is a win
# in terms of number of queries per second. Use 'yes' if unsure.
<% if @conf_glueoutputbuf != 'UNSET' %>
glueoutputbuf <%= @conf_glueoutputbuf %>
<% end %>

# Use object sharing. Can save a lot of memory if you have many common
# string in your dataset, but performs lookups against the shared objects
# pool so it uses more CPU and can be a bit slower. Usually it's a good
# idea.
#
# When object sharing is enabled (shareobjects yes) you can use
# shareobjectspoolsize to control the size of the pool used in order to try
# object sharing. A bigger pool size will lead to better sharing capabilities.
# In general you want this value to be at least the double of the number of
# very common strings you have in your dataset.
#
# WARNING: object sharing is experimental, don't enable this feature
# in production before of Redis 1.0-stable. Still please try this feature in
# your development environment so that we can test it better.
# shareobjects no
# shareobjectspoolsize 1024
<%= @conf_logfile_real %> {
    weekly
    rotate 10
    copytruncate
    delaycompress
    compress
    notifempty
    missingok
}
# Redis configuration file example

# Note on units: when memory size is needed, it is possible to specifiy
# it in the usual form of 1k 5GB 4M and so forth:
#
# 1k => 1000 bytes
# 1kb => 1024 bytes
# 1m => 1000000 bytes
# 1mb => 1024*1024 bytes
# 1g => 1000000000 bytes
# 1gb => 1024*1024*1024 bytes
#
# units are case insensitive so 1GB 1Gb 1gB are all the same.

# By default Redis does not run as a daemon. Use 'yes' if you need it.
# Note that Redis will write a pid file in /var/run/redis.pid when daemonized.
daemonize <%= @conf_daemonize %>

# When running daemonized, Redis writes a pid file in /var/run/redis.pid by
# default. You can specify a custom pid file location here.
pidfile <%= @conf_pidfile_real %>

# Accept connections on the specified port, default is 6379.
# If port 0 is specified Redis will not listen on a TCP socket.
port <%= @conf_port %>

# If you want you can bind a single interface, if the bind option is not
# specified all the interfaces will listen for incoming connections.
#
<% if @conf_bind != 'UNSET' %>
bind <%= @conf_bind %>
<% end %>

# Specify the path for the unix socket that will be used to listen for
# incoming connections. There is no default, so Redis will not listen
# on a unix socket when not specified.
#
# unixsocket /tmp/redis.sock
# unixsocketperm 755

# Close the connection after a client is idle for N seconds (0 to disable)
timeout <%= @conf_timeout %>

# Set server verbosity to 'debug'
# it can be one of:
# debug (a lot of information, useful for development/testing)
# verbose (many rarely useful info, but not a mess like the debug level)
# notice (moderately verbose, what you want in production probably)
# warning (only very important / critical messages are logged)
loglevel <%= @conf_loglevel %>

# Specify the log file name. Also 'stdout' can be used to force
# Redis to log on the standard output. Note that if you use standard
# output for logging but daemonize, logs will be sent to /dev/null
logfile <%= @conf_logfile_real %>

# To enable logging to the system logger, just set 'syslog-enabled' to yes,
# and optionally update the other syslog parameters to suit your needs.
<% if @conf_syslog_enabled != 'UNSET' %>
syslog-enabled <%= @conf_syslog_enabled %>
<% else %>
# syslog-enabled no
<% end %>

# Specify the syslog identity.
<% if @conf_syslog_ident != 'UNSET' %>
syslog-ident <%= @conf_syslog_ident %>
<% else %>
# syslog-ident redis
<% end %>

# Specify the syslog facility.  Must be USER or between LOCAL0-LOCAL7.
<% if @conf_syslog_facility != 'UNSET' %>
syslog-facility <%= @conf_syslog_facility %>
<% else %>
# syslog-facility local0
<% end %>

# Set the number of databases. The default database is DB 0, you can select
# a different one on a per-connection basis using SELECT <dbid> where
# dbid is a number between 0 and 'databases'-1
databases <%= @conf_databases %>

################################ SNAPSHOTTING  #################################
#
# Save the DB on disk:
#
#   save <seconds> <changes>
#
#   Will save the DB if both the given number of seconds and the given
#   number of write operations against the DB occurred.
#
#   In the example below the behaviour will be to save:
#   after 900 sec (15 min) if at least 1 key changed
#   after 300 sec (5 min) if at least 10 keys changed
#   after 60 sec if at least 10000 keys changed
#
#   Note: you can disable saving at all commenting all the "save" lines.

<% if @conf_nosave != 'UNSET' %>
#do not persist to disk:
#save 900 1
#save 300 10
#save 60 10000
<% else %>
  <% if @conf_save != 'UNSET' %>
  save <%= @conf_save %>
  <% else %>
  save 900 1
  save 300 10
  save 60 10000
  <% end %>
<% end %>

# Compress string objects using LZF when dump .rdb databases?
# For default that's set to 'yes' as it's almost always a win.
# If you want to save some CPU in the saving child set it to 'no' but
# the dataset will likely be bigger if you have compressible values or keys.
rdbcompression <%= @conf_rdbcompression %>

# The filename where to dump the DB
dbfilename <%= @conf_dbfilename %>

# The working directory.
#
# The DB will be written inside this directory, with the filename specified
# above using the 'dbfilename' configuration directive.
#
# Also the Append Only File will be created inside this directory.
#
# Note that you must specify a directory here, not a file name.
dir <%= @conf_dir %>

################################# REPLICATION #################################

# Master-Slave replication. Use slaveof to make a Redis instance a copy of
# another Redis server. Note that the configuration is local to the slave
# so for example it is possible to configure the slave to save the DB with a
# different interval, or to listen to another port, and so on.
#
<% if @conf_slaveof != 'UNSET' %>
slaveof <%= @conf_slaveof %>
<% else %>
# slaveof <masterip> <masterport>
<% end %>

# If the master is password protected (using the "requirepass" configuration
# directive below) it is possible to tell the slave to authenticate before
# starting the replication synchronization process, otherwise the master will
# refuse the slave request.
#
<% if @conf_masterauth != 'UNSET' %>
masterauth <%= @conf_masterauth %>
<% else %>
# masterauth <master-password>
<% end %>

# When a slave lost the connection with the master, or when the replication
# is still in progress, the slave can act in two different ways:
#
# 1) if slave-serve-stale-data is set to 'yes' (the default) the slave will
#    still reply to client requests, possibly with out of data data, or the
#    data set may just be empty if this is the first synchronization.
#
# 2) if slave-serve-stale data is set to 'no' the slave will reply with
#    an error "SYNC with master in progress" to all the kind of commands
#    but to INFO and SLAVEOF.
#
slave-serve-stale-data <%= @conf_slave_server_stale_data %>

# Slaves send PINGs to server in a predefined interval. It's possible to change
# this interval with the repl_ping_slave_period option. The default value is 10
# seconds.
#
# repl-ping-slave-period 10
repl-ping-slave-period <%= @conf_repl_ping_slave_period %>

# The following option sets a timeout for both Bulk transfer I/O timeout and
# master data or ping response timeout. The default value is 60 seconds.
#
# It is important to make sure that this value is greater than the value
# specified for repl-ping-slave-period otherwise a timeout will be detected
# every time there is low traffic between the master and the slave.
#
# repl-timeout 60
repl-timeout <%= @conf_repl_timeout %>

################################## SECURITY ###################################

# Require clients to issue AUTH <PASSWORD> before processing any other
# commands.  This might be useful in environments in which you do not trust
# others with access to the host running redis-server.
#
# This should stay commented out for backward compatibility and because most
# people do not need auth (e.g. they run their own servers).
#
# Warning: since Redis is pretty fast an outside user can try up to
# 150k passwords per second against a good box. This means that you should
# use a very strong password otherwise it will be very easy to break.
#
<% if @conf_requirepass != 'UNSET' %>
requirepass <%= @conf_requirepass %>
<% else %>
# requirepass foobared
<% end %>

# Command renaming.
#
# It is possilbe to change the name of dangerous commands in a shared
# environment. For instance the CONFIG command may be renamed into something
# of hard to guess so that it will be still available for internal-use
# tools but not available for general clients.
#
# Example:
#
# rename-command CONFIG b840fc02d524045429941cc15f59e41cb7be6c52
#
# It is also possilbe to completely kill a command renaming it into
# an empty string:
#
# rename-command CONFIG ""

################################### LIMITS ####################################

# Set the max number of connected clients at the same time. By default there
# is no limit, and it's up to the number of file descriptors the Redis process
# is able to open. The special value '0' means no limits.
# Once the limit is reached Redis will close all the new connections sending
# an error 'max number of clients reached'.
#
# maxclients 128
<% if @conf_maxclients != 'UNSET' %>
maxclients <%= @conf_maxclients %>
<% end %>

# Don't use more memory than the specified amount of bytes.
# When the memory limit is reached Redis will try to remove keys
# accordingly to the eviction policy selected (see maxmemmory-policy).
#
# If Redis can't remove keys according to the policy, or if the policy is
# set to 'noeviction', Redis will start to reply with errors to commands
# that would use more memory, like SET, LPUSH, and so on, and will continue
# to reply to read-only commands like GET.
#
# This option is usually useful when using Redis as an LRU cache, or to set
# an hard memory limit for an instance (using the 'noeviction' policy).
#
# WARNING: If you have slaves attached to an instance with maxmemory on,
# the size of the output buffers needed to feed the slaves are subtracted
# from the used memory count, so that network problems / resyncs will
# not trigger a loop where keys are evicted, and in turn the output
# buffer of slaves is full with DELs of keys evicted triggering the deletion
# of more keys, and so forth until the database is completely emptied.
#
# In short... if you have slaves attached it is suggested that you set a lower
# limit for maxmemory so that there is some free RAM on the system for slave
# output buffers (but this is not needed if the policy is 'noeviction').
#
# maxmemory <bytes>
<% if @conf_maxmemory != 'UNSET' %>
maxmemory <%= @conf_maxmemory %>
<% end %>

# MAXMEMORY POLICY: how Redis will select what to remove when maxmemory
# is reached? You can select among five behavior:
#
# volatile-lru -> remove the key with an expire set using an LRU algorithm
# allkeys-lru -> remove any key accordingly to the LRU algorithm
# volatile-random -> remove a random key with an expire set
# allkeys->random -> remove a random key, any key
# volatile-ttl -> remove the key with the nearest expire time (minor TTL)
# noeviction -> don't expire at all, just return an error on write operations
#
# Note: with all the kind of policies, Redis will return an error on write
#       operations, when there are not suitable keys for eviction.
#
#       At the date of writing this commands are: set setnx setex append
#       incr decr rpush lpush rpushx lpushx linsert lset rpoplpush sadd
#       sinter sinterstore sunion sunionstore sdiff sdiffstore zadd zincrby
#       zunionstore zinterstore hset hsetnx hmset hincrby incrby decrby
#       getset mset msetnx exec sort
#
# The default is:
#
# maxmemory-policy volatile-lru
<% if @conf_maxmemory_policy != 'UNSET' %>
maxmemory-policy <%= @conf_maxmemory_policy %>
<% end %>

# LRU and minimal TTL algorithms are not precise algorithms but approximated
# algorithms (in order to save memory), so you can select as well the sample
# size to check. For instance for default Redis will check three keys and
# pick the one that was used less recently, you can change the sample size
# using the following configuration directive.
#
# maxmemory-samples 3
<% if @conf_maxmemory_samples != 'UNSET' %>
maxmemory-samples <%= @conf_maxmemory_samples %>
<% end %>

############################## APPEND ONLY MODE ###############################

# By default Redis asynchronously dumps the dataset on disk. If you can live
# with the idea that the latest records will be lost if something like a crash
# happens this is the preferred way to run Redis. If instead you care a lot
# about your data and don't want to that a single record can get lost you should
# enable the append only mode: when this mode is enabled Redis will append
# every write operation received in the file appendonly.aof. This file will
# be read on startup in order to rebuild the full dataset in memory.
#
# Note that you can have both the async dumps and the append only file if you
# like (you have to comment the "save" statements above to disable the dumps).
# Still if append only mode is enabled Redis will load the data from the
# log file at startup ignoring the dump.rdb file.
#
# IMPORTANT: Check the BGREWRITEAOF to check how to rewrite the append
# log file in background when it gets too big.

appendonly <%= @conf_appendonly %>

# The name of the append only file (default: "appendonly.aof")
# appendfilename appendonly.aof
<% if @conf_appendfilename != 'UNSET' %>
appendfilename <%= @conf_appendfilename %>
<% end %>

# The fsync() call tells the Operating System to actually write data on disk
# instead to wait for more data in the output buffer. Some OS will really flush
# data on disk, some other OS will just try to do it ASAP.
#
# Redis supports three different modes:
#
# no: don't fsync, just let the OS flush the data when it wants. Faster.
# always: fsync after every write to the append only log . Slow, Safest.
# everysec: fsync only if one second passed since the last fsync. Compromise.
#
# The default is "everysec" that's usually the right compromise between
# speed and data safety. It's up to you to understand if you can relax this to
# "no" that will will let the operating system flush the output buffer when
# it wants, for better performances (but if you can live with the idea of
# some data loss consider the default persistence mode that's snapshotting),
# or on the contrary, use "always" that's very slow but a bit safer than
# everysec.
#
# If unsure, use "everysec".

# appendfsync always
appendfsync <%= @conf_appendfsync %>
# appendfsync no

# When the AOF fsync policy is set to always or everysec, and a background
# saving process (a background save or AOF log background rewriting) is
# performing a lot of I/O against the disk, in some Linux configurations
# Redis may block too long on the fsync() call. Note that there is no fix for
# this currently, as even performing fsync in a different thread will block
# our synchronous write(2) call.
#
# In order to mitigate this problem it's possible to use the following option
# that will prevent fsync() from being called in the main process while a
# BGSAVE or BGREWRITEAOF is in progress.
#
# This means that while another child is saving the durability of Redis is
# the same as "appendfsync none", that in pratical terms means that it is
# possible to lost up to 30 seconds of log in the worst scenario (with the
# default Linux settings).
#
# If you have latency problems turn this to "yes". Otherwise leave it as
# "no" that is the safest pick from the point of view of durability.
no-appendfsync-on-rewrite <%= @conf_no_appendfsync_on_rewrite %>

# Automatic rewrite of the append only file.
# Redis is able to automatically rewrite the log file implicitly calling
# BGREWRITEAOF when the AOF log size will growth by the specified percentage.
#
# This is how it works: Redis remembers the size of the AOF file after the
# latest rewrite (or if no rewrite happened since the restart, the size of
# the AOF at startup is used).
#
# This base size is compared to the current size. If the current size is
# bigger than the specified percentage, the rewrite is triggered. Also
# you need to specify a minimal size for the AOF file to be rewritten, this
# is useful to avoid rewriting the AOF file even if the percentage increase
# is reached but it is still pretty small.
#
# Specify a precentage of zero in order to disable the automatic AOF
# rewrite feature.

auto-aof-rewrite-percentage <%= @conf_auto_aof_rewrite_percentage %>
auto-aof-rewrite-min-size <%= @conf_auto_aof_rewrite_min_size %>

################################## SLOW LOG ###################################

# The Redis Slow Log is a system to log queries that exceeded a specified
# execution time. The execution time does not include the I/O operations
# like talking with the client, sending the reply and so forth,
# but just the time needed to actually execute the command (this is the only
# stage of command execution where the thread is blocked and can not serve
# other requests in the meantime).
#
# You can configure the slow log with two parameters: one tells Redis
# what is the execution time, in microseconds, to exceed in order for the
# command to get logged, and the other parameter is the length of the
# slow log. When a new command is logged the oldest one is removed from the
# queue of logged commands.

# The following time is expressed in microseconds, so 1000000 is equivalent
# to one second. Note that a negative number disables the slow log, while
# a value of zero forces the logging of every command.
slowlog-log-slower-than <%= @conf_slowlog_log_slower_than %>

# There is no limit to this length. Just be aware that it will consume memory.
# You can reclaim memory used by the slow log with SLOWLOG RESET.
slowlog-max-len <%= @conf_slowlog_max_len %>

################################ VIRTUAL MEMORY ###############################

### WARNING! Virtual Memory is deprecated in Redis 2.4
### The use of Virtual Memory is strongly discouraged.

# Virtual Memory allows Redis to work with datasets bigger than the actual
# amount of RAM needed to hold the whole dataset in memory.
# In order to do so very used keys are taken in memory while the other keys
# are swapped into a swap file, similarly to what operating systems do
# with memory pages.
#
# To enable VM just set 'vm-enabled' to yes, and set the following three
# VM parameters accordingly to your needs.

#vm-enabled <%= @conf_vm_enabled %>
# vm-enabled yes

# This is the path of the Redis swap file. As you can guess, swap files
# can't be shared by different Redis instances, so make sure to use a swap
# file for every redis process you are running. Redis will complain if the
# swap file is already in use.
#
# The best kind of storage for the Redis swap file (that's accessed at random)
# is a Solid State Disk (SSD).
#
# *** WARNING *** if you are using a shared hosting the default of putting
# the swap file under /tmp is not secure. Create a dir with access granted
# only to Redis user and configure Redis to create the swap file there.
#vm-swap-file <%= @conf_vm_swap_file %>

# vm-max-memory configures the VM to use at max the specified amount of
# RAM. Everything that deos not fit will be swapped on disk *if* possible, that
# is, if there is still enough contiguous space in the swap file.
#
# With vm-max-memory 0 the system will swap everything it can. Not a good
# default, just specify the max amount of RAM you can in bytes, but it's
# better to leave some margin. For instance specify an amount of RAM
# that's more or less between 60 and 80% of your free RAM.
#vm-max-memory <%= @conf_vm_max_memory %>

# Redis swap files is split into pages. An object can be saved using multiple
# contiguous pages, but pages can't be shared between different objects.
# So if your page is too big, small objects swapped out on disk will waste
# a lot of space. If you page is too small, there is less space in the swap
# file (assuming you configured the same number of total swap file pages).
#
# If you use a lot of small objects, use a page size of 64 or 32 bytes.
# If you use a lot of big objects, use a bigger page size.
# If unsure, use the default :)
#vm-page-size <%= @conf_vm_page_size %>

# Number of total memory pages in the swap file.
# Given that the page table (a bitmap of free/used pages) is taken in memory,
# every 8 pages on disk will consume 1 byte of RAM.
#
# The total swap size is vm-page-size * vm-pages
#
# With the default of 32-bytes memory pages and 134217728 pages Redis will
# use a 4 GB swap file, that will use 16 MB of RAM for the page table.
#
# It's better to use the smallest acceptable value for your application,
# but the default is large in order to work in most conditions.
#vm-pages <%= @conf_vm_pages %>

# Max number of VM I/O threads running at the same time.
# This threads are used to read/write data from/to swap file, since they
# also encode and decode objects from disk to memory or the reverse, a bigger
# number of threads can help with big objects even if they can't help with
# I/O itself as the physical device may not be able to couple with many
# reads/writes operations at the same time.
#
# The special value of 0 turn off threaded I/O and enables the blocking
# Virtual Memory implementation.
#vm-max-threads <%= @conf_vm_max_threads %>

############################### ADVANCED CONFIG ###############################

# Hashes are encoded in a special way (much more memory efficient) when they
# have at max a given numer of elements, and the biggest element does not
# exceed a given threshold. You can configure this limits with the following
# configuration directives.
#hash-max-zipmap-entries <%= @conf_hash_max_zipmap_entries %>
#hash-max-zipmap-value <%= @conf_hash_max_zipmap_value %>

# Similarly to hashes, small lists are also encoded in a special way in order
# to save a lot of space. The special representation is only used when
# you are under the following limits:
list-max-ziplist-entries <%= @conf_list_max_ziplist_entries %>
list-max-ziplist-value <%= @conf_list_max_ziplist_value %>

# Sets have a special encoding in just one case: when a set is composed
# of just strings that happens to be integers in radix 10 in the range
# of 64 bit signed integers.
# The following configuration setting sets the limit in the size of the
# set in order to use this special memory saving encoding.
set-max-intset-entries <%= @conf_set_max_intset_entries %>

# Similarly to hashes and lists, sorted sets are also specially encoded in
# order to save a lot of space. This encoding is only used when the length and
# elements of a sorted set are below the following limits:
zset-max-ziplist-entries <%= @conf_zset_max_ziplist_entries %>
zset-max-ziplist-value <%= @conf_zset_max_ziplist_value %>

# Active rehashing uses 1 millisecond every 100 milliseconds of CPU time in
# order to help rehashing the main Redis hash table (the one mapping top-level
# keys to values). The hash table implementation redis uses (see dict.c)
# performs a lazy rehashing: the more operation you run into an hash table
# that is rhashing, the more rehashing "steps" are performed, so if the
# server is idle the rehashing is never complete and some more memory is used
# by the hash table.
#
# The default is to use this millisecond 10 times every second in order to
# active rehashing the main dictionaries, freeing memory when possible.
#
# If unsure:
# use "activerehashing no" if you have hard latency requirements and it is
# not a good thing in your environment that Redis can reply form time to time
# to queries with 2 milliseconds delay.
#
# use "activerehashing yes" if you don't have such hard requirements but
# want to free memory asap when possible.
activerehashing <%= @conf_activerehashing %>

################################## INCLUDES ###################################

# Include one or more other config files here.  This is useful if you
# have a standard template that goes to all redis server but also need
# to customize a few per-server settings.  Include files can include
# other files, so use this wisely.
#
# include /path/to/local.conf
# include /path/to/other.conf
<% if @conf_include != 'UNSET' %>
include <%= @conf_include %>
<% end %>
node default {

  package { 'epel-release':
    ensure   => present,
    source   => 'http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm',
    provider => rpm,
  }

  class { 'redis':
    conf_port     => '6379',
    conf_bind     => '0.0.0.0',
    system_sysctl => true,
  }

}
FROM centos:latest
MAINTAINER Carlos Sanchez <carlos@apache.org>

RUN rpm --import https://yum.puppetlabs.com/RPM-GPG-KEY-puppetlabs && \
    rpm -ivh http://yum.puppetlabs.com/puppetlabs-release-el-6.noarch.rpm

# Need to enable centosplus for the image libselinux issue
RUN yum install -y yum-utils
RUN yum-config-manager --enable centosplus

RUN yum update -y
RUN yum install -y puppet tar
RUN puppet module install maestrodev/rvm
RUN puppet module install stahnma/epel

ADD tests/common.yaml /var/lib/hiera/
ADD tests/site.pp /etc/puppet/manifests/

RUN puppet apply /etc/puppet/manifests/site.pp --verbose

CMD ["/bin/bash"]
source 'https://rubygems.org'

group :rake do
  gem 'puppet', ENV['PUPPET_VERSION'] || '>=3.0.0', :require => false
  gem 'rspec-puppet', '>=1.0.0', :require => false
  gem 'rake', :require => false
  gem 'puppet-lint', '>=1.0.0', :require => false
  gem 'puppetlabs_spec_helper', :require => false
  gem 'puppet-blacksmith', '>=1.0.5', :require => false
  gem 'librarian-puppet', '>=2.0.0', :require => false
  gem 'beaker', '>=1.14.0', :require => false
  gem 'beaker-rspec', '>=2.1.0', :require => false
  gem 'minitest', '<5.0.0', :require => false # conflicts with beaker
end
GEM
  remote: https://rubygems.org/
  specs:
    CFPropertyList (2.2.8)
    activemodel (4.0.12)
      activesupport (= 4.0.12)
      builder (~> 3.1.0)
    activesupport (4.0.12)
      i18n (~> 0.6, >= 0.6.9)
      minitest (~> 4.2)
      multi_json (~> 1.3)
      thread_safe (~> 0.1)
      tzinfo (~> 0.3.37)
    addressable (2.3.6)
    archive-tar-minitar (0.5.2)
    autoparse (0.3.3)
      addressable (>= 2.3.1)
      extlib (>= 0.9.15)
      multi_json (>= 1.0.0)
    aws-sdk (1.42.0)
      json (~> 1.4)
      nokogiri (>= 1.4.4)
    beaker (1.20.1)
      aws-sdk (= 1.42.0)
      blimpy (~> 0.6)
      docker-api
      fission (~> 0.4)
      fog (~> 1.22.1)
      google-api-client (~> 0.7.1)
      hocon (~> 0.0.4)
      inifile (~> 2.0)
      json (~> 1.8)
      mime-types (~> 1.25)
      net-scp (~> 1.1)
      net-ssh (~> 2.6)
      nokogiri (~> 1.5.10)
      rbvmomi (= 1.8.1)
      unf (~> 0.1)
    beaker-rspec (3.0.0)
      beaker (~> 1.10)
      rspec
      serverspec (~> 1.0)
      specinfra (~> 1.0)
    blimpy (0.6.7)
      fog
      minitar
      thor
    builder (3.1.4)
    diff-lcs (1.2.5)
    docker-api (1.15.0)
      archive-tar-minitar
      excon (>= 0.38.0)
      json
    excon (0.41.0)
    extlib (0.9.16)
    facter (2.3.0)
      CFPropertyList (~> 2.2.6)
    faraday (0.9.0)
      multipart-post (>= 1.2, < 3)
    fission (0.5.0)
      CFPropertyList (~> 2.2)
    fog (1.22.1)
      fog-brightbox
      fog-core (~> 1.22)
      fog-json
      ipaddress (~> 0.5)
      nokogiri (~> 1.5, >= 1.5.11)
    fog-brightbox (0.6.1)
      fog-core (~> 1.22)
      fog-json
      inflecto
    fog-core (1.25.0)
      builder
      excon (~> 0.38)
      formatador (~> 0.2)
      mime-types
      net-scp (~> 1.1)
      net-ssh (>= 2.1.3)
    fog-json (1.0.0)
      multi_json (~> 1.0)
    formatador (0.2.5)
    google-api-client (0.7.1)
      addressable (>= 2.3.2)
      autoparse (>= 0.3.3)
      extlib (>= 0.9.15)
      faraday (>= 0.9.0)
      jwt (>= 0.1.5)
      launchy (>= 2.1.1)
      multi_json (>= 1.0.0)
      retriable (>= 1.4)
      signet (>= 0.5.0)
      uuidtools (>= 2.1.0)
    her (0.7.2)
      activemodel (>= 3.0.0, < 4.2)
      activesupport (>= 3.0.0, < 4.2)
      faraday (>= 0.8, < 1.0)
      multi_json (~> 1.7)
    hiera (1.3.4)
      json_pure
    highline (1.6.21)
    hocon (0.0.6)
    i18n (0.6.11)
    inflecto (0.0.2)
    inifile (2.0.2)
    ipaddress (0.8.0)
    json (1.8.1)
    json_pure (1.8.1)
    jwt (1.0.0)
    launchy (2.4.3)
      addressable (~> 2.3)
    librarian (0.1.2)
      highline
      thor (~> 0.15)
    librarian-puppet (2.0.0)
      librarian (>= 0.1.2)
      puppet_forge
      rsync
    metaclass (0.0.4)
    mime-types (1.25.1)
    minitar (0.5.4)
    minitest (4.7.5)
    mocha (1.1.0)
      metaclass (~> 0.0.1)
    multi_json (1.10.1)
    multipart-post (2.0.0)
    net-scp (1.2.1)
      net-ssh (>= 2.6.5)
    net-ssh (2.9.1)
    netrc (0.8.0)
    nokogiri (1.5.11)
    puppet (3.7.3)
      facter (> 1.6, < 3)
      hiera (~> 1.0)
      json_pure
    puppet-blacksmith (3.0.3)
      puppet (>= 2.7.16)
      rest-client
    puppet-lint (1.1.0)
    puppet-syntax (1.3.0)
      rake
    puppet_forge (1.0.3)
      her (~> 0.6)
    puppetlabs_spec_helper (0.8.2)
      mocha
      puppet-lint
      puppet-syntax
      rake
      rspec
      rspec-puppet
    rake (10.3.2)
    rbvmomi (1.8.1)
      builder
      nokogiri (>= 1.4.1)
      trollop
    rest-client (1.7.2)
      mime-types (>= 1.16, < 3.0)
      netrc (~> 0.7)
    retriable (1.4.1)
    rspec (2.99.0)
      rspec-core (~> 2.99.0)
      rspec-expectations (~> 2.99.0)
      rspec-mocks (~> 2.99.0)
    rspec-core (2.99.2)
    rspec-expectations (2.99.2)
      diff-lcs (>= 1.1.3, < 2.0)
    rspec-its (1.0.1)
      rspec-core (>= 2.99.0.beta1)
      rspec-expectations (>= 2.99.0.beta1)
    rspec-mocks (2.99.2)
    rspec-puppet (1.0.1)
      rspec
    rsync (1.0.9)
    serverspec (1.16.0)
      highline
      net-ssh
      rspec (~> 2.99)
      rspec-its
      specinfra (~> 1.27)
    signet (0.5.1)
      addressable (>= 2.2.3)
      faraday (>= 0.9.0.rc5)
      jwt (>= 0.1.5)
      multi_json (>= 1.0.0)
    specinfra (1.27.5)
    thor (0.19.1)
    thread_safe (0.3.4)
    trollop (2.0)
    tzinfo (0.3.42)
    unf (0.1.4)
      unf_ext
    unf_ext (0.0.6)
    uuidtools (2.1.5)

PLATFORMS
  ruby

DEPENDENCIES
  beaker (>= 1.14.0)
  beaker-rspec (>= 2.1.0)
  librarian-puppet (>= 2.0.0)
  minitest (< 5.0.0)
  puppet (>= 3.0.0)
  puppet-blacksmith (>= 1.0.5)
  puppet-lint (>= 1.0.0)
  puppetlabs_spec_helper
  rake
  rspec-puppet (>= 1.0.0)
Copyright (c) 2012-2013, MaestroDev, Brandon Turner
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of Brandon Turner nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL BRANDON TURNER BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
forge 'http://forge.puppetlabs.com'

metadata

mod 'puppetlabs/apache', '>= 1.1.0'
FORGE
  remote: http://forge.puppetlabs.com
  specs:
    puppetlabs/apache (1.1.0)
      puppetlabs/concat (>= 1.0.0)
      puppetlabs/stdlib (>= 2.4.0)
    puppetlabs/concat (1.1.0)
      puppetlabs/stdlib (>= 4.0.0)
    puppetlabs/stdlib (4.3.2)

DEPENDENCIES
  puppetlabs/apache (>= 1.1.0)
  puppetlabs/stdlib (>= 3.2.0)

Puppet Module for Ruby Version Manager (RVM)
==============================================

[![Build Status](https://maestro.maestrodev.com/api/v1/projects/24/compositions/324/badge/icon)](https://maestro.maestrodev.com/projects/24/compositions/324)

This module handles installing system RVM (also known as multi-user installation
as root) and using it to install rubies and gems.  Support for installing and
configuring passenger is also included.

We are actively using this module.  It works well, but does have some issues you
should be aware of.  Due to the way puppet works, certain resources
(rvm\_sytem\_ruby, rvm\_gem and rvm\_gemset) may generate errors until RVM is
installed.  You may want to use run stages to install RVM before the rest
of your configuration runs.  However, if you run puppet using the `--noop`
parameter, you may see _Could not find a default provider_ errors.  See the
Troubleshooting section for more information.

Please read the troubleshooting section below before opening an issue.


## System Requirements

Puppet 3.0.0 or higher.

## Upgrading

Version 1.5 no longer includes a dependency on puppetlabs/apache, you must install it yourself
if you want to use the passenger module.

## Add Puppet Module

Before you begin, you must add the RVM module to your Puppet installation.  This can be done with:

    $ puppet module install maestrodev/rvm

You may now continue configuring RVM resources.


## Install RVM with Puppet

Install RVM with:

    include rvm

or

    class { 'rvm': version => '1.20.12' }

This will install RVM into `/usr/local/rvm`.

To use RVM without sudo, users need to be added to the `rvm` group.  This can be easily done with:

    rvm::system_user { bturner: ; jdoe: ; jsmith: ; }


## Installing Ruby

You can tell RVM to install one or more Ruby versions with:

    rvm_system_ruby {
      'ruby-1.9':
        ensure      => 'present',
        default_use => true,
        build_opts  => ['--binary'];
      'ruby-2.0':
        ensure      => 'present',
        default_use => false;
    }

You should use the full version number.  While the shorthand version may work (e.g. '1.9.2'), the provider will be unable to detect if the correct version is installed.

If rvm fails to install binary rubies you can increase curl's timeout with the `rvm_max_time_flag` in `~/.rvmrc` with a fully qualified path to the home directory.

    # ensure rvm doesn't timeout finding binary rubies
    # the umask line is the default content when installing rvm if file does not exist
    file { '/home/user/rvmrc':
      content => 'umask u=rwx,g=rwx,o=rx
                  export rvm_max_time_flag=20',
      mode    => '0664',
      before  => Class['rvm'],
    }

Or, to configure `/etc/rvmrc` you can use use `Class['rvm::rvmrc]`

    class{ 'rvm::rvmrc':
      max_time_flag => 20,
      before  => Class['rvm'],
    }

### Installing JRuby from sources

JRuby has some extra requirements, java, maven and ant that you can install using
[puppetlabs/java](http://forge.puppetlabs.com/puppetlabs/java),
[maestrodev/ant](http://forge.puppetlabs.com/maestrodev/ant) and
[maestrodev/maven](http://forge.puppetlabs.com/maestrodev/maven) modules.

    class { 'java': } ->
    class { 'ant': } ->
    class { 'maven::maven': } ->
    rvm_system_ruby { 'jruby-1.7.6':
      ensure      => 'present',
      default_use => false;
    }


## Creating Gemsets

Create a gemset with:

    rvm_gemset {
      'ruby-1.9.3-p448@myproject':
        ensure  => present,
        require => Rvm_system_ruby['ruby-1.9.3-p448'];
    }


## Installing Gems

Install a gem with:

    rvm_gem {
      'ruby-1.9.3-p448@myproject/bundler':
        ensure  => '1.0.21',
        require => Rvm_gemset['ruby-1.9.3-p448@myproject'];
    }

The *name* of the gem should be `<ruby-version>[@<gemset>]/<gemname>`.  For example, you can install bundler for ruby-1.9.2 using `ruby-1.9.3-p448/bundler`.  You could install rails in your project's gemset with: `ruby-1.9.3-p448@myproject/rails`.

Alternatively, you can use this more verbose syntax:

    rvm_gem {
      'bundler':
        name         => 'bundler',
        ruby_version => 'ruby-1.9.3-p448',
        ensure       => latest,
        require      => Rvm_system_ruby['ruby-1.9.3-p448'];
    }

## Creating Aliases

To create an RVM alias, you can use:

    rvm_alias {
      'myproject':
        target_ruby => 'ruby-1.9.3-p448@myproject',
        ensure      => present,
        require     => Rvm_gemset['ruby-1.9.3-p448@myproject'];
    }

## Creating Wrappers

To create an RVM wrapper, you can use:

    rvm_wrapper {
      'god':
        target_ruby => 'ruby-1.9.3-p448',
        prefix      => 'bootup',
        ensure      => present,
        require     => Rvm_system_ruby['ruby-1.9.3-p448'];
    }

## Installing Passenger

NOTE: You must install the [puppetlabs/apache](http://forge.puppetlabs.com/puppetlabs/apache) module by yourself.
It is not included as a dependency to this module to avoid installing it when is not needed most times.

Install passenger using the [puppetlabs/apache](http://forge.puppetlabs.com/puppetlabs/apache) module,
and using:

    class { 'apache': }
    class { 'rvm::passenger::apache':
        version            => '3.0.11',
        ruby_version       => 'ruby-1.9.3-p448',
        mininstances       => '3',
        maxinstancesperapp => '0',
        maxpoolsize        => '30',
        spawnmethod        => 'smart-lv2',
    }

## Using Hiera

You can configure the ruby versions to be installed and the system users from hiera

    rvm::system_rubies:
      '1.9':
        default_use: true
      '2.0': {}
      'jruby-1.7': {}

    rvm::system_users:
      - john
      - doe


## Building the module

Testing is done with rspec, [Beaker-rspec](https://github.com/puppetlabs/beaker-rspec), [Beaker](https://github.com/puppetlabs/beaker))

To test and build the module

    bundle install
    # run specs
    rake

    # run Beaker system tests with vagrant vms
    rake beaker
    # to use other vm from the list spec/acceptance/nodesets and not destroy the vm after the tests
    BEAKER_destroy=no BEAKER_set=centos-64-x64 bundle exec rake beaker

    # Release the Puppet module to the Forge, doing a clean, build, tag, push, bump_commit and git push
    rake module:release

## Troubleshooting / FAQ

### An error "Could not find a default provider for rvm\_system\_ruby" is displayed when running Puppet with --noop

This means that puppet cannot find the `/usr/local/rvm/bin/rvm` command
(probably because RVM isn't installed yet).  Currently, Puppet does not support
making a provider suitable using another resource (late-binding).  You may want
to use run stages to install RVM before the rest of the
configuration runs.  When running in _noop_ mode, RVM is not actually installed
causing rvm\_system\_ruby, rvm\_gem and rvm\_gemset resources to generate this
error.  You can avoid this error by surrounding your rvm configuration in an if
block:

    if $rvm_installed == "true" {
        rvm_system_ruby ...
    }

Do not surround `include rvm` in the if block, as this is used to install RVM.

NOTE: $rvm\_installed is evaluated at the beginning of each puppet run.  If you
use this in your manifests, you will need to run puppet twice to fully
configure RVM.

### An error "Resource type rvm_gem does not support parameter false" prevents puppet from running.

The RVM module requires Puppet version 2.6.7 or higher.

There is a bug in Puppet versions 2.7.4 through 2.7.9 that also causes this
error.  The error can be safely ignored in these versions.  For best results,
upgrade to Puppet 2.7.10.


### Some packages/libraries I don't want or need are installed (e.g. build-essential, libc6-dev, libxml2-dev).

RVM works by compiling Ruby from source.  This means you must have all the libraries and binaries required to compile Ruby installed on your system, which is handled by rvm autolibs in newer versions of RVM.


### It doesn't work on my operating system.

Check the rspec-system tests as described above to test in a specific OS
If that doesn't work feel free to send a pull request ;)


### Why didn't you just add an RVM provider for the existing package type?

The puppet [package](http://docs.puppetlabs.com/references/latest/type.html#package)
type seems like an obvious place for the RVM provider.  It would be nice if the syntax
for installing Ruby with RVM looked like:

    # NOTE: This does not work
    package {'ruby':
        provider => 'rvm',
        ensure => '1.9.2-p290';
    }

While this may be possible, it becomes harder to manage multiple Ruby versions and
nearly impossible to install gems for a specific Ruby version.  For this reason,
I decided it was best to create a completely new set of types for RVM.

require 'rake/clean'

CLEAN.include('spec/fixtures/manifests/', 'spec/fixtures/modules/', 'doc', 'pkg')
CLOBBER.include('.tmp', '.librarian')

require 'puppetlabs_spec_helper/rake_tasks'
require 'puppet_blacksmith/rake_tasks'

require 'puppet-lint/tasks/puppet-lint'
PuppetLint.configuration.send("disable_80chars")
PuppetLint.configuration.send('disable_class_inherits_from_params_class')
PuppetLint.configuration.fail_on_warnings = true
PuppetLint.configuration.relative = true

# use librarian-puppet to manage fixtures instead of .fixtures.yml
# offers more possibilities like explicit version management, forge
# downloads,...
task :librarian_spec_prep do
 sh "librarian-puppet install --path=spec/fixtures/modules/"
end
task :spec_prep => :librarian_spec_prep

require 'rspec/core/rake_task'
RSpec::Core::RakeTask.new(:beaker) do |c|
  c.pattern = "spec/acceptance/**/*_spec.rb"
end
task :beaker => :librarian_spec_prep

task :default => [:clean, :lint, :spec]
{
  "Dockerfile": "212c5e7a95fbf3fa3094be01f92f6e84",
  "Gemfile": "6091853b663cd471db389c986b52682d",
  "Gemfile.lock": "5a1b0df4ae7bbd19f7a17055015f4004",
  "LICENSE": "c09f1ff12ffc19bb5aa3ca918d6496c7",
  "Puppetfile": "3e0e8b7a7a4cbc0d7d9dc17318042ba1",
  "Puppetfile.lock": "706fa05484afd0407dd80d9fcbf17f8b",
  "README.markdown": "cc6153a4e89f2f8ceddecd2ccb9bfb85",
  "Rakefile": "c87c1fd9eea4933b275dbdfa9cf1ade0",
  "lib/facter/rvm_installed.rb": "17880333546300f31ee0b924dc0e7135",
  "lib/facter/rvm_version.rb": "83ce2d25f399adbcbc04c9f441066c8b",
  "lib/puppet/provider/rvm_alias/alias.rb": "7f422f68856ffa399a7d564fc7cdc62e",
  "lib/puppet/provider/rvm_gem/gem.rb": "270580ab370c1b8268e354b86185ed18",
  "lib/puppet/provider/rvm_gemset/gemset.rb": "a7636d1c484444c64c1aad1be2c2d30a",
  "lib/puppet/provider/rvm_system_ruby/rvm_system_ruby.rb": "a00210df670b29779c3a37b862cfa34b",
  "lib/puppet/provider/rvm_wrapper/wrapper.rb": "238ba3f4d28a019952a99bbdde35f675",
  "lib/puppet/type/rvm_alias.rb": "33c703a7c346235f0dba87de1a43a859",
  "lib/puppet/type/rvm_gem.rb": "d61f03748c4344ea3955c029a2b5bd90",
  "lib/puppet/type/rvm_gemset.rb": "9f7d37bc51c2b75a288ea4edca5f57a8",
  "lib/puppet/type/rvm_system_ruby.rb": "bc04967cdf93e46492e1ce7507b1e8a5",
  "lib/puppet/type/rvm_wrapper.rb": "4e85d8d1c7bae4a7549e7f0edbcbc4df",
  "manifests/dependencies/centos.pp": "d0b6fb9803c92a1ed02a3ba30e94be7a",
  "manifests/dependencies/oraclelinux.pp": "3f60f61da00a2e41109058fe70ed7536",
  "manifests/dependencies/ubuntu.pp": "c18938a26d927f3c4f3a64bddd3b1948",
  "manifests/dependencies.pp": "421d1b11cb1395ee0d2f3763e75d8c72",
  "manifests/gpg.pp": "f08fe68d273591aa86de372a6dc2af25",
  "manifests/group.pp": "ac396e22475220c972a6777ea03f26b8",
  "manifests/init.pp": "6b06083a0c5abd39d03df6e242a6afb9",
  "manifests/params.pp": "b71cd37117e6ac9150c067bfa649eee9",
  "manifests/passenger/apache.pp": "9051c6413fa51e8023adb3e190c75f89",
  "manifests/passenger/dependencies/centos.pp": "9f3179196388289f0aff232dab6468fb",
  "manifests/passenger/dependencies/oraclelinux.pp": "388ca20676c972d2a85790374adae45f",
  "manifests/passenger/dependencies/ubuntu.pp": "1a61e3cb072c82f68d8ff604f1e59e47",
  "manifests/passenger/dependencies.pp": "e819338156ed5965ebdbc76f6b698a75",
  "manifests/passenger/gem.pp": "80587f1bc2beab8b91f3b54932e60e7c",
  "manifests/rvmrc.pp": "ad57fbdd2a7e471e89393545fbd36b10",
  "manifests/system.pp": "517eae960644e3dd3e8970f58716ca66",
  "manifests/system_user.pp": "a820a7af8120f0595cf8f0bd22c79bc6",
  "metadata.json": "7ba81b6baf6288e625f2d9b46751984a",
  "spec/acceptance/nodesets/centos-64-x64.yml": "d65958bdf25fb31eb4838fd984b555df",
  "spec/acceptance/nodesets/centos-65-x64-docker.yml": "e1814bf97de6f03758bcec39d80d725b",
  "spec/acceptance/nodesets/centos-65-x64.yml": "d5644c01c7955069665ac1d08b36aa6a",
  "spec/acceptance/nodesets/debian-73-x64.yml": "df78f357e1bd0f7f9818d552eeb35026",
  "spec/acceptance/nodesets/default.yml": "e1814bf97de6f03758bcec39d80d725b",
  "spec/acceptance/nodesets/ubuntu-server-12042-x64.yml": "c4f1b8b8c0272ea63c78732c55f7d154",
  "spec/acceptance/nodesets/ubuntu-server-1310-x64.yml": "9deb39279e104d765179b471c6ebb3a2",
  "spec/acceptance/rvm_system_spec.rb": "b78e61f0ffa98ce0d5e3765b828d21e2",
  "spec/classes/dependencies_spec.rb": "d40ac9bd6ce9b4bf96d8fc2ce5740b6c",
  "spec/classes/gpg_spec.rb": "b3a9ee65622128221378914b0dc5f088",
  "spec/classes/init_spec.rb": "0c71abd2e8f5f4eab7b9248b462d24d4",
  "spec/classes/rvmrc_spec.rb": "8a89f89ca9b7b9ec1d5c9bc2868be646",
  "spec/classes/system_spec.rb": "02a1a0657d40c754e15a3bc11db8e21b",
  "spec/defines/rvm_alias_spec.rb": "83c263ca60fd32aec9fbccc8f3679e83",
  "spec/defines/rvm_gem_spec.rb": "c26c78f19676b8a03e96bd30625ab2fb",
  "spec/defines/rvm_gemset_spec.rb": "ae6518149a7100a1f35a80a919b1f55f",
  "spec/defines/rvm_system_ruby_spec.rb": "328be8c8810d2a9acf8b8f4799cefc33",
  "spec/defines/rvm_wrapper_spec.rb": "a37c75e48716ce92e2ad5381c821397f",
  "spec/defines/system_user_spec.rb": "7899c7147abbc4c3a9f7f0c5e3f0e81a",
  "spec/spec_helper.rb": "f02508cd8c5e584edb962e3579cdcd80",
  "spec/spec_helper_acceptance.rb": "3fb3bf87c0a0be4baecab8ec3c9fbb07",
  "templates/rvmrc.erb": "a3e3e312817a572a6f148891d27d7d86",
  "tests/common.yaml": "f0df94cc55cef2100e3a0fb9f917283f",
  "tests/init.pp": "7096c96ab9b56ee1dab6e2b5754e770a",
  "tests/site.pp": "7096c96ab9b56ee1dab6e2b5754e770a"
}
Facter.add("rvm_installed") do
  rvm_binary = "/usr/local/rvm/bin/rvm"

  setcode do
    File.exists? rvm_binary
  end
end
Facter.add("rvm_version") do
  rvm_binary = "/usr/local/rvm/bin/rvm"

  setcode do
    File.exists?(rvm_binary) ? `#{rvm_binary} version`.strip.match(/rvm ([0-9]+\.[0-9]+\.[0-9]+) .*/)[1] : nil
  end
end
# RVM gemset support
Puppet::Type.type(:rvm_alias).provide(:alias) do
  desc "RVM alias support."

  has_command(:rvmcmd, '/usr/local/rvm/bin/rvm') do
    environment :HOME => ENV['HOME']
  end

  def target_ruby
    resource[:target_ruby]
  end

  def alias_name
    resource[:name]
  end

  def aliascmd
    [command(:rvmcmd), "alias"]
  end

  def alias_list
    command = aliascmd + ['list']

    list = []
    begin
      list = execute(command)
    rescue Puppet::ExecutionFailure => detail
    end

    list.to_s
  end

  def create
    command = aliascmd + ['create', alias_name, target_ruby]
    execute(command)
  end

  def destroy
    command = aliascmd + ['delete', alias_name]
    execute(command)
  end

  def exists?
    alias_list.match("#{alias_name} => #{target_ruby}")
  end
end
require 'puppet/provider/package'
require 'uri'

# Ruby gems support.
Puppet::Type.type(:rvm_gem).provide(:gem) do
  desc "Ruby Gem support using RVM."

  has_feature :versionable
  has_command(:rvmcmd, '/usr/local/rvm/bin/rvm') do
    environment :HOME => ENV['HOME']
  end


  def ruby_version
    resource[:ruby_version]
  end

  def gembinary
    [command(:rvmcmd), ruby_version, "do", "gem"]
  end


  def gemlist(hash)
    command = gembinary + ['list']

    if hash[:local]
      command << "--local"
    else
      command << "--remote"
    end

    if name = hash[:justme]
      command << name + "$"
    end

    # use proxy if proxy_url is set
    if resource[:proxy_url] and !resource[:proxy_url].empty?
      command << "--http-proxy" << resource[:proxy_url]
    end

    list = []
    begin
      list = execute(command).split("\n").collect do |set|
        if gemhash = self.class.gemsplit(set)
          gemhash[:provider] = :gem
          gemhash
        else
          nil
        end
      end.compact
    rescue Puppet::ExecutionFailure => detail
    end

    if hash[:justme]
      return list.shift
    else
      return list
    end
  end

  def self.gemsplit(desc)
    case desc
    when /^\*\*\*/, /^\s*$/, /^\s+/; return nil
    when /gem: not found/; return nil
    # when /^(\S+)\s+\((((((\d+[.]?))+)(,\s)*)+)\)/
    when /^(\S+)\s+\((\d+.*)\)/
      name = $1
      version = $2.split(/,\s*/)
      return {
        :name => name,
        :ensure => version
      }
    else
      Puppet.warning "Could not match #{desc}"
      nil
    end
  end


  def install(useversion = true)
    command = gembinary + ['install']
    command << "-v" << resource[:ensure] if (! resource[:ensure].is_a? Symbol) and useversion
    # Dependencies are now installed by default
    # command << "--include-dependencies"

    # use proxy if proxy_url is set
    if resource[:proxy_url] and !resource[:proxy_url].empty?
      command << "--http-proxy" << resource[:proxy_url]
    end

    if source = resource[:source]
      begin
        uri = URI.parse(source)
      rescue => detail
        fail "Invalid source '#{uri}': #{detail}"
      end

      case uri.scheme
      when nil
        # no URI scheme => interpret the source as a local file
        command << source
      when /file/i
        command << uri.path
      when 'puppet'
        # we don't support puppet:// URLs (yet)
        raise Puppet::Error.new("puppet:// URLs are not supported as gem sources")
      else
        # interpret it as a gem repository
        command << "--source" << "#{source}" << resource[:name]
      end
    else
      command << "--no-rdoc" << "--no-ri" <<  resource[:name]
    end

    # makefile opts,
    # must be last
    if resource[:withopts]
      command << "--" << resource[:withopts]
    end

    output = execute(command)
    # Apparently some stupid gem versions don't exit non-0 on failure
    self.fail "Could not install: #{output.chomp}" if output.include?("ERROR")
  end

  def latest
    # This always gets the latest version available.
    hash = gemlist(:justme => resource[:name])

    hash[:ensure][0]
  end

  def query
    gemlist(:justme => resource[:name], :local => true)
  end

  def uninstall
    execute(gembinary + ["uninstall", "-x", "-a", resource[:name]])
  end

  def update
    self.install(false)
  end
end
# RVM gemset support
Puppet::Type.type(:rvm_gemset).provide(:gemset) do
  desc "RVM gemset support."

  has_command(:rvmcmd, '/usr/local/rvm/bin/rvm') do
    environment :HOME => ENV['HOME']
  end

  def ruby_version
    resource[:ruby_version]
  end

  def gemset_name
    resource[:name]
  end

  def gemsetcommand
    [command(:rvmcmd), ruby_version, "exec", "rvm", "gemset"]
  end

  def gemsetcommand_force
    [command(:rvmcmd), ruby_version, "exec", "rvm", "--force", "gemset"]
  end

  def gemset_list
    command = gemsetcommand + ['list']

    # use proxy if proxy_url is set
    if resource[:proxy_url] and !resource[:proxy_url].empty?
      command << "--http-proxy" << resource[:proxy_url]
    end

    list = []
    begin
      list = execute(command).split("\n").collect do |line|
        line.strip if line =~ /^\s+\S+/
      end.compact
    rescue Puppet::ExecutionFailure => detail
    end

    list
  end

  def create
    command = gemsetcommand + ['create', gemset_name]
    execute(command)
  end

  def destroy
    command = gemsetcommand_force + ['delete', gemset_name]
    execute(command)
  end

  def exists?
    gemset_list.include? gemset_name
  end
end
Puppet::Type.type(:rvm_system_ruby).provide(:rvm) do
  desc "Ruby RVM support."

  has_command(:rvmcmd, '/usr/local/rvm/bin/rvm') do
    environment :HOME => ENV['HOME']
  end

  def create
    unless resource[:proxy_url].nil?
      ENV['http_proxy'] = resource[:proxy_url]
      ENV['https_proxy'] = resource[:proxy_url]
    end
    set_autolib_mode if resource.value(:autolib_mode)
    options = Array(resource[:build_opts])
    if resource[:proxy_url] and !resource[:proxy_url].empty?
      rvmcmd "install", resource[:name], "--proxy", resource[:proxy_url], *options
    else
      rvmcmd "install", resource[:name], *options
    end
    set_default if resource.value(:default_use)
  end

  def destroy
    rvmcmd "uninstall", resource[:name]
  end

  def exists?
    begin
      rvmcmd("list", "strings").split("\n").any? do |line|
        line =~ Regexp.new(Regexp.escape(resource[:name]))
      end
    rescue Puppet::ExecutionFailure => detail
      raise Puppet::Error, "Could not list RVMs: #{detail}"
    end

  end

  def default_use
    begin
      rvmcmd("list", "default").split("\n").any? do |line|
        line =~ Regexp.new(Regexp.escape(resource[:name]))
      end
    rescue Puppet::ExecutionFailure => detail
      raise Puppet::Error, "Could not list default RVM: #{detail}"
    end
  end

  def default_use=(value)
    set_default if value
  end

  def set_default
    rvmcmd "alias", "create", "default", resource[:name]
  end

  def set_autolib_mode
    begin
      rvmcmd "autolibs", resource[:autolib_mode]
    rescue Puppet::ExecutionFailure => detail
      raise Puppet::Error, "Could not set autolib mode: #{detail}"
    end
  end
end
# RVM gemset support
Puppet::Type.type(:rvm_wrapper).provide(:wrapper) do
  desc "RVM wrapper support."

  has_command(:rvmcmd, '/usr/local/rvm/bin/rvm') do
    environment :HOME => ENV['HOME']
  end

  def target_ruby
    resource[:target_ruby]
  end

  def wrapper_name
    resource[:name]
  end

  def prefix
    resource[:prefix]
  end

  def wrapper_filename
    filename = prefix ? "#{prefix}_#{wrapper_name}" : wrapper_name
    "/usr/local/rvm/bin/#{filename}"
  end

  def create
    execute([command(:rvmcmd), "wrapper", target_ruby, prefix || "--no-prefix", wrapper_name])
  end

  def destroy
    File.delete wrapper_filename
  end

  def exists?
    File.exists? wrapper_filename
  end
end
Puppet::Type.newtype(:rvm_alias) do
  @doc = "Manage RVM Aliases."

  ensurable

  autorequire(:rvm_system_ruby) do
    [self[:target_ruby]]
  end

  newparam(:name) do
    desc "The name of the alias to be managed."
    isnamevar
  end

  newparam(:target_ruby) do
    desc "The ruby version that is the target of our alias.
    For example: 'ruby-1.9.2-p290'"
  end

end
Puppet::Type.newtype(:rvm_gem) do
  @doc = "Ruby Gem support using RVM."

  def self.title_patterns
    [ [ /^(?:(.*)\/)?(.*)$/, [ [ :ruby_version, lambda{|x| x} ], [ :name, lambda{|x| x} ] ] ] ]
  end

  ensurable do
    desc "What state the gem should be in.
      Possible values:
        *present* - the gem is installed
        *latest* - the gem is installed and is the latest stable version
        *absent* - the gem is not installed
        version - the gem is installed and matches the given version"

    attr_accessor :latest

    newvalue(:present, :event => :package_installed) do
      provider.install
    end

    newvalue(:absent, :event => :package_removed) do
      provider.uninstall
    end

    # Alias the 'present' value.
    aliasvalue(:installed, :present)

    newvalue(:latest) do
      current = self.retrieve
      begin
        provider.update
      rescue => detail
        self.fail "Could not update: #{detail}"
      end

      if current == :absent
        :package_installed
      else
        :package_changed
      end
    end

    newvalue(/./) do
      begin
        provider.install
      rescue => detail
        self.fail "Could not update: #{detail}"
      end

      if self.retrieve == :absent
        :package_installed
      else
        :package_changed
      end
    end

    def insync?(is)
      @should ||= []

      @latest ||= nil
      @lateststamp ||= (Time.now.to_i - 1000)
      # Iterate across all of the should values, and see how they
      # turn out.

      @should.each { |should|
        case should
        when :present
          return true unless is == :absent
        when :latest
          # Short-circuit packages that are not present
          return false if is == :absent

          # Don't run 'latest' more than about every 5 minutes
          if @latest and ((Time.now.to_i - @lateststamp) / 60) < 5
            #self.debug "Skipping latest check"
          else
            begin
              @latest = provider.latest
              @lateststamp = Time.now.to_i
            rescue => detail
              error = Puppet::Error.new("Could not get latest version: #{detail}")
              error.set_backtrace(detail.backtrace)
              raise error
            end
          end

          case is
          when is.is_a?(Array)
            if is.include?(@latest)
              return true
            else
              return false
            end
          when @latest
            return true
          else
            self.debug "#{@resource.name} #{is.inspect} is installed, latest is #{@latest.inspect}"
          end
        when :absent
          return true if is == :absent
        when *Array(is)
          return true
        end
      }

      false
    end

    def retrieve
      if gem = provider.query
        gem[:ensure]
      else
        :absent
      end
    end

    defaultto :installed

  end

  autorequire(:rvm_system_ruby) do
    [self[:ruby_version].split("@").first]
  end

  newparam(:name) do
    desc "The name of the Ruby gem."

    isnamevar
  end

  newparam(:withopts) do
    desc "Install the gem with these makefile opts."
  end

  newparam(:source) do
    desc "If a URL is passed via, then that URL is used as the
    remote gem repository; if a source is present but is not a valid URL, it will be
    interpreted as the path to a local gem file.  If source is not present at all,
    the gem will be installed from the default gem repositories."
  end

  newparam(:ruby_version) do
    desc "The ruby version to use.  This should be the fully qualified RVM string
    (including gemset if applicable).  For example: 'ruby-1.9.2-p136@mygemset'
    For a full list of known strings: `rvm list known_strings`."

    defaultto "1.9"
    isnamevar
  end

  newparam(:proxy_url) do
    desc "Proxy to use when downloading ruby installation"
    defaultto ""
  end 

end
Puppet::Type.newtype(:rvm_gemset) do
  @doc = "Manage RVM Gemsets."

  def self.title_patterns
    [ [ /^(?:(.*)@)?(.*)$/, [ [ :ruby_version, lambda{|x| x} ], [ :name, lambda{|x| x} ] ] ] ]
  end

  ensurable

  autorequire(:rvm_system_ruby) do
    [self[:ruby_version]]
  end

  newparam(:name) do
    desc "The name of the gemset to be managed."
    isnamevar
  end

  newparam(:ruby_version) do
    desc "The ruby version to use.  This should be the fully qualified RVM string.
    For example: 'ruby-1.9.2-p290'
    For a full list of known strings: `rvm list known_strings`."

    defaultto "1.9"
    isnamevar
  end

  newparam(:proxy_url) do
    desc "Proxy to use when downloading ruby installation"
    defaultto ""
  end

end
Puppet::Type.newtype(:rvm_system_ruby) do
  @doc = "Manage RVM Ruby installations."

  ensurable

  newparam(:name) do
    desc "The name of the Ruby to be managed."
    isnamevar
  end

  newparam(:build_opts) do
    desc "Build flags for RVM (e.g.: ['--movable', '--with-libyaml-dir=...', ...])"
    defaultto ""
  end

  newparam(:proxy_url) do
    desc "Proxy to use when downloading ruby installation"
    defaultto ""
  end

  newproperty(:default_use) do
    desc "Should this Ruby be the system default for new terminals?"
    defaultto false
  end

  newproperty(:autolib_mode) do
    desc "Set RVM autolib mode"
  end

end
Puppet::Type.newtype(:rvm_wrapper) do
  @doc = "Manage RVM Wrappers."

  ensurable

  newparam(:name) do
    desc "The name of the command to create a wrapper for to be managed."
    isnamevar
  end

  newparam(:prefix) do
    desc "The prefix of the wrapper command to be managed."
  end

  newparam(:target_ruby) do
    desc "The ruby version that is the target of our wrapper.
    For example: 'ruby-1.9.2-p290'"
  end

end
# Install packages needed by RVM when not using autolibs
class rvm::dependencies {
  case $::operatingsystem {
    'Ubuntu','Debian': { require rvm::dependencies::ubuntu }
    'CentOS','RedHat','Fedora','rhel','Amazon','Scientific': { require rvm::dependencies::centos }
    'OracleLinux': { require rvm::dependencies::oraclelinux }
    default: {}
  }
}
# Install packages needed by RVM on RedHat systems when not using autolibs
class rvm::dependencies::centos {

  $version = $::operatingsystem ? {
    'Amazon' => '6.x',
    default  => $::operatingsystemrelease,
  }

  case $version {
    /^6\..*/: {
      ensure_packages(['libcurl-devel'])
    }
    /^5\..*/: {
      ensure_packages(['autoconf'])
      ensure_packages(['curl-devel'])
    }
    default: {
      ensure_packages(['curl-devel'])
    }
  }

  ensure_packages(['which','gcc','gcc-c++','make','gettext-devel','expat-devel','zlib-devel','openssl-devel',
    'perl','cpio','gettext-devel','wget','bzip2','libxml2','libxml2-devel','libxslt','libxslt-devel',
    'readline-devel','patch','git','libyaml-devel','libffi-devel','libtool','bison'])
}
# Install packages needed by RVM on Oracle Linux when not using autolibs
class rvm::dependencies::oraclelinux {

  ensure_packages(['which','gcc','gcc-c++','make','gettext-devel','expat-devel','libcurl-devel',
    'zlib-devel','openssl-devel','perl','cpio','expat-devel','gettext-devel','wget','bzip2',
    'libxml2','libxml2-devel','libxslt','libxslt-devel','readline-devel','patch','git'])
}
# Install packages needed by RVM on Ubuntu when not using autolibs
class rvm::dependencies::ubuntu {

  ensure_packages(['build-essential','bison','openssl','libreadline6','libreadline6-dev','curl','git-core',
    'zlib1g','zlib1g-dev','libssl-dev','libyaml-dev','libsqlite3-0','libsqlite3-dev','sqlite3','libxml2-dev',
    'autoconf','libc6-dev'])

  ensure_resource('package', 'libxslt1-dev', {'ensure' => 'present', 'alias' => 'libxslt-dev'})
}
# RVM's GPG key security signing mechanism requires gpg2 for key import / validation

class rvm::gpg($package = $rvm::params::gpg_package) inherits rvm::params {
  ensure_packages([$package])
}
# Create the RVM group
class rvm::group inherits rvm::params {
  ensure_resource('group', $rvm::params::group, {'ensure' => 'present' })
}
# Install RVM, create system user a install system level rubies
class rvm(
  $version=undef,
  $install_rvm=true,
  $install_dependencies=false,
  $system_users=[],
  $system_rubies={},
  $proxy_url=$rvm::params::proxy_url) inherits rvm::params {

  if $install_rvm {

    # rvm has now autolibs enabled by default so let it manage the dependencies
    if $install_dependencies {
      class { 'rvm::dependencies':
        before => Class['rvm::system']
      }
    }

    ensure_resource('class', 'rvm::rvmrc')

    class { 'rvm::system':
      version   => $version,
      proxy_url => $proxy_url,
    }
  }

  rvm::system_user{ $system_users: }
  create_resources('rvm_system_ruby', $system_rubies, {'ensure' => present, 'proxy_url' => $proxy_url})
}
# Default module parameters
class rvm::params() {

  $group = $::operatingsystem ? {
    default => 'rvm',
  }

  $proxy_url = undef

  $gpg_package = $::osfamily ? {
    /(Debian|RedHat)/ => 'gnupg2',
    default => undef,
  }
}
# Install Passenger dependencies and Apache module
class rvm::passenger::apache(
  $ruby_version,
  $version,
  $rvm_prefix = '/usr/local',
  $mininstances = '1',
  $maxpoolsize = '6',
  $poolidletime = '300',
  $maxinstancesperapp = '0',
  $spawnmethod = 'smart-lv2',
  $proxy_url = undef,
  $install_timeout = 600
) {

  class { 'rvm::passenger::gem':
    ruby_version => $ruby_version,
    version      => $version,
    proxy_url    => $proxy_url
  }

  # TODO: How can we get the gempath automatically using the ruby version
  # Can we read the output of a command into a variable?
  # e.g. $gempath = `usr/local/rvm/bin/rvm ${ruby_version} exec rvm gemdir`
  $gempath = "${rvm_prefix}/rvm/gems/${ruby_version}/gems"
  $binpath = "${rvm_prefix}/rvm/bin/"
  $gemroot = "${gempath}/passenger-${version}"

  if ( versioncmp( $rvm::passenger::apache::version, '4.0.0' ) < 0 ) {
    if ( versioncmp( $rvm::passenger::apache::version, '3.9.0' ) < 0 ) {
      $objdir = 'ext'
    } else {
      $objdir = 'libout'
    }
  } else {
    $objdir = 'buildout'
  }

  $modpath = "${gemroot}/${objdir}/apache2"

  # build the Apache module
  # different passenger versions put the built module in different places (ext, libout, buildout)
  include apache::dev

  class { 'rvm::passenger::dependencies': } ->

  exec { 'passenger-install-apache2-module':
    command     => "${binpath}rvm ${ruby_version} exec passenger-install-apache2-module -a",
    creates     => "${modpath}/mod_passenger.so",
    environment => [ 'HOME=/root', ],
    path        => '/usr/bin:/usr/sbin:/bin',
    require     => Class['rvm::passenger::gem','apache::dev'],
    timeout     => $install_timeout,
  }

  class { 'apache::mod::passenger':
    passenger_root           => $gemroot,
    passenger_ruby           => "${rvm_prefix}/rvm/wrappers/${ruby_version}/ruby",
    passenger_max_pool_size  => $maxpoolsize,
    passenger_pool_idle_time => $poolidletime,
    mod_lib_path             => $modpath,
    require                  => Exec['passenger-install-apache2-module'],
    subscribe                => Exec['passenger-install-apache2-module'],
  }

  case $::osfamily {
    # for redhat and debian OSs Apache configures passenger_extra.conf
    # with the details that should be located in
    # passenger.conf;apache::mod::passenger can't be written directly to
    # passenger.conf without creating a conflict within the apache
    # module, but copying the file contents works fine
    'debian','redhat': {
      case $::osfamily {
        'redhat': {
          $apache_mods_path = '/etc/httpd/conf.d'
        }
        'debian': {
          $apache_mods_path = '/etc/apache2/mods-available'
        }
        default: {
          $apache_mods_path = '/etc/httpd/conf.d'
        }
      }
      exec { 'copy passenger_extra.conf to passenger.conf':
        command     => "/bin/cp ${apache_mods_path}/passenger_extra.conf ${apache_mods_path}/passenger.conf",
        unless      => "/usr/bin/diff ${apache_mods_path}/passenger_extra.conf ${apache_mods_path}/passenger.conf",
        environment => [ 'HOME=/root', ],
        path        => '/usr/bin:/usr/sbin:/bin',
        require     => Class['apache::mod::passenger'],
      }
    }
    default: {}
  }
}
# Package dependencies for Passenger
class rvm::passenger::dependencies {
  case $::operatingsystem {
    'Ubuntu','Debian': { require rvm::passenger::dependencies::ubuntu }
    'CentOS','RedHat','Fedora','rhel','Amazon','Scientific': { require rvm::passenger::dependencies::centos }
    'OracleLinux': { require rvm::passenger::dependencies::oraclelinux }
    default: {}
  }
}
# Package dependencies for Passenger on RedHat
class rvm::passenger::dependencies::centos {

  $version = $::operatingsystem ? {
    'Amazon' => '6.x',
    default  => $::operatingsystemrelease,
  }

  case $version {
    /^6\..*/: {
      ensure_packages(['libcurl-devel'])
    }
    default: {
      ensure_packages(['curl-devel'])
    }
  }
}
# Package dependencies for Passenger on Oracle Linux
class rvm::passenger::dependencies::oraclelinux {
  ensure_packages(['libcurl-devel'])
}
# Package dependencies for Passenger on Ubuntu
class rvm::passenger::dependencies::ubuntu {
  ensure_packages(['curl','libcurl4-gnutls-dev'])
}
# Install the passenger gem
class rvm::passenger::gem($ruby_version, $version, $proxy_url = undef ) {
  $ruby_version_only = regsubst($ruby_version,'([^@]+)(@(.+))?','\1')
  rvm_gem {
    'passenger':
      ensure       => $version,
      require      => Rvm_system_ruby[$ruby_version_only],
      ruby_version => $ruby_version,
      proxy_url    => $proxy_url;
  }
}
# Configure the /etc/rvmrc file
class rvm::rvmrc(
  $template = 'rvm/rvmrc.erb',
  $umask = 'u=rwx,g=rwx,o=rx',
  $max_time_flag = undef,
  $autoupdate_flag = '0',
  $silence_path_mismatch_check_flag = undef) inherits rvm::params {

  include rvm::group

  file { '/etc/rvmrc':
    content => template($template),
    mode    => '0664',
    owner   => 'root',
    group   => $rvm::params::group,
    before  => Exec['system-rvm'],
  }
}
# Install the RVM system
class rvm::system(
  $version=undef,
  $proxy_url=undef) {

  class {'rvm::gpg':}

  $actual_version = $version ? {
    undef     => 'latest',
    'present' => 'latest',
    default   => $version,
  }

  # curl needs to be installed
  if ! defined(Package['curl']) {
    case $::kernel {
      'Linux': {
        ensure_packages(['curl'])
        Package['curl'] -> Exec['system-rvm']
      }
      default: {}
    }
  }

  $proxy_environment = $proxy_url ? {
    undef   => undef,
    default => [ "http_proxy=${proxy_url}" , "https_proxy=${proxy_url}" ],
  }

  exec { 'system-rvm-gpg-key':
    command     => 'gpg2 --keyserver hkp://keys.gnupg.net --recv-keys D39DC0E3',
    path        => $::path,
    environment => 'HOME=/root',
    unless      => 'gpg2 --list-keys D39DC0E3',
    require     => Class['::rvm::gpg']
  } ->

  exec { 'system-rvm':
    path        => '/usr/bin:/usr/sbin:/bin',
    command     => "/usr/bin/curl -fsSL https://get.rvm.io | bash -s -- --version ${actual_version}",
    creates     => '/usr/local/rvm/bin/rvm',
    environment => $proxy_environment,
  }

  # the fact won't work until rvm is installed before puppet starts
  if !empty($::rvm_version) {
    if ($version != undef) and ($version != present) and ($version != $::rvm_version) {
      # Update the rvm installation to the version specified
      notify { 'rvm-get_version':
        message => "RVM updating from version ${::rvm_version} to ${version}",
      }
      exec { 'system-rvm-get':
        path        => '/usr/local/rvm/bin:/usr/bin:/usr/sbin:/bin',
        command     => "rvm get ${version}",
        before      => Exec['system-rvm'], # so it doesn't run after being installed the first time
        environment => $proxy_environment,
        require     => Notify['rvm-get_version'],
      }
    }
  }
}
# Create a user that belongs to the correct group to have access to RVM
define rvm::system_user (
  $create = true) {

  include rvm::params

  if $create {
    ensure_resource('user', $name, {'ensure' => 'present' })
  }

  include rvm::group

  $add_to_group = $::osfamily ? {
    'Darwin' => "/usr/sbin/dseditgroup -o edit -a ${name} -t user ${rvm::params::group}",
    default  => "/usr/sbin/usermod -a -G ${rvm::params::group} ${name}",
  }
  $check_in_group = $::osfamily ? {
    'Darwin' => "/usr/bin/dsmemberutil checkmembership -U ${name} -G ${rvm::params::group} | grep -q 'user is a member'",
    default  => "/bin/cat /etc/group | grep '^${rvm::params::group}:' | grep -qw ${name}",
  }
  exec { "rvm-system-user-${name}":
    command => $add_to_group,
    unless  => $check_in_group,
    require => [User[$name], Group[$rvm::params::group]];
  }
}
{
  "name": "maestrodev-rvm",
  "version": "1.7.1",
  "author": "maestrodev & Brandon Turner <bt@brandonturner.net>",
  "summary": "A puppet module for installing and using RVM (Ruby Version Manager)",
  "license": "Modified BSD License",
  "source": "http://github.com/maestrodev/puppet-rvm",
  "project_page": "http://github.com/maestrodev/puppet-rvm",
  "issues_url": "https://github.com/maestrodev/puppet-rvm/issues",
  "description": "Installing and using RVM (Ruby Version Manager)",
  "operatingsystem_support": [
    {
      "operatingsystem": "RedHat",
      "operatingsystemrelease": [
        "4",
        "5",
        "6",
        "7"
      ]
    },
    {
      "operatingsystem": "CentOS",
      "operatingsystemrelease": [
        "4",
        "5",
        "6",
        "7"
      ]
    },
    {
      "operatingsystem": "OracleLinux",
      "operatingsystemrelease": [
        "4",
        "5",
        "6",
        "7"
      ]
    },
    {
      "operatingsystem": "Scientific",
      "operatingsystemrelease": [
        "4",
        "5",
        "6",
        "7"
      ]
    },
    {
      "operatingsystem": "SLES",
      "operatingsystemrelease": [
        "11 SP1"
      ]
    },
    {
      "operatingsystem": "Debian",
      "operatingsystemrelease": [
        "6",
        "7"
      ]
    },
    {
      "operatingsystem": "Ubuntu",
      "operatingsystemrelease": [
        "10.04",
        "12.04"
      ]
    },
    {
      "operatingsystem": "Solaris",
      "operatingsystemrelease": [
        "10",
        "11"
      ]
    },
    {
      "operatingsystem": "Windows",
      "operatingsystemrelease": [
        "Server 2003",
        "Server 2003 R2",
        "Server 2008",
        "Server 2008 R2",
        "Server 2012",
        "Server 2012 R2",
        "7",
        "8"
      ]
    },
    {
      "operatingsystem": "AIX",
      "operatingsystemrelease": [
        "5.3",
        "6.1",
        "7.1"
      ]
    },
    {
      "operatingsystem": "Darwin",
      "operatingsystemrelease": [
        "10",
        "11",
        "12",
        "13"
      ]
    }
  ],
  "requirements": [
    {
      "name": "pe",
      "version_requirement": ">=3.2.0"
    },
    {
      "name": "puppet",
      "version_requirement": ">=3.0.0"
    }
  ],
  "dependencies": [
    {"name":"puppetlabs/stdlib","version_requirement":">=3.2.0"}
  ]
}
HOSTS:
  centos-64-x64:
    roles:
      - master
    platform: el-6-x86_64
    box : centos-64-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  log_level: debug
  type: git
HOSTS:
  centos-65-x64:
    roles:
      - master
    platform: el-6-x86_64
    image: devopsil/puppet:3.5.1
    # ip: localhost
    hypervisor : docker
    docker_image_commands:
      - yum -y install tar
      - useradd vagrant
CONFIG:
  log_level: debug
  type: git
HOSTS:
  centos-65-x64:
    roles:
      - master
    platform: el-6-x86_64
    box : centos-65-x64-virtualbox-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-65-x64-virtualbox-nocm.box
    hypervisor : vagrant
CONFIG:
  log_level: debug
  type: git
HOSTS:
  debian-73-x64:
    roles:
      - master
    platform: debian-7-amd64
    box : debian-73-x64-virtualbox-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/debian-73-x64-virtualbox-nocm.box
    hypervisor : vagrant
CONFIG:
  log_level: debug
  type: git
HOSTS:
  centos-65-x64:
    roles:
      - master
    platform: el-6-x86_64
    image: devopsil/puppet:3.5.1
    # ip: localhost
    hypervisor : docker
    docker_image_commands:
      - yum -y install tar
      - useradd vagrant
CONFIG:
  log_level: debug
  type: git
HOSTS:
  ubuntu-server-12042-x64:
    roles:
      - master
    platform: ubuntu-12.04-amd64
    box : ubuntu-server-12042-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/ubuntu-server-12042-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  log_level: debug
  type: git
HOSTS:
  ubuntu-server-1310-x64:
    roles:
      - master
    platform: ubuntu-13.10-amd64
    box : ubuntu-server-1310-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/ubuntu-1310-x64-virtualbox-nocm.box
    hypervisor : vagrant
CONFIG:
  log_level   : debug
  type: git
require "spec_helper_acceptance"

describe "rvm" do

  # host variables
  let(:osfamily) { fact("osfamily") }
  let(:operatingsystem) { fact("operatingsystem") }
  
  # rvm config
  let(:rvm_path) { "/usr/local/rvm/" }

  # ruby 1.9.3 config
  let(:ruby19_version) { "ruby-1.9.3-p484" } # chosen for RVM binary support across nodesets
  let(:ruby19_environment) { "#{rvm_path}environments/#{ruby19_version}" }
  let(:ruby19_bin) { "#{rvm_path}rubies/#{ruby19_version}/bin/" }
  let(:ruby19_gems) { "#{rvm_path}gems/#{ruby19_version}/gems/" }
  let(:ruby19_gemset) { "myproject" }
  let(:ruby19_and_gemset) { "#{ruby19_version}@#{ruby19_gemset}" }

  # ruby 2.0 config
  let(:ruby20_version) { "ruby-2.0.0-p481" } # chosen for RVM binary support across nodesets
  let(:ruby20_environment) { "#{rvm_path}environments/#{ruby20_version}" }
  let(:ruby20_bin) { "#{rvm_path}rubies/#{ruby20_version}/bin/" }
  let(:ruby20_gems) { "#{rvm_path}gems/#{ruby20_version}/gems/" }
  let(:ruby20_gemset) { "myproject" }
  let(:ruby20_and_gemset) { "#{ruby20_version}@#{ruby20_gemset}" }

  # passenger baseline configuration
  let(:service_name) {
    case osfamily
    when "Debian"
      "apache2"
    when "RedHat"
      "httpd"
    end
  }
  let(:mod_dir) {
    case osfamily
    when "Debian"
      "/etc/apache2/mods-available/"
    when "RedHat"
      "/etc/httpd/conf.d/"
    end
  }
  let(:rackapp_user) {
    case osfamily
    when "Debian"
      "www-data"
    when "RedHat"
      "apache"
    end
  }
  let(:rackapp_group) {
    case osfamily
    when "Debian"
      "www-data"
    when "RedHat"
      "apache"
    end
  }
  let(:conf_file) { "#{mod_dir}passenger.conf" }
  let(:load_file) { "#{mod_dir}passenger.load" }

  # baseline manifest
  let(:manifest) {
    <<-EOS
      if $::osfamily == 'RedHat' {
        class { 'epel':
          before => Class['rvm'],
        }
      }

      # ensure rvm doesn't timeout finding binary rubies
      class { 'rvm::rvmrc':
        max_time_flag => '20',
      } ->

      class { 'rvm': } ->
      rvm::system_user { 'vagrant': }
  EOS
  }

  it "rvm should install and configure system user" do
    # Run it twice and test for idempotency
    apply_manifest(manifest, :catch_failures => true)
    apply_manifest(manifest, :catch_changes => true)
    shell("/usr/local/rvm/bin/rvm list") do |r|
      r.stdout.should =~ Regexp.new(Regexp.escape("# No rvm rubies installed yet."))
      r.exit_code.should be_zero
    end
  end

  context "when installing rubies" do

    let(:manifest) {
      super() + <<-EOS
        rvm_system_ruby {
          '#{ruby19_version}':
            ensure      => 'present',
            default_use => false;
          '#{ruby20_version}':
            ensure      => 'present',
            default_use => false;
        }
      EOS
    }

    it "should install with no errors" do
      apply_manifest(manifest, :catch_failures => true)
      apply_manifest(manifest, :catch_changes => true)
    end

    it "should reflect installed rubies" do
      shell("/usr/local/rvm/bin/rvm list") do |r|
        r.stdout.should =~ Regexp.new(Regexp.escape("\n   #{ruby19_version}"))
        r.stdout.should =~ Regexp.new(Regexp.escape("\n   #{ruby20_version}"))
        r.exit_code.should be_zero
      end
    end

    context "and installing gems" do
      let(:gem_name) { "simple-rss" } # used because has no dependencies
      let(:gem_version) { "1.3.1" }

      let(:gemset_manifest) {
        manifest + <<-EOS
          rvm_gemset {
            '#{ruby19_and_gemset}':
              ensure  => present,
              require => Rvm_system_ruby['#{ruby19_version}'];
          }
          rvm_gem {
            '#{ruby19_and_gemset}/#{gem_name}':
              ensure  => '#{gem_version}',
              require => Rvm_gemset['#{ruby19_and_gemset}'];
          }
          rvm_gemset {
            '#{ruby20_and_gemset}':
              ensure  => present,
              require => Rvm_system_ruby['#{ruby20_version}'];
          }
          rvm_gem {
            '#{ruby20_and_gemset}/#{gem_name}':
              ensure  => '#{gem_version}',
              require => Rvm_gemset['#{ruby20_and_gemset}'];
          }
        EOS
      }

      it "should install with no errors" do
        apply_manifest(gemset_manifest, :catch_failures => true)
        apply_manifest(gemset_manifest, :catch_changes => true)
      end

      it "should reflect installed gems and gemsets" do
        shell("/usr/local/rvm/bin/rvm #{ruby19_version} gemset list") do |r|
          r.stdout.should =~ Regexp.new(Regexp.escape("\n=> (default)"))
          r.stdout.should =~ Regexp.new(Regexp.escape("\n   global"))
          r.stdout.should =~ Regexp.new(Regexp.escape("\n   #{ruby19_gemset}"))
          r.exit_code.should be_zero
        end

        shell("/usr/local/rvm/bin/rvm #{ruby20_version} gemset list") do |r|
          r.stdout.should =~ Regexp.new(Regexp.escape("\n=> (default)"))
          r.stdout.should =~ Regexp.new(Regexp.escape("\n   global"))
          r.stdout.should =~ Regexp.new(Regexp.escape("\n   #{ruby20_gemset}"))
          r.exit_code.should be_zero
        end
      end
    end
  end

  context "when installing jruby" do
    let(:jruby_version) { "jruby-1.7.6" }

    let(:manifest) {
      super() + <<-EOS
        rvm_system_ruby { '#{jruby_version}':
          ensure      => 'present',
          default_use => false;
        }
      EOS
    }

    it 'should install with no errors' do
      apply_manifest(manifest, :catch_failures => true)
      apply_manifest(manifest, :catch_changes => true)
    end

    it 'should reflect installed rubies' do
      shell("/usr/local/rvm/bin/rvm list") do |r|
        r.stdout.should =~ Regexp.new(Regexp.escape("\n   #{jruby_version}"))
        r.exit_code.should be_zero
      end
    end
  end

  context "when installing passenger 3.0.x" do

    let(:passenger_version) { "3.0.21" }
    let(:passenger_domain) { "passenger3.example.com" }

    let(:passenger_ruby) { "#{rvm_path}wrappers/#{ruby19_version}/ruby" }
    let(:passenger_root) { "#{ruby19_gems}passenger-#{passenger_version}" }
    # particular to 3.0.x (may or may not also work with 2.x?)
    let(:passenger_module_path) { "#{passenger_root}/ext/apache2/mod_passenger.so" }

    let(:manifest) { 
      super() + <<-EOS
        rvm_system_ruby {
          '#{ruby19_version}':
            ensure      => 'present',
            default_use => false,
        }
        class { 'apache':
          service_enable => false, # otherwise detects changes in 2nd run in ubuntu and docker
        }
        class { 'rvm::passenger::apache':
          version            => '#{passenger_version}',
          ruby_version       => '#{ruby19_version}',
          mininstances       => '3',
          maxinstancesperapp => '0',
          maxpoolsize        => '30',
          spawnmethod        => 'smart-lv2',
        }
        /* a simple ruby rack 'hello world' app */
        file { '/var/www/passenger':
          ensure  => directory,
          owner   => '#{rackapp_user}',
          group   => '#{rackapp_group}',
          require => Class['rvm::passenger::apache'],
        }
        file { '/var/www/passenger/config.ru':
          ensure  => file,
          owner   => '#{rackapp_user}',
          group   => '#{rackapp_group}',
          content => "app = proc { |env| [200, { \\"Content-Type\\" => \\"text/html\\" }, [\\"hello <b>world</b>\\"]] }\\nrun app",
          require => File['/var/www/passenger'] ,
        }
        apache::vhost { '#{passenger_domain}':
          port    => '80',
          docroot => '/var/www/passenger/public',
          docroot_group => '#{rackapp_group}' ,
          docroot_owner => '#{rackapp_user}' ,
          custom_fragment => "PassengerRuby  #{passenger_ruby}\\nRailsEnv  development" ,
          default_vhost => true ,
          require => File['/var/www/passenger/config.ru'] ,
        }
      EOS
    }

    it "should install with no errors" do
      # Run it twice and test for idempotency
      apply_manifest(manifest, :catch_failures => true)
      apply_manifest(manifest, :catch_changes => true)

      shell("rvm #{ruby19_version} do #{ruby19_bin}gem list passenger | grep \"passenger (#{passenger_version})\"").exit_code.should be_zero
    end

    it "should be running" do
      service(service_name) do |s|
        s.should_not be_enabled
        s.should be_running
      end
    end

    it "should answer" do
      shell("/usr/bin/curl localhost:80") do |r|
        r.stdout.should =~ /^hello <b>world<\/b>$/
        r.exit_code.should == 0
      end
    end

    it "should output status via passenger-status" do
      shell("rvmsudo_secure_path=1 /usr/local/rvm/bin/rvm #{ruby19_version} do passenger-status") do |r|
        # spacing may vary
        r.stdout.should =~ /[\-]+ General information [\-]+/
        r.stdout.should =~ /max[ ]+= [0-9]+/
        r.stdout.should =~ /count[ ]+= [0-9]+/
        r.stdout.should =~ /active[ ]+= [0-9]+/
        r.stdout.should =~ /inactive[ ]+= [0-9]+/
        r.stdout.should =~ /Waiting on global queue: [0-9]+/
        r.exit_code.should == 0
      end
    end

    it "module loading should be configured as expected" do
      file(load_file) do |f|
        f.should contain "LoadModule passenger_module #{passenger_module_path}"
      end
    end

    it "module behavior should be configured as expected" do
      file(conf_file) do |f|
        f.should contain "PassengerRoot \"#{passenger_root}\""
        f.should contain "PassengerRuby \"#{passenger_ruby}\""
      end
    end

  end

  context "when installing passenger 4.0.x" do

    let(:passenger_version) { "4.0.46" }
    let(:passenger_domain) { "passenger4.example.com" }

    let(:passenger_ruby) { "#{rvm_path}wrappers/#{ruby20_version}/ruby" }
    let(:passenger_root) { "#{ruby20_gems}passenger-#{passenger_version}" }
    # particular to passenger 4.0.x
    let(:passenger_module_path) { "#{passenger_root}/buildout/apache2/mod_passenger.so" }

    let(:manifest) {
      super() + <<-EOS
        rvm_system_ruby {
          '#{ruby20_version}':
            ensure      => 'present',
            default_use => false,
        }
        class { 'apache':
          service_enable => false, # otherwise detects changes in 2nd run in ubuntu and docker
        }
        class { 'rvm::passenger::apache':
          version            => '#{passenger_version}',
          ruby_version       => '#{ruby20_version}',
          mininstances       => '3',
          maxinstancesperapp => '0',
          maxpoolsize        => '30',
          spawnmethod        => 'smart-lv2',
        }
        /* a simple ruby rack 'hello world' app */
        file { '/var/www/passenger':
          ensure  => directory,
          owner   => '#{rackapp_user}',
          group   => '#{rackapp_group}',
          require => Class['rvm::passenger::apache'],
        }
        file { '/var/www/passenger/config.ru':
          ensure  => file,
          owner   => '#{rackapp_user}',
          group   => '#{rackapp_group}',
          content => "app = proc { |env| [200, { \\"Content-Type\\" => \\"text/html\\" }, [\\"hello <b>world</b>\\"]] }\\nrun app",
          require => File['/var/www/passenger'] ,
        }
        apache::vhost { '#{passenger_domain}':
          port    => '80',
          docroot => '/var/www/passenger/public',
          docroot_group => '#{rackapp_group}' ,
          docroot_owner => '#{rackapp_user}' ,
          custom_fragment => "PassengerRuby  #{passenger_ruby}\\nRailsEnv  development" ,
          default_vhost => true ,
          require => File['/var/www/passenger/config.ru'] ,
        }
      EOS
    }

    it "should install with no errors" do
      # Run it twice and test for idempotency
      apply_manifest(manifest, :catch_failures => true)
      apply_manifest(manifest, :catch_changes => true)

      shell("/usr/local/rvm/bin/rvm #{ruby20_version} do #{ruby20_bin}gem list passenger | grep \"passenger (#{passenger_version})\"").exit_code.should be_zero
    end

    it "should be running" do
      service(service_name) do |s|
        s.should_not be_enabled
        s.should be_running
      end
    end

    it "should answer" do
      shell("/usr/bin/curl localhost:80") do |r|
        r.stdout.should =~ /^hello <b>world<\/b>$/
        r.exit_code.should == 0
      end
    end

    it "should output status via passenger-status" do
      shell("rvmsudo_secure_path=1 /usr/local/rvm/bin/rvm #{ruby20_version} do passenger-status") do |r|
        # spacing may vary
        r.stdout.should =~ /[\-]+ General information [\-]+/
        r.stdout.should =~ /Max pool size \: [0-9]+/
        r.stdout.should =~ /Processes     \: [0-9]+/
        r.stdout.should =~ /Requests in top\-level queue \: [0-9]+/
        r.stdout.should =~ /[\-]+ Application groups [\-]+/
        # the following will only appear after a request has been made, as in "should answer to" above
        r.stdout.should =~ /App root\: \/var\/www\/passenger/
        r.stdout.should =~ /Requests in queue\: [0-9]+/
        r.exit_code.should == 0
      end
    end

    it "module loading should be configured as expected" do
      file(load_file) do |f|
        f.should contain "LoadModule passenger_module #{passenger_module_path}"
      end
    end

    it "module behavior should be configured as expected" do
      file(conf_file) do |f|
        f.should contain "PassengerRoot \"#{passenger_root}\""
        f.should contain "PassengerRuby \"#{passenger_ruby}\""
      end
    end

  end

end
require 'spec_helper'

describe 'rvm::dependencies' do

  packages = ['which','gcc','autoconf','libcurl-devel','build-essential']

  let(:facts) {{}}

  shared_examples 'package creation' do |packages_to_have|
    packages_to_have.each {|p| it { should contain_package(p)} }
    (packages-packages_to_have).each {|p| it { should_not contain_package(p)} }
  end

  shared_context 'redhat_facts' do |operatingsystem, operatingsystemrelease|
    let(:facts) { super().merge({
      :osfamily => "RedHat",
      :operatingsystem => operatingsystem,
      :operatingsystemrelease => operatingsystemrelease
    }) }
  end

  shared_examples 'redhat' do |packages_to_have|
    it_behaves_like 'package creation', packages_to_have + ['which','gcc']
  end

  shared_examples 'redhat5' do |operatingsystem, operatingsystemrelease|
    include_context 'redhat_facts', operatingsystem, operatingsystemrelease
    it_behaves_like 'redhat', ['autoconf']
  end

  shared_examples 'redhat6' do |operatingsystem, operatingsystemrelease|
    include_context 'redhat_facts', operatingsystem, operatingsystemrelease
    it_behaves_like 'redhat', ['libcurl-devel']
  end

  shared_examples 'debian' do |operatingsystem|
    let(:facts) {{
      :osfamily => "Debian",
      :operatingsystem => operatingsystem
    }}
    it_behaves_like 'package creation', ['autoconf','build-essential']
  end


  context 'RedHat' do
    operatingsystems = ['centos', 'fedora', 'rhel', 'redhat', 'scientific']
    versions = { '5.0' => 'redhat5', '6.4' => 'redhat6' }
    operatingsystems.each do |os|
      context os, :compile do
        versions.each {|version,example| it_behaves_like example, os, version }
      end
    end

    context 'amazon linux', :compile do
      let(:facts) {{ :operatingsystemmajrelease => "3" }}
      it_behaves_like 'redhat6', 'Amazon', '3.4.43-43.43.amzn1.x86_64'
    end
  end

  context 'debian', :compile do
    it_behaves_like 'debian', 'ubuntu'
  end

  context 'other', :compile do
    let(:facts) {{ :operatingsystem => 'xxx' }}
    it_behaves_like 'package creation', []
  end
end
require 'spec_helper'

describe 'rvm::gpg' do

  context "RedHat", :compile do
    let(:facts) {{
      :osfamily => 'RedHat'
    }}
    it { should contain_package('gnupg2') }
  end

  context "Debian", :compile do
    let(:facts) {{
      :osfamily => 'Debian'
    }}
    it { should contain_package('gnupg2') }
  end

  context "OS X", :compile do
    let(:facts) {{
      :osfamily => 'Darwin'
    }}
    it { should_not contain_package('gnupg2') }
  end
end
require 'spec_helper'

describe 'rvm' do

  let(:facts) {{
    :path => '/bin'
  }}

  context "default parameters", :compile do
    it { should_not contain_class('rvm::dependencies') }
    it { should contain_class('rvm::system') }
  end

  context "with install_rvm false", :compile do
    let(:params) {{
      :install_rvm => false
    }}
    it { should_not contain_class('rvm::dependencies') }
    it { should_not contain_class('rvm::system') }
  end

  context "with system_rubies", :compile do
    let(:params) {{
      :system_rubies => {
        'ruby-1.9' => {
          'default_use' => true
        },
        'ruby-2.0' => {}
      }
    }}
    it { should contain_rvm_system_ruby('ruby-1.9').with({
      :ensure => 'present',
      :default_use => true
    }) }
    it { should contain_rvm_system_ruby('ruby-2.0').with({
      :ensure => 'present',
      :default_use => nil
    }) }
  end

  context "with system_users", :compile do
    let(:params) {{ :system_users => ['john','doe'] }}
    it { should contain_rvm__system_user('john') }
    it { should contain_rvm__system_user('doe') }
  end
end
require 'spec_helper'

describe 'rvm::rvmrc' do
  let(:file) { '/etc/rvmrc' }
  let(:pre_condition) { "exec {'system-rvm': path => '/bin'}" }

  context "default parameters", :compile do
    it { should contain_file(file).with_group('rvm') }
    it { should contain_file(file).with_content(%r{^umask u=rwx,g=rwx,o=rx$}) }
    it { should contain_file(file).with_content(%r{^rvm_autoupdate_flag=0$}) }
    it { should_not contain_file(file).with_content(%r{rvm_max_time_flag}) }
  end

  context "with max_time_flag", :compile do
    let(:params) {{ :max_time_flag => 20 }}
    it { should contain_file(file).with_content(%r{^export rvm_max_time_flag=20$}) }
  end

end
require 'spec_helper'

describe 'rvm::system' do

  # assume RVM is already installed
  let(:facts) {{
    :rvm_version => '1.10.0',
    :path => '/bin'
  }}

  context "default parameters", :compile do
    it { should_not contain_exec('system-rvm-get') }
  end

  context "with present version", :compile do
    let(:params) {{ :version => 'present' }}
    it { should_not contain_exec('system-rvm-get') }
  end

  context "with latest version", :compile do
    let(:params) {{ :version => 'latest' }}
    it { should contain_exec('system-rvm-get').with_command('rvm get latest') }
  end

  context "with explicit version", :compile do
    let(:params) {{ :version => '1.20.0' }}
    it { should contain_exec('system-rvm-get').with_command('rvm get 1.20.0') }
  end

  context "with proxy_url parameter", :compile do
    let(:params) {{ :version => 'latest', :proxy_url => 'http://dummy.bogus.local:8080' }}
    it { should contain_exec('system-rvm-get').with_environment("[\"http_proxy=#{params[:proxy_url]}\", \"https_proxy=#{params[:proxy_url]}\"]") }
  end

end
require 'spec_helper'

describe 'rvm_alias' do

  let(:title) { '2.0' }
  let(:params) {{ :target_ruby => '2.0-384' }}

  context "when using default parameters", :compile do
    it { should contain_rvm_alias('2.0').with_target_ruby('2.0-384') }
  end
end
require 'spec_helper'

describe 'rvm_gem' do

  let(:title) { 'thin' }
  let(:params) {{ :ruby_version => '2.0' }}
  let(:pre_condition) { "rvm_system_ruby { '2.0': }" }

  context "when using default parameters", :compile do
    # TODO test autorequirement
    it { should contain_rvm_gem('thin') } #.that_requires("Rvm_system_ruby[2.0]")
  end
end
require 'spec_helper'

describe 'rvm_gemset' do

  let(:title) { 'ruby-1.9@myproject' }

  context "when using default parameters", :compile do
    it { should contain_rvm_gemset('ruby-1.9@myproject').with_ruby_version('ruby-1.9') }
  end

  context "when setting ruby_version", :compile do
    let(:params) {{ :ruby_version => '1.9'}}
    it { should contain_rvm_gemset('ruby-1.9@myproject').with_ruby_version('1.9') }
  end
end
require 'spec_helper'

describe 'rvm_system_ruby' do

  let(:title) { '2.0' }

  context "when using default parameters", :compile do
    it { should contain_rvm_system_ruby('2.0') }
  end
end
require 'spec_helper'

describe 'rvm_wrapper' do

  let(:title) { 'god' }
  let(:params) {{
    :target_ruby => 'ruby-1.9.3-p448',
    :prefix      => 'bootup',
    :ensure      => 'present'
  }}

  context "when using default parameters", :compile do
    it { should contain_rvm_wrapper('god').with_prefix('bootup') }
  end
end
require 'spec_helper'

describe 'rvm::system_user' do

  let(:username) { 'johndoe' }
  let(:group) { 'rvm' }
  let(:title) { username }

  context "when using default parameters", :compile do
    it { should contain_user(username) }
    it { should contain_group(group) }
    it { should contain_exec("rvm-system-user-#{username}").with_command("/usr/sbin/usermod -a -G #{group} #{username}") }
  end
end
require 'puppetlabs_spec_helper/module_spec_helper'
require 'puppet'

RSpec.configure do |c|
  c.treat_symbols_as_metadata_keys_with_true_values = true

  c.before(:each) do
    Puppet::Util::Log.level = :warning
    Puppet::Util::Log.newdestination(:console)
  end

end

shared_examples :compile, :compile => true do
  it { should compile.with_all_deps }
end
require 'puppet'
require 'beaker-rspec/spec_helper'
require 'beaker-rspec/helpers/serverspec'

# overriding puppet installation for the RedHat family distros due to
# puppet breakage >= 3.5
def install_puppet(host)
  host['platform'] =~ /(fedora|el)-(\d+)/
  if host['platform'] =~ /(fedora|el)-(\d+)/
    safeversion = '3.4.2'
    platform = $1
    relver = $2
    on host, "rpm -ivh http://yum.puppetlabs.com/puppetlabs-release-#{platform}-#{relver}.noarch.rpm"
    on host, "yum install -y puppet-#{safeversion}"
  else
    super()
  end
end

RSpec.configure do |c|

  # Project root
  proj_root = File.expand_path(File.join(File.dirname(__FILE__), '..'))

  c.before(:each) do
    Puppet::Util::Log.level = :warning
    Puppet::Util::Log.newdestination(:console)
  end

  c.before :suite do
    hosts.each do |host|
      unless (ENV['RS_PROVISION'] == 'no' || ENV['BEAKER_provision'] == 'no')
        begin
          on host, 'puppet --version'
        rescue
          if host.is_pe?
            install_pe
          else
            install_puppet(host)
          end
        end
      end

      # Install module and dependencies
      puppet_module_install(:source => proj_root, :module_name => 'rvm')

      if fact('osfamily') == 'RedHat'
        # not included in Puppetfile.lock, version based on latest when Puppetfile.lock last set
        on host, puppet('module', 'install', 'stahnma/epel', '--version=0.1.0'), { :acceptable_exit_codes => [0,1] }
      end
      # version based on current Puppetfile.lock
      on host, puppet('module', 'install', 'puppetlabs-apache', '--version=1.1.0'), { :acceptable_exit_codes => [0,1] }
    end
  end

end
<% if @umask and !@umask.empty? -%>
umask <%= @umask %>
<% end -%>
<% if @max_time_flag and !@max_time_flag.empty? -%>
export rvm_max_time_flag=<%= @max_time_flag %>
<% end -%>
<% if @autoupdate_flag and !@autoupdate_flag.empty? -%>
rvm_autoupdate_flag=<%= @autoupdate_flag %>
<% end -%>
<% if @silence_path_mismatch_check_flag and !@silence_path_mismatch_check_flag.empty? -%>
rvm_silence_path_mismatch_check_flag=<%= @silence_path_mismatch_check_flag %>
<%end -%>
rvm::system_rubies:
  '1.9': {}
  '2.0':
    default_use: true
  '2.1': {}
  'jruby-1.7': {}

rvm::system_users:
  - root
if $::osfamily == 'RedHat' {
  class { 'epel':
    before => Class['rvm'],
  }
}

class { 'rvm': }
if $::osfamily == 'RedHat' {
  class { 'epel':
    before => Class['rvm'],
  }
}

class { 'rvm': }
fixtures:
  repositories:
    "puppi": "git://github.com/example42/puppi.git"
    "monitor": "git://github.com/example42/puppet-monitor.git"
    "firewall": "git://github.com/example42/puppet-firewall.git"
    "iptables": "git://github.com/example42/puppet-iptables.git"
    "concat": "git://github.com/puppetlabs/puppet-concat.git"
    "stdlib": "git://github.com/puppetlabs/puppetlabs-stdlib.git"
  symlinks:
    "solr": "#{source_dir}"

source :rubygems

puppetversion = ENV['PUPPET_VERSION']
gem 'puppet', puppetversion, :require => false
gem 'puppet-lint'
gem 'puppetlabs_spec_helper', '>= 0.1.0'
language: ruby
rvm:
  - 1.8.7
  - 1.9.3
script:
  - "rake spec SPEC_OPTS='--format documentation'"
env:
  - PUPPET_VERSION="~> 2.6.0"
  - PUPPET_VERSION="~> 2.7.0"
  - PUPPET_VERSION="~> 3.0.0"
  - PUPPET_VERSION="~> 3.1.0"
matrix:
  exclude:
    - rvm: 1.9.3
      env: PUPPET_VERSION="~> 2.6.0"
      gemfile: .gemfile

gemfile: .gemfile
notifications:
  email:
    - al@lab42.it
Copyright (C) 2013 Alessandro Franceschi / Lab42

for the relevant commits Copyright (C) by the respective authors.

Contact Lab42 at: info@lab42.it

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
name 'example42-solr'
version '2.0.6'

author 'Alessandro Franceschi'
license 'Apache2'
project_page 'http://www.example42.com'
source 'https://github.com/example42/puppet-solr'
summary 'Puppet module for solr'
description 'This module installs and manages solr. Check README for details.'
dependency 'puppetlabs/stdlib', '>=2.0.0'
dependency 'example42/puppi', '>=2.0.0'
dependency 'example42/monitor', '>=2.0.0'
# Puppet module: solr

This is a Puppet solr module from the second generation of Example42 Puppet Modules.

Made by Alessandro Franceschi / Lab42 - http://www.example42.com

Released under the terms of Apache 2 License.

Check Modulefile for dependencies.

Development has been sponsored by Elce - http://www.elce.us


## USAGE - Basic management
* Install solr with default settings

        class { "solr": }

* Remove solr 

        class { "solr":
          absent => true,
        }

* Define solr installation method: Valid values for install => are "package" (default), "source" and "puppi".

        class { "solr":
          install => "source",
        }

* Install source from a custom url to a custom install_destination path.
  The following parameters apply both for "source" and "puppi" install methods.
  Puppi method may be used to manage deployment updates (given the $install_source is updated).
  By default install_source is set to upstream developer and install_destination to Web (App) server document root
  Pre and post installation commands may be already defined (check solr/manifests/params.pp) override them only if needed.
  Url_check and url_pattern are used for application checks, if monitor is enabled. Override only if needed.

        class { "solr":
          install             => "source",
          install_source      => "http://deploy.example42.com/solr/solr.tar.gz",
          install_destination => "/opt/apps/",
          # install_precommand  => "...",
          # install_postcommand => "...",
          # url_check           => "...",
          # url_pattern         => "...",
        }



## USAGE - Overrides and Customizations
* Use custom sources for main config file 

        class { "solr":
          source => [ "puppet:///modules/lab42/solr/solr.conf-$hostname" , "puppet:///modules/lab42/solr/solr.conf" ], 
        }

* Use custom template for main config file 

        class { "solr":
          template => "example42/solr/solr.conf.erb",      
        }

* Define custom options that can be used in a custom template without the
  need to add parameters to the solr class

        class { "solr":
          template => "example42/solr/solr.conf.erb",    
          options  => {
            'LogLevel' => 'INFO',
            'UsePAM'   => 'yes',
          },
        }

* Automaticallly include a custom subclass

        class { "solr:"
          my_class => 'lab42::solr',
        }


## USAGE - Example42 extensions management 
* Activate puppi (recommended, but disabled by default)
  Note that this option requires the usage of Example42 puppi module

        class { "solr": 
          puppi    => true,
        }

* Activate automatic monitoring (recommended, but disabled by default)
  This option requires the usage of Example42 monitor and relevant monitor tools modules

        class { "solr":
          monitor      => true,
          monitor_tool => [ "nagios" , "monit" , "munin" ],
        }


[![Build Status](https://travis-ci.org/example42/puppet-solr.png?branch=master)](https://travis-ci.org/example42/puppet-solr)
require 'rubygems'
require 'puppetlabs_spec_helper/rake_tasks'
require 'puppet-lint'
PuppetLint.configuration.send("disable_80chars")
PuppetLint.configuration.send('disable_class_parameter_defaults')
# Class: solr
#
# This is the main solr class
#
#
# == Parameters
#
# Standard class parameters - Define solr web app specific settings
#
# [*install*]
#   Kind of installation to attempt:
#     - package : Installs solr using the OS common packages
#     - source  : Installs solr downloading and extracting a specific tarball or zip file
#     - puppi   : Installs solr tarball or file via Puppi, creating the "puppi deploy solr" command
#
# [*install_source*]
#   The URL from where to retrieve the source tarball/zip. Used if install => "source" or "puppi"
#   Default is from upstream developer site. Update the version when needed.
#
# [*install_destination*]
#   The base path where to extract the source tarball/zip. Used if install => "source" or "puppi"
#   By default is the distro's default DocumentRoot for Web or Application server
#
# [*install_precommand*]
#   A custom command to execute before installing the source tarball/zip. Used if install => "source" or "puppi"
#   Check solr/manifests/params.pp before overriding the default settings
#
# [*install_postcommand*]
#   A custom command to execute after installing the source tarball/zip. Used if install => "source" or "puppi"
#   Check solr/manifests/params.pp before overriding the default settings
#
# [*url_check*]
#   An url, relevant to the solr application, to use for testing the correct deployment of solr.
#   Used is monitor is enabled.
#
# [*url_pattern*]
#   A string that must exist in the defined url_check that confirms that the application is running correctly
#
#
# Standard class parameters - Define the general class behaviour and customizations
#
# [*my_class*]
#   Name of a custom class to autoload to manage module's customizations
#   If defined, solr class will automatically "include $my_class"
#
# [*source*]
#   Sets the content of source parameter for main configuration file
#   If defined, solr main config file will have the parameter: source => $source
#
# [*source_dir*]
#   If defined, the whole solr configuration directory content is retrieved recursively from
#   the specified source (parameter: source => $source_dir , recurse => true)
#
# [*source_dir_purge*]
#   If set to true all the existing configuration directory is overriden by the
#   content retrived from source_dir. (source => $source_dir , recurse => true , purge => true)
#
# [*template*]
#   Sets the path to the template to be used as content for main configuration file
#   If defined, solr main config file will have: content => content("$template")
#   Note source and template parameters are mutually exclusive: don't use both
#
# [*options*]
#   An hash of custom options that can be used in templates for arbitrary settings.
#
# [*absent*]
#   Set to 'true' to remove package(s) installed by module
#
# [*monitor*]
#   Set to 'true' to enable monitoring of the services provided by the module
#
# [*monitor_tool*]
#   Define which monitor tools (ad defined in Example42 monitor module) you want to use for solr
#
# [*puppi*]
#   Set to 'true' to enable creation of module data files that are used by puppi
#
# [*debug*]
#   Set to 'true' to enable modules debugging
#
#
# Default class params - As defined in solr::params.
# Note that these variables are mostly defined and used in the module itself, overriding the default
# values might not affected all the involved components (ie: packages layout)
# Set and override them only if you know what you're doing.
#
# [*package*]
#   The name of solr package
#
# [*config_dir*]
#   Main configuration directory. Used by puppi
#
# [*config_file*]
#   Main configuration file path
#
# [*config_file_mode*]
#   Main configuration file path mode
#
# [*config_file_owner*]
#   Main configuration file path owner
#
# [*config_file_group*]
#   Main configuration file path group
#
# [*data_dir*]
#   Path of application data directory. Used by puppi
#
# [*log_dir*]
#   Base logs directory. Used by puppi
#
# [*log_file*]
#   Log file(s). Used by puppi
#
#
# == Examples
#
# See README
#
#
# == Author
#   Alessandro Franceschi <al@lab42.it/>
#
class solr (
  $install             = params_lookup( 'install' ),
  $install_source      = params_lookup( 'install_source' ),
  $install_destination = params_lookup( 'install_destination' ),
  $install_precommand  = params_lookup( 'install_precommand' ),
  $install_postcommand = params_lookup( 'install_postcommand' ),
  $url_check           = params_lookup( 'url_check' ),
  $url_pattern         = params_lookup( 'url_pattern' ),
  $my_class            = params_lookup( 'my_class' ),
  $source              = params_lookup( 'source' ),
  $source_dir          = params_lookup( 'source_dir' ),
  $source_dir_purge    = params_lookup( 'source_dir_purge' ),
  $template            = params_lookup( 'template' ),
  $options             = params_lookup( 'options' ),
  $absent              = params_lookup( 'absent' ),
  $monitor             = params_lookup( 'monitor' ),
  $monitor_tool        = params_lookup( 'monitor_tool' ),
  $puppi               = params_lookup( 'puppi' ),
  $debug               = params_lookup( 'debug' ),
  $package             = params_lookup( 'package' ),
  $config_dir          = params_lookup( 'config_dir' ),
  $config_file         = params_lookup( 'config_file' ),
  $config_file_mode    = params_lookup( 'config_file_mode' ),
  $config_file_owner   = params_lookup( 'config_file_owner' ),
  $config_file_group   = params_lookup( 'config_file_group' ),
  $data_dir            = params_lookup( 'data_dir' ),
  $log_dir             = params_lookup( 'log_dir' ),
  $log_file            = params_lookup( 'log_file' ),
  ) inherits solr::params {

  validate_bool($source_dir_purge, $absent , $monitor , $puppi , $debug)

  # Calculations of some variables used in the module
  $manage_package = $solr::absent ? {
    true  => 'absent',
    false => 'present',
  }

  $manage_file = $solr::absent ? {
    true    => 'absent',
    default => 'present',
  }

  $manage_monitor = $solr::absent ? {
    true  => false ,
    default => $solr::disable ? {
      true    => false,
      default => true,
    }
  }


  # Installation is managed in dedicated class
  require solr::install

  file { 'solr.conf':
    ensure  => $solr::manage_file,
    path    => $solr::config_file,
    mode    => $solr::config_file_mode,
    owner   => $solr::config_file_owner,
    group   => $solr::config_file_group,
    require => Class['solr::install'],
    source  => $source ? {
      ''      => undef,
      default => $source,
    },
    content => $template ? {
      ''      => undef,
      default => template($template),
    },
  }

  # Whole solr configuration directory can be recursively overriden
  if $solr::source_dir {
    file { 'solr.dir':
      ensure  => directory,
      path    => $solr::config_dir,
      require => Class['solr::install'],
      source  => $source_dir,
      recurse => true,
      purge   => $source_dir_purge,
    }
  }

  # Include custom class if $my_class is set
  if $solr::my_class {
    include $solr::my_class
  }


  # Provide puppi data, if enabled ( puppi => true )
  if $solr::puppi == true {
    $puppivars=get_class_args()
    file { 'puppi_solr':
      ensure  => $solr::manage_file,
      path    => "${settings::vardir}/puppi/solr",
      mode    => '0644',
      owner   => 'root',
      group   => 'root',
      require => Class['puppi'],
      content => inline_template('<%= puppivars.to_yaml %>'),
    }
  }


  # Url check, if enabled ( monitor => true )
  if $solr::monitor == true and $solr::url_check != '' {
    monitor::url { 'solr_url':
      enable  => $solr::manage_monitor,
      url     => $solr::url_check,
      pattern => $solr::url_pattern,
      port    => $solr::port,
      target  => $::fqdn,
      tool    => $solr::monitor_tool,
    }
  }


  # Include debug class is debugging is enabled
  if $solr::debug == true {
    file { 'debug_solr':
      ensure  => $solr::manage_file,
      path    => "${settings::vardir}/debug-solr",
      mode    => '0640',
      owner   => 'root',
      group   => 'root',
      content => inline_template('<%= scope.to_hash.reject { |k,v| k.to_s =~ /(uptime.*|path|timestamp|free|.*password.*|.*psk.*|.*key)/ }.to_yaml %>'),
    }
  }

}
# Class: solr::install
#
# This class installs solr
#
# == Variables
#
# Refer to solr class for the variables defined here.
#
# == Usage
#
# This class is not intended to be used directly. It's automatically included by solr
#
class solr::install inherits solr {

  case $solr::install {

    package: {
      package { 'solr':
        ensure => $solr::manage_package,
        name   => $solr::package,
      }
    }

    source: {
      puppi::netinstall { 'netinstall_solr':
        url                 => $solr::install_source,
        destination_dir     => $solr::install_destination,
        preextract_command  => $solr::install_precommand,
        postextract_command => $solr::install_postcommand,
      }
    }

    puppi: {
      puppi::project::archive { 'solr':
        source                   => $solr::install_source,
        deploy_root              => $solr::install_destination,
        predeploy_customcommand  => $solr::install_precommand,
        postdeploy_customcommand => $solr::install_postcommand,
        report_email             => 'root',
        auto_deploy              => true,
        enable                   => true,
      }
    }

  }

}
# Class: solr::params
#
# This class defines default parameters used by the main module class solr
# Operating Systems differences in names and paths are addressed here
#
# == Variables
#
# Refer to solr class for the variables defined here.
#
# == Usage
#
# This class is not intended to be used directly.
# It may be imported or inherited by other classes
#
class solr::params {

  # Default installation type depends on OS package availability
  $install = $::operatingsystem ? {
    /(?i:Ubuntu|Debian|Mint)/ => 'package',
    default                   => 'source',
  }

  # Install source from the upstream provider is updated
  # to module's last update time
  # You may need to change this: use the "install_source" parameter
  # of the solr class
  $install_source = 'http://www.apache.org/dist/lucene/solr/3.4.0/apache-solr-3.4.0.tgz'

  $install_destination = $::operatingsystem ? {
    default                   => '/opt/solr',
  }

  $install_precommand  = ''

  $install_postcommand = ''

  $url_check           = "${::fqdn}/solr"

  $url_pattern         = 'Welcome to Solr!'

  $my_class            = ''
  $source              = ''
  $source_dir          = ''
  $source_dir_purge    = false
  $template            = ''
  $options             = ''
  $absent              = false
  $monitor             = false
  $monitor_tool        = ''
  $puppi               = false
  $debug               = false

  $package = $::operatingsystem ? {
    /(?i:Ubuntu|Debian|Mint)/ => 'solr-tomcat',
    default                   => 'solr',
  }

  $config_dir = $::operatingsystem ? {
    default => '/etc/solr/conf',
  }

  $config_file = $::operatingsystem ? {
    default => '/etc/solr/conf/solrconfig.xml',
  }

  $config_file_mode = $::operatingsystem ? {
    default => '0644',
  }

  $config_file_owner = $::operatingsystem ? {
    default => 'root',
  }

  $config_file_group = $::operatingsystem ? {
    default => 'root',
  }

  $data_dir = $::operatingsystem ? {
    default => '/var/lib/solr',
  }

  $log_dir = $::operatingsystem ? {
    default => '/var/log',
  }

  $log_file = $::operatingsystem ? {
    default => '/var/log/solr.log',
  }

}
name    'puppetlabs-sqlite'
version '0.0.1'
source 'https://github.com/puppetlabs/puppetlabs-sqlite/'
author 'puppetlabs'
license 'Apache'
summary 'Manage a sqlite installation and databases'
description 'This module provides a sqlite class to manage
the installation of sqlite on a node.  It also provides
a sqlite::db defined type to manage databases on a system'
project_page 'http://projects.puppetlabs.com/projects/modules/issues'

## Add dependencies, if any:
# dependency 'username/name', '>= 1.2.0'
sqlite
======

Author: Carl Caum <carl@puppetlabs.com>
Copyright (c) 2011, Puppet Labs Inc.

ABOUT
=====

This module manages [sqlite](http://www.sqlite.org). Through declarion of the `sqlite` class, sqlite will be installed on the system.

The `sqlite::db` defined type allows for the management of a sqlite database on the node

CONFIGURATION
=============

The main class (sqlite) only needs to be declared.  No class parameters or top scope variables are needed.

The `sqlite::db` defined type can be used to manage a sqlite database on the system.
The following parameters are available for the resources declaration:

location    What directory the database should go in.  The presence of the directory must be managed separately of the defined type.
owner       The owner of the sqlite database file on disk
group       The group owning the sqlite database file on disk
mode        The mode of the sqlite database file on disk
ensure      Whether the database should be `present` or `absent`.  Default to `present`
sqlite_cmd  The sqlite command for the node's platform.  Defaults to `sqlite3`

TODO
====

 * Allow for sql commands to be based to sqlite::db for use during creation
# Define: sqlite::db
#
# This define allows for managing the existance of a sqlite database
#
# Parameters:
#  $location:
#    The location on disk to store the sqlite database
#  $owner:
#    The owner of the sqlite database file on disk
#  $group:
#    The group owning the sqlite database file on disk
#  $mode:
#    The mode of the sqlite datbase file on disk
#  $ensure:
#    Whether the database should be `present` or `absent`. Defaults to `present`
#  $sqlite_cmd:
#    The sqlite command for the node's platform.  Defaults to `sqlite3`
define sqlite::db(
    $location   = '',
    $owner      = 'root',
    $group      = 0,
    $mode       = '755',
    $ensure     = present,
    $sqlite_cmd = 'sqlite3'
  ) {

  $safe_location = $location ? {
    ''      => "/var/lib/sqlite/${name}.db",
    default => $location,
  }

  file { $safe_location:
    ensure => $ensure,
    owner  => $owner,
    group  => $group,
    notify => Exec["create_${name}_db"],
  }

  exec { "create_${name}_db":
    command     => "${sqlite_cmd} $safe_location",
    path        => '/usr/bin:/usr/local/bin',
    refreshonly => true,
  }
}
# Class: sqlite
#
# This class manages the installation of the sqlite
# database.
#
# Sample Usage:
# class { 'sqlite': }
class sqlite {
  package { 'sqlite':
    ensure => installed,
  }

  file { '/var/lib/sqlite/':
    ensure => directory,
  }
}
/*
+-----------------------------------------------------------------------+
|                                                                       |
|                    ==> DO NOT EDIT THIS FILE! <==                     |
|                                                                       |
|   You should edit the `Modulefile` and run `puppet-module build`      |
|   to generate the `metadata.json` file for your releases.             |
|                                                                       |
+-----------------------------------------------------------------------+
*/

{}
s
mtime
require 'pathname'
dir = Pathname.new(__FILE__).parent
$LOAD_PATH.unshift(dir, dir + 'lib', dir + '../lib')

require 'mocha'
require 'puppet'
gem 'rspec', '=1.2.9'
require 'spec/autorun'

Spec::Runner.configure do |config|
    config.mock_with :mocha
end

# We need this because the RAL uses 'should' as a method.  This
# allows us the same behaviour but with a different method name.
class Object
    alias :must :should
end
include sqlite
fixtures:
  repositories:
    stdlib: 'git://github.com/puppetlabs/puppetlabs-stdlib.git'
  symlinks:
    staging: "#{source_dir}"
language: ruby
script: "bundle exec rake validate && bundle exec rake lint && bundle exec rake spec SPEC_OPTS='--format documentation'"
before_install:
  - gem update bundler
  - bundle --version
  - gem update --system 2.1.11
  - gem --version
rvm:
  - 1.8.7
  - 1.9.3
env:
  - PUPPET_GEM_VERSION="~> 3.2.0"
  - PUPPET_GEM_VERSION=">= 3.0.0"
branches:
  only:
    - master
matrix:
  exclude:
    - rvm: 1.8.7
      env: PUPPET_GEM_VERSION=">= 3.0.0"
notifications:
  email: false
source "https://rubygems.org"

group :development, :test do
  gem 'rake'
  gem 'rspec', "~> 2.11.0", :require => false
  gem 'mocha', "~> 0.10.5", :require => false
  gem 'puppetlabs_spec_helper', :require => false
  gem 'rspec-puppet', :require => false
  gem 'puppet-lint'
end

facterversion = ENV['GEM_FACTER_VERSION']
if facterversion
  gem 'facter', facterversion
else
  gem 'facter', :require => false
end

ENV['GEM_PUPPET_VERSION'] ||= ENV['PUPPET_GEM_VERSION']
puppetversion = ENV['GEM_PUPPET_VERSION']
if puppetversion
  gem 'puppet', puppetversion
else
  gem 'puppet', :require => false
end
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
name    'nanliu-staging'
version '0.4.0'
source  'git@github.com:nanliu/puppet-staging.git'
author  'nanliu'
license 'Apache License Version 2.0'
summary 'Compressed file staging and deployment'
description 'Manages compressed file staging and deployment.'
project_page 'https://github.com/nanliu/puppet-staging'

## Add dependencies, if any:
# Staging module for Puppet

Manages staging directory, along with download/extraction of compressed files.

[![Build Status](https://secure.travis-ci.org/nanliu/puppet-staging.png?branch=master)](http://travis-ci.org/nanliu/puppet-staging)

WARNING: Version 0.2.0 no longer uses hiera functions. The same behavior should be available in Puppet 3.0.

## Usage

Specify a different default staging path (must be declared before using resource):

    class { 'staging':
      path  => '/var/staging',
      owner => 'puppet',
      group => 'puppet',
    }

Staging files from various sources:

    staging::file { 'sample':
      source => 'puppet://modules/staging/sample',
    }

    staging::file { 'apache-tomcat-6.0.35':
      source => 'http://apache.cs.utah.edu/tomcat/tomcat-6/v6.0.35/bin/apache-tomcat-6.0.35.tar.gz',
    }


Staging and extracting files:

    staging::file { 'sample.tar.gz':
      source => 'puppet:///modules/staging/sample.tar.gz'
    }

    staging::extract { 'sample.tar.gz':
      target  => '/tmp/staging',
      creates => '/tmp/staging/sample',
      require => Staging::File['sample.tar.gz'],
    }

Staging files currently support the following source:

* http(s)://
* puppet://
* ftp://
* local (though this doesn't serve any real purpose.)

## Contributor

* Adrien Thebo
* gizero
* Harald Skoglund
* Hunter Haugen
* Justin Clayton
* Owen Jacobson
* Reid Vandewiele
require 'rubygems'
require 'puppetlabs_spec_helper/rake_tasks'

def io_popen(command)
  IO.popen(command) do |io|
    io.each do |line|
      print line
      yield line if block_given?
    end
  end
end

# Customize lint option
task :lint do
  PuppetLint.configuration.send("disable_80chars")
  PuppetLint.configuration.send("disable_class_parameter_defaults")
end

desc "Validate manifests, templates, and ruby files in lib."
task :validate do
  Dir['manifests/**/*.pp'].each do |manifest|
    sh "puppet parser validate --noop #{manifest}"
  end
  Dir['lib/**/*.rb'].each do |lib_file|
    sh "ruby -c #{lib_file}"
  end
  Dir['templates/**/*.erb'].each do |template|
    sh "erb -P -x -T '-' #{template} | ruby -c"
  end
end

# Initialize vagrant instance for testing
desc "Powers on Vagrant VMs with specific manifests"
task :vagrant, :manifest do |t, args|
  Rake::Task["spec_prep"].execute

  prefix = "VAGRANT_MANIFEST='#{args[:manifest]||'init.pp'}'"

  puts args[:manifest]
  provision = false
  io_popen("export #{prefix}; vagrant up --provider=vmware_fusion") do |line|
    provision = true if line =~ /Machine is already running./
  end
  io_popen("export #{prefix}; vagrant provision") if provision
end

# Cleanup vagrant environment
task :vagrant_clean do
  `vagrant destroy -f`
  Rake::Task["spec_clean"].execute
end
# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure("2") do |config|
  # All Vagrant configuration is done here. The most common configuration
  # options are documented and commented below. For a complete reference,
  # please see the online documentation at vagrantup.com.

  #config.vm.synced_folder "manifests", "/tmp/manifests", "tests"
  config.vm.synced_folder "./", "/etc/puppet/modules/staging"

  config.vm.define :staging do |m|
    m.vm.box = "centos63"
    m.vm.box_url = "https://dl.dropbox.com/s/eqdrqnla4na8qax/centos63.box"

    m.vm.hostname = 'staging'
    m.vm.provider :vmware_fusion do |v|
      v.vmx["displayName"] = "staging"
      v.vmx["memsize"] = 512
      v.vmx["numvcpus"] = 4
    end

    m.vm.provision :puppet do |puppet|
      puppet.manifests_path = "tests"
      puppet.module_path    = "spec/fixtures/modules/"
      puppet.manifest_file  = "init.pp"
    end
  end
end
<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="content-type" content="text/html;charset=utf-8">
  <title>deploy.pp</title>
  <link rel="stylesheet" href="http://jashkenas.github.com/docco/resources/docco.css">
</head>
<body>
<div id='container'>
  <div id="background"></div>
  <div id="jump_to">
    Jump To &hellip;
    <div id="jump_wrapper">
      <div id="jump_page">
          <a class="source" href="deploy.html">deploy.pp</a>
          <a class="source" href="extract.html">extract.pp</a>
          <a class="source" href="file.html">file.pp</a>
          <a class="source" href="init.html">init.pp</a>
      </div>
    </div>
  </div>
  <table cellspacing=0 cellpadding=0>
  <thead>
    <tr>
      <th class=docs><h1>deploy.pp</h1></th>
      <th class=code></th>
    </tr>
  </thead>
  <tbody>
    <tr id='section-Define:_staging::deploy'>
      <td class=docs>
        <div class="pilwrap">
          <a class="pilcrow" href="#section-Define:_staging::deploy">&#182;</a>
        </div>
        <h3>Define: staging::deploy</h3>

<p>The define resource extracts compressed file to a staging location.</p>

<h3>Parameters:</h3>

<ul>
<li>[<em>source</em>]:  the source file location, supports local files, puppet://, http://, https://, ftp:// (default: )</li>
<li>[<em>target</em>]:  the target extraction directory (default: )</li>
<li>[<em>staging_path</em>]:  the staging location for compressed file. defaults to ${staging::path}/${caller_module_name} (default: undef)</li>
<li>[<em>username</em>]:  https or ftp username (default: undef)</li>
<li>[<em>certificate</em>]:  https certifcate file (default: undef)</li>
<li>[<em>password</em>]:  https or ftp user password or https certificate password (default: undef)</li>
<li>[<em>environment</em>]:  environment variable for settings such as http_proxy (default: undef)</li>
<li>[<em>timeout</em>]:  the time to wait for the file transfer to complete (default: undef)</li>
<li>[<em>user</em>]:  extract file as this user (default: undef)</li>
<li>[<em>group</em>]:  extract group as this group (default: undef)</li>
<li>[<em>creates</em>]:  the file/folder created after extraction. if unspecified defaults to ${target}/${name} (default: undef)</li>
<li>[<em>unless</em>]:  alternative way to conditionally extract file (default: undef)</li>
<li>[<em>onlyif</em>]:  alternative way to conditionally extract file (default: undef)</li>
</ul>


<h3>Usage:</h3>

<pre><code>staging::deploy { 'sample.tar.gz':
  source =&gt; 'puppet:///modules/staging/sample.tar.gz',
  target =&gt; '/usr/local',
}
</code></pre>

      </td>
      <td class=code>
        <div class='highlight'><pre><span class="n">define</span> <span class="n">staging</span><span class="o">::</span><span class="n">deploy</span> <span class="p">(</span>
  <span class="vg">$source</span><span class="p">,</span>               
  <span class="vg">$target</span><span class="p">,</span>               
  <span class="vg">$staging_path</span> <span class="o">=</span> <span class="k">undef</span><span class="p">,</span> 
  <span class="vg">$username</span>     <span class="o">=</span> <span class="k">undef</span><span class="p">,</span> 
  <span class="vg">$certificate</span>  <span class="o">=</span> <span class="k">undef</span><span class="p">,</span> 
  <span class="vg">$password</span>     <span class="o">=</span> <span class="k">undef</span><span class="p">,</span> 
  <span class="vg">$environment</span>  <span class="o">=</span> <span class="k">undef</span><span class="p">,</span> 
  <span class="vg">$timeout</span>      <span class="o">=</span> <span class="k">undef</span><span class="p">,</span> 
  <span class="vg">$user</span>         <span class="o">=</span> <span class="k">undef</span><span class="p">,</span> 
  <span class="vg">$group</span>        <span class="o">=</span> <span class="k">undef</span><span class="p">,</span> 
  <span class="vg">$creates</span>      <span class="o">=</span> <span class="k">undef</span><span class="p">,</span> 
  <span class="vg">$unless</span>       <span class="o">=</span> <span class="k">undef</span><span class="p">,</span> 
  <span class="vg">$onlyif</span>       <span class="o">=</span> <span class="k">undef</span>  
<span class="p">)</span> <span class="p">{</span>

  <span class="n">staging</span><span class="o">::</span><span class="n">file</span> <span class="p">{</span> <span class="vg">$name</span><span class="p">:</span>
    <span class="n">source</span>      <span class="o">=&gt;</span> <span class="vg">$source</span><span class="p">,</span>
    <span class="n">target</span>      <span class="o">=&gt;</span> <span class="vg">$staging_path</span><span class="p">,</span>
    <span class="n">username</span>    <span class="o">=&gt;</span> <span class="vg">$username</span><span class="p">,</span>
    <span class="n">certificate</span> <span class="o">=&gt;</span> <span class="vg">$certificate</span><span class="p">,</span>
    <span class="n">password</span>    <span class="o">=&gt;</span> <span class="vg">$password</span><span class="p">,</span>
    <span class="n">environment</span> <span class="o">=&gt;</span> <span class="vg">$environment</span><span class="p">,</span>
    <span class="n">subdir</span>      <span class="o">=&gt;</span> <span class="vg">$caller_module_name</span><span class="p">,</span>
    <span class="n">timeout</span>     <span class="o">=&gt;</span> <span class="vg">$timeout</span><span class="p">,</span>
  <span class="p">}</span>

  <span class="n">staging</span><span class="o">::</span><span class="n">extract</span> <span class="p">{</span> <span class="vg">$name</span><span class="p">:</span>
    <span class="n">target</span>      <span class="o">=&gt;</span> <span class="vg">$target</span><span class="p">,</span>
    <span class="n">source</span>      <span class="o">=&gt;</span> <span class="vg">$staging_path</span><span class="p">,</span>
    <span class="n">user</span>        <span class="o">=&gt;</span> <span class="vg">$user</span><span class="p">,</span>
    <span class="n">group</span>       <span class="o">=&gt;</span> <span class="vg">$group</span><span class="p">,</span>
    <span class="n">environment</span> <span class="o">=&gt;</span> <span class="vg">$environment</span><span class="p">,</span>
    <span class="n">subdir</span>      <span class="o">=&gt;</span> <span class="vg">$caller_module_name</span><span class="p">,</span>
    <span class="n">creates</span>     <span class="o">=&gt;</span> <span class="vg">$creates</span><span class="p">,</span>
    <span class="k">unless</span>      <span class="o">=&gt;</span> <span class="vg">$unless</span><span class="p">,</span>
    <span class="n">onlyif</span>      <span class="o">=&gt;</span> <span class="vg">$onlyif</span><span class="p">,</span>
    <span class="nb">require</span>     <span class="o">=&gt;</span> <span class="no">Staging</span><span class="o">::</span><span class="no">File</span><span class="o">[</span><span class="vg">$name</span><span class="o">]</span><span class="p">,</span>
  <span class="p">}</span>

<span class="p">}</span></pre></div>
      </td>
    </tr>
  </table>
</div>
</body>
<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="content-type" content="text/html;charset=utf-8">
  <title>extract.pp</title>
  <link rel="stylesheet" href="http://jashkenas.github.com/docco/resources/docco.css">
</head>
<body>
<div id='container'>
  <div id="background"></div>
  <div id="jump_to">
    Jump To &hellip;
    <div id="jump_wrapper">
      <div id="jump_page">
          <a class="source" href="deploy.html">deploy.pp</a>
          <a class="source" href="extract.html">extract.pp</a>
          <a class="source" href="file.html">file.pp</a>
          <a class="source" href="init.html">init.pp</a>
      </div>
    </div>
  </div>
  <table cellspacing=0 cellpadding=0>
  <thead>
    <tr>
      <th class=docs><h1>extract.pp</h1></th>
      <th class=code></th>
    </tr>
  </thead>
  <tbody>
    <tr id='section-Define:_staging::extract'>
      <td class=docs>
        <div class="pilwrap">
          <a class="pilcrow" href="#section-Define:_staging::extract">&#182;</a>
        </div>
        <h3>Define: staging::extract</h3>

<p>Define resource to extract files from staging directories to target directories.</p>

<h3>Parameters:</h3>

<ul>
<li>[<em>target</em>]:  the target extraction directory (default: )</li>
<li>[<em>source</em>]:  the source compression file, supports tar, tar.gz, zip, war (default: undef)</li>
<li>[<em>creates</em>]:  the file created after extraction. if unspecified defaults ${staging::path}/${caller_module_name}/${name} ${target}/${name} (default: undef)</li>
<li>[<em>unless</em>]:  alternative way to conditionally check whether to extract file. (default: undef)</li>
<li>[<em>onlyif</em>]:  alternative way to conditionally check whether to extract file. (default: undef)</li>
<li>[<em>user</em>]:  extract file as this user. (default: undef)</li>
<li>[<em>group</em>]:   extract file as this group. (default: undef)</li>
<li>[<em>environment</em>]:  environment variables. (default: undef)</li>
<li>[<em>subdir</em>]:  subdir per module in staging directory. (default: $caller_module_name)</li>
</ul>


<h3>Usage:</h3>

<pre><code>$caller_module_name = 'demo'

class { 'staging':
  path =&gt; '/tmp/staging',
}

staging::file { 'sample.tar.gz':
  source =&gt; 'puppet:///modules/staging/sample.tar.gz'
}

staging::extract { 'sample.tar.gz':
  target  =&gt; '/tmp/staging',
  creates =&gt; '/tmp/staging/sample',
  require =&gt; Staging::File['sample.tar.gz'],
}
</code></pre>
      </td>
      <td class=code>
        <div class='highlight'><pre><span class="n">define</span> <span class="n">staging</span><span class="o">::</span><span class="n">extract</span> <span class="p">(</span>
  <span class="vg">$target</span><span class="p">,</span>              
  <span class="vg">$source</span>      <span class="o">=</span> <span class="k">undef</span><span class="p">,</span> 
  <span class="vg">$creates</span>     <span class="o">=</span> <span class="k">undef</span><span class="p">,</span> 
  <span class="vg">$unless</span>      <span class="o">=</span> <span class="k">undef</span><span class="p">,</span> 
  <span class="vg">$onlyif</span>      <span class="o">=</span> <span class="k">undef</span><span class="p">,</span> 
  <span class="vg">$user</span>        <span class="o">=</span> <span class="k">undef</span><span class="p">,</span> 
  <span class="vg">$group</span>       <span class="o">=</span> <span class="k">undef</span><span class="p">,</span> 
  <span class="vg">$environment</span> <span class="o">=</span> <span class="k">undef</span><span class="p">,</span> 
  <span class="vg">$subdir</span>      <span class="o">=</span> <span class="vg">$caller_module_name</span> 
<span class="p">)</span> <span class="p">{</span>

  <span class="kp">include</span> <span class="n">staging</span>

  <span class="k">if</span> <span class="vg">$source</span> <span class="p">{</span>
    <span class="vg">$source_path</span> <span class="o">=</span> <span class="vg">$source</span>
  <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
    <span class="vg">$source_path</span> <span class="o">=</span> <span class="s2">&quot;${staging::path}/${subdir}/${name}&quot;</span>
  <span class="p">}</span></pre></div>
      </td>
    </tr>
    <tr id='section-2'>
      <td class=docs>
        <div class="pilwrap">
          <a class="pilcrow" href="#section-2">&#182;</a>
        </div>
        <p>Use user supplied creates path, set default value if creates, unless or
onlyif is not supplied.</p>

      </td>
      <td class=code>
        <div class='highlight'><pre>  <span class="k">if</span> <span class="vg">$creates</span> <span class="p">{</span>
    <span class="vg">$creates_path</span> <span class="o">=</span> <span class="vg">$creates</span>
  <span class="p">}</span> <span class="k">elsif</span> <span class="o">!</span> <span class="p">(</span><span class="vg">$unless</span> <span class="ow">or</span> <span class="vg">$onlyif</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="vg">$name</span> <span class="o">=~</span> <span class="sr">/.tar.gz$/</span> <span class="p">{</span>
      <span class="vg">$folder</span>       <span class="o">=</span> <span class="n">staging_parse</span><span class="p">(</span><span class="vg">$name</span><span class="p">,</span> <span class="s1">&#39;basename&#39;</span><span class="p">,</span> <span class="s1">&#39;.tar.gz&#39;</span><span class="p">)</span>
      <span class="vg">$creates_path</span> <span class="o">=</span> <span class="s2">&quot;${target}/${folder}&quot;</span>
    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
      <span class="vg">$folder</span>       <span class="o">=</span> <span class="n">staging_parse</span><span class="p">(</span><span class="vg">$name</span><span class="p">,</span> <span class="s1">&#39;basename&#39;</span><span class="p">)</span>
      <span class="vg">$creates_path</span> <span class="o">=</span> <span class="s2">&quot;${target}/${folder}&quot;</span>
    <span class="p">}</span>
  <span class="p">}</span>

  <span class="k">if</span> <span class="n">scope_defaults</span><span class="p">(</span><span class="s1">&#39;Exec&#39;</span><span class="p">,</span><span class="s1">&#39;path&#39;</span><span class="p">)</span> <span class="p">{</span>
    <span class="no">Exec</span><span class="p">{</span>
      <span class="n">cwd</span>         <span class="o">=&gt;</span> <span class="vg">$target</span><span class="p">,</span>
      <span class="n">user</span>        <span class="o">=&gt;</span> <span class="vg">$user</span><span class="p">,</span>
      <span class="n">group</span>       <span class="o">=&gt;</span> <span class="vg">$group</span><span class="p">,</span>
      <span class="n">environment</span> <span class="o">=&gt;</span> <span class="vg">$environment</span><span class="p">,</span>
      <span class="n">creates</span>     <span class="o">=&gt;</span> <span class="vg">$creates_path</span><span class="p">,</span>
      <span class="k">unless</span>      <span class="o">=&gt;</span> <span class="vg">$unless</span><span class="p">,</span>
      <span class="n">onlyif</span>      <span class="o">=&gt;</span> <span class="vg">$onlyif</span><span class="p">,</span>
      <span class="n">logoutput</span>   <span class="o">=&gt;</span> <span class="n">on_failure</span><span class="p">,</span>
    <span class="p">}</span>
  <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
    <span class="no">Exec</span><span class="p">{</span>
      <span class="n">path</span>        <span class="o">=&gt;</span> <span class="vg">$:</span><span class="ss">:path</span><span class="p">,</span>
      <span class="n">cwd</span>         <span class="o">=&gt;</span> <span class="vg">$target</span><span class="p">,</span>
      <span class="n">user</span>        <span class="o">=&gt;</span> <span class="vg">$user</span><span class="p">,</span>
      <span class="n">group</span>       <span class="o">=&gt;</span> <span class="vg">$group</span><span class="p">,</span>
      <span class="n">environment</span> <span class="o">=&gt;</span> <span class="vg">$environment</span><span class="p">,</span>
      <span class="n">creates</span>     <span class="o">=&gt;</span> <span class="vg">$creates_path</span><span class="p">,</span>
      <span class="k">unless</span>      <span class="o">=&gt;</span> <span class="vg">$unless</span><span class="p">,</span>
      <span class="n">onlyif</span>      <span class="o">=&gt;</span> <span class="vg">$onlyif</span><span class="p">,</span>
      <span class="n">logoutput</span>   <span class="o">=&gt;</span> <span class="n">on_failure</span><span class="p">,</span>
    <span class="p">}</span>
  <span class="p">}</span>

  <span class="k">case</span> <span class="vg">$name</span> <span class="p">{</span>
    <span class="sr">/.tar$/</span><span class="p">:</span> <span class="p">{</span>
      <span class="vg">$command</span> <span class="o">=</span> <span class="s2">&quot;tar xf ${source_path}&quot;</span>
    <span class="p">}</span>

    <span class="sr">/(.tgz|.tar.gz)$/</span><span class="p">:</span> <span class="p">{</span>
      <span class="k">if</span> <span class="vg">$:</span><span class="ss">:osfamily</span> <span class="o">==</span> <span class="s1">&#39;Solaris&#39;</span> <span class="p">{</span>
        <span class="vg">$command</span> <span class="o">=</span> <span class="s2">&quot;gunzip -dc &lt; ${source_path} | tar xf - &quot;</span>
      <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
        <span class="vg">$command</span> <span class="o">=</span> <span class="s2">&quot;tar xzf ${source_path}&quot;</span>
      <span class="p">}</span>
    <span class="p">}</span>

    <span class="sr">/.zip$/</span><span class="p">:</span> <span class="p">{</span>
      <span class="vg">$command</span> <span class="o">=</span> <span class="s2">&quot;unzip ${source_path}&quot;</span>
    <span class="p">}</span>

    <span class="sr">/.war$/</span><span class="p">:</span> <span class="p">{</span>
      <span class="vg">$command</span> <span class="o">=</span> <span class="s2">&quot;jar xf ${source_path}&quot;</span>
    <span class="p">}</span>

    <span class="n">default</span><span class="p">:</span> <span class="p">{</span>
      <span class="nb">fail</span><span class="p">(</span><span class="s2">&quot;staging::extract: unsupported file format ${name}.&quot;</span><span class="p">)</span>
    <span class="p">}</span>
  <span class="p">}</span>

  <span class="nb">exec</span> <span class="p">{</span> <span class="s2">&quot;extract ${name}&quot;</span><span class="p">:</span>
    <span class="n">command</span> <span class="o">=&gt;</span> <span class="vg">$command</span><span class="p">,</span>
  <span class="p">}</span>
<span class="p">}</span></pre></div>
      </td>
    </tr>
  </table>
</div>
</body>
<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="content-type" content="text/html;charset=utf-8">
  <title>file.pp</title>
  <link rel="stylesheet" href="http://jashkenas.github.com/docco/resources/docco.css">
</head>
<body>
<div id='container'>
  <div id="background"></div>
  <div id="jump_to">
    Jump To &hellip;
    <div id="jump_wrapper">
      <div id="jump_page">
          <a class="source" href="deploy.html">deploy.pp</a>
          <a class="source" href="extract.html">extract.pp</a>
          <a class="source" href="file.html">file.pp</a>
          <a class="source" href="init.html">init.pp</a>
      </div>
    </div>
  </div>
  <table cellspacing=0 cellpadding=0>
  <thead>
    <tr>
      <th class=docs><h1>file.pp</h1></th>
      <th class=code></th>
    </tr>
  </thead>
  <tbody>
    <tr id='section-Define:_staging::file'>
      <td class=docs>
        <div class="pilwrap">
          <a class="pilcrow" href="#section-Define:_staging::file">&#182;</a>
        </div>
        <h3>Define: staging::file</h3>

<h4>Overview:</h4>

<p>Define resource to retrieve files to staging directories. It is
intententionally not replacing files, as these intend to be large binaries
that are versioned.</p>

<h4>Notes:</h4>

<p>  If you specify a different staging location, please manage the file
  resource as necessary.</p>

<h3>Parameters:</h3>

<ul>
<li>[<em>source</em>]:  the source file location, supports local files, puppet://, http://, https://, ftp:// (default: )</li>
<li>[<em>target</em>]:  the target staging directory, if unspecified ${staging::path}/${caller_module_name} (default: undef)</li>
<li>[<em>username</em>]:  https or ftp username (default: undef)</li>
<li>[<em>certificate</em>]:  https certificate file (default: undef)</li>
<li>[<em>password</em>]:  https or ftp user password or https certificate password (default: undef)</li>
<li>[<em>environment</em>]:  environment variable for settings such as http_proxy, https_proxy, of ftp_proxy (default: undef)</li>
<li>[<em>timeout</em>]:  the the time to wait for the file transfer to complete (default: undef)</li>
<li>[<em>subdir</em>]:  (default: $caller_module_name)</li>
</ul>


<h3>Usage:</h3>

<pre><code>$caller_module_name = 'demo'

class { 'staging':
  path =&gt; '/tmp/staging',
}

staging::file { 'sample':
  source =&gt; 'puppet:///modules/staging/sample',
}

staging::file { 'passwd':
  source =&gt; '/etc/passwd',
}

staging::file { 'manpage.html':
  source =&gt; 'http://curl.haxx.se/docs/manpage.html',
}
</code></pre>

      </td>
      <td class=code>
        <div class='highlight'><pre><span class="n">define</span> <span class="n">staging</span><span class="o">::</span><span class="n">file</span> <span class="p">(</span>
  <span class="vg">$source</span><span class="p">,</span>              
  <span class="vg">$target</span>      <span class="o">=</span> <span class="k">undef</span><span class="p">,</span> 
  <span class="vg">$username</span>    <span class="o">=</span> <span class="k">undef</span><span class="p">,</span> 
  <span class="vg">$certificate</span> <span class="o">=</span> <span class="k">undef</span><span class="p">,</span> 
  <span class="vg">$password</span>    <span class="o">=</span> <span class="k">undef</span><span class="p">,</span> 
  <span class="vg">$environment</span> <span class="o">=</span> <span class="k">undef</span><span class="p">,</span> 
  <span class="vg">$timeout</span>     <span class="o">=</span> <span class="k">undef</span><span class="p">,</span> 
  <span class="vg">$subdir</span>      <span class="o">=</span> <span class="vg">$caller_module_name</span>
<span class="p">)</span> <span class="p">{</span>

  <span class="kp">include</span> <span class="n">staging</span>

  <span class="k">if</span> <span class="vg">$target</span> <span class="p">{</span>
    <span class="vg">$target_file</span> <span class="o">=</span> <span class="vg">$target</span>
    <span class="vg">$staging_dir</span> <span class="o">=</span> <span class="n">staging_parse</span><span class="p">(</span><span class="vg">$target</span><span class="p">,</span> <span class="s1">&#39;parent&#39;</span><span class="p">)</span>
  <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
    <span class="vg">$staging_dir</span> <span class="o">=</span> <span class="s2">&quot;${staging::path}/${subdir}&quot;</span>
    <span class="vg">$target_file</span> <span class="o">=</span> <span class="s2">&quot;${staging_dir}/${name}&quot;</span>

    <span class="k">if</span> <span class="o">!</span> <span class="n">defined</span><span class="p">(</span><span class="no">File</span><span class="o">[</span><span class="vg">$staging_dir</span><span class="o">]</span><span class="p">)</span> <span class="p">{</span>
      <span class="n">file</span> <span class="p">{</span> <span class="vg">$staging_dir</span><span class="p">:</span>
        <span class="k">ensure</span><span class="o">=&gt;</span><span class="n">directory</span><span class="p">,</span>
      <span class="p">}</span>
    <span class="p">}</span>
  <span class="p">}</span>

  <span class="no">Exec</span> <span class="p">{</span>
    <span class="n">path</span>        <span class="o">=&gt;</span> <span class="s1">&#39;/usr/local/bin:/usr/bin:/bin&#39;</span><span class="p">,</span>
    <span class="n">environment</span> <span class="o">=&gt;</span> <span class="vg">$environment</span><span class="p">,</span>
    <span class="n">cwd</span>         <span class="o">=&gt;</span> <span class="vg">$staging_dir</span><span class="p">,</span>
    <span class="n">creates</span>     <span class="o">=&gt;</span> <span class="vg">$target_file</span><span class="p">,</span>
    <span class="n">timeout</span>     <span class="o">=&gt;</span> <span class="vg">$timeout</span><span class="p">,</span>
    <span class="n">logoutput</span>   <span class="o">=&gt;</span> <span class="n">on_failure</span><span class="p">,</span>
  <span class="p">}</span>

  <span class="k">case</span> <span class="vg">$source</span> <span class="p">{</span>
    <span class="sr">/^\//</span><span class="p">:</span> <span class="p">{</span>
      <span class="n">file</span> <span class="p">{</span> <span class="vg">$target_file</span><span class="p">:</span>
        <span class="n">source</span>  <span class="o">=&gt;</span> <span class="vg">$source</span><span class="p">,</span>
        <span class="n">replace</span> <span class="o">=&gt;</span> <span class="kp">false</span><span class="p">,</span>
      <span class="p">}</span>
    <span class="p">}</span>

    <span class="sr">/^puppet:\/\//</span><span class="p">:</span> <span class="p">{</span>
      <span class="n">file</span> <span class="p">{</span> <span class="vg">$target_file</span><span class="p">:</span>
        <span class="n">source</span>  <span class="o">=&gt;</span> <span class="vg">$source</span><span class="p">,</span>
        <span class="n">replace</span> <span class="o">=&gt;</span> <span class="kp">false</span><span class="p">,</span>
      <span class="p">}</span>
    <span class="p">}</span>

    <span class="sr">/^http:\/\//</span><span class="p">:</span> <span class="p">{</span>
      <span class="nb">exec</span> <span class="p">{</span> <span class="vg">$target_file</span><span class="p">:</span>
        <span class="n">command</span>     <span class="o">=&gt;</span> <span class="s2">&quot;curl -L -o ${name} ${source}&quot;</span><span class="p">,</span>
      <span class="p">}</span>
    <span class="p">}</span>

    <span class="sr">/^https:\/\//</span><span class="p">:</span> <span class="p">{</span>
      <span class="k">if</span> <span class="vg">$username</span> <span class="p">{</span>
        <span class="vg">$command</span> <span class="o">=</span> <span class="s2">&quot;curl -L -o ${name} -u ${username}:${password} ${source}&quot;</span>
      <span class="p">}</span> <span class="k">elsif</span> <span class="vg">$certificate</span> <span class="p">{</span>
        <span class="vg">$command</span> <span class="o">=</span> <span class="s2">&quot;curl -L -o ${name} -E ${certificate}:${password} ${source}&quot;</span>
      <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
        <span class="vg">$command</span> <span class="o">=</span> <span class="s2">&quot;curl -L -o ${name} ${source}&quot;</span>
      <span class="p">}</span>

      <span class="nb">exec</span> <span class="p">{</span> <span class="vg">$target_file</span><span class="p">:</span>
        <span class="n">command</span>     <span class="o">=&gt;</span> <span class="vg">$command</span><span class="p">,</span>
      <span class="p">}</span>
    <span class="p">}</span>

    <span class="sr">/^ftp:\/\//</span><span class="p">:</span> <span class="p">{</span>
      <span class="k">if</span> <span class="vg">$username</span> <span class="p">{</span>
        <span class="vg">$command</span> <span class="o">=</span> <span class="s2">&quot;curl -o ${name} -u ${username}:${password} ${source}&quot;</span>
      <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
        <span class="vg">$command</span> <span class="o">=</span> <span class="s2">&quot;curl -o ${name} ${source}&quot;</span>
      <span class="p">}</span>

      <span class="nb">exec</span> <span class="p">{</span> <span class="vg">$target_file</span><span class="p">:</span>
        <span class="n">command</span>     <span class="o">=&gt;</span> <span class="vg">$command</span><span class="p">,</span>
      <span class="p">}</span>
    <span class="p">}</span>

    <span class="n">default</span><span class="p">:</span> <span class="p">{</span>
      <span class="nb">fail</span><span class="p">(</span><span class="s2">&quot;stage::file: do not recognize source ${source}.&quot;</span><span class="p">)</span>
    <span class="p">}</span>
  <span class="p">}</span>

<span class="p">}</span></pre></div>
      </td>
    </tr>
  </table>
</div>
</body>
<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="content-type" content="text/html;charset=utf-8">
  <title>init.pp</title>
  <link rel="stylesheet" href="http://jashkenas.github.com/docco/resources/docco.css">
</head>
<body>
<div id='container'>
  <div id="background"></div>
  <div id="jump_to">
    Jump To &hellip;
    <div id="jump_wrapper">
      <div id="jump_page">
          <a class="source" href="deploy.html">deploy.pp</a>
          <a class="source" href="extract.html">extract.pp</a>
          <a class="source" href="file.html">file.pp</a>
          <a class="source" href="init.html">init.pp</a>
      </div>
    </div>
  </div>
  <table cellspacing=0 cellpadding=0>
  <thead>
    <tr>
      <th class=docs><h1>init.pp</h1></th>
      <th class=code></th>
    </tr>
  </thead>
  <tbody>
    <tr id='section-Class:_staging'>
      <td class=docs>
        <div class="pilwrap">
          <a class="pilcrow" href="#section-Class:_staging">&#182;</a>
        </div>
        <h3>Class: staging</h3>

<p>This module manages staging and extraction of files from various sources.</p>

<h4>Actions:</h4>

<p>Creates the root staging directory. By default files will be created in a subdirectory matching the caller_module_name.</p>

<p>   /opt/staging/</p>

<pre><code>          |-- puppet
          |   `-- puppet.enterprise.2.0.tar.gz
          `-- tomcat
              `-- tomcat.5.0.tar.gz
</code></pre>

<h3>Parameters:</h3>

<ul>
<li>[<em>path</em>]:  staging directory filepath (default: &lsquo;/opt/staging&rsquo;)</li>
<li>[<em>owner</em>]:  staging directory owner (default: &lsquo;0&rsquo;)</li>
<li>[<em>group</em>]:  staging directory group (default: &lsquo;0&rsquo;)</li>
<li>[<em>mode</em>]:  staging directory permission (default: &lsquo;0755&rsquo;)</li>
</ul>


<h3>Usage:</h3>

<pre><code>include staging
</code></pre>

      </td>
      <td class=code>
        <div class='highlight'><pre><span class="k">class</span> <span class="n">staging</span> <span class="p">(</span>
  <span class="vg">$path</span>  <span class="o">=</span> <span class="s1">&#39;/opt/staging&#39;</span><span class="p">,</span> 
  <span class="vg">$owner</span> <span class="o">=</span> <span class="s1">&#39;0&#39;</span><span class="p">,</span>            
  <span class="vg">$group</span> <span class="o">=</span> <span class="s1">&#39;0&#39;</span><span class="p">,</span>            
  <span class="vg">$mode</span>  <span class="o">=</span> <span class="s1">&#39;0755&#39;</span>          
<span class="p">)</span> <span class="p">{</span>

  <span class="n">file</span> <span class="p">{</span> <span class="vg">$path</span><span class="p">:</span>
    <span class="k">ensure</span> <span class="o">=&gt;</span> <span class="n">directory</span><span class="p">,</span>
    <span class="n">owner</span>  <span class="o">=&gt;</span> <span class="vg">$owner</span><span class="p">,</span>
    <span class="n">group</span>  <span class="o">=&gt;</span> <span class="vg">$group</span><span class="p">,</span>
    <span class="n">mode</span>   <span class="o">=&gt;</span> <span class="vg">$mode</span><span class="p">,</span>
  <span class="p">}</span>

<span class="p">}</span></pre></div>
      </td>
    </tr>
  </table>
</div>
</body>
sample file to test module.
Facter.add("staging_http_get") do
  setcode do

    fact = nil

    which = lambda do |cmd|
      result = nil
      exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
      ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
        exts.each do |ext|
          exe = File.join(path, "#{cmd}#{ext}")
          result = exe if File.executable? exe
          break if result
        end
        break if result
      end
      result
    end

    ['curl', 'wget', 'powershell'].each do |cmd|
      available = which.call(cmd)
      fact = available ? cmd : nil
      break if fact
    end

    fact

  end
end
Facter.add(:staging_windir) do
  confine :osfamily => :windows
  setcode do
    program_data = `echo %SYSTEMDRIVE%\\ProgramData`.chomp
    if File.directory? program_data
      "#{program_data}\\staging"
    else
      "C:\\staging"
    end
  end
end
module Puppet::Parser::Functions
  newfunction(:scope_defaults, :type => :rvalue, :doc => <<-EOS
Determine if specified resource defaults have a attribute defined in
current scope.
EOS
  ) do |arguments|

    raise(Puppet::ParseError, "scope_defaults(): Wrong number of arguments " +
      "given (#{arguments.size} for 2)") if arguments.size != 2

    # auto capitalize puppet resource for lookup:
    res_type = arguments[0].split('::').collect{ |x| x.capitalize }.join('::')
    res_attr = arguments[1]

    return self.lookupdefaults(res_type).has_key?(res_attr.to_sym)
  end
end
require 'uri'

module Puppet::Parser::Functions
  newfunction(:staging_parse, :type => :rvalue, :doc => <<-EOS
Parse filepath to retrieve information about the file.
    EOS
  ) do |arguments|

    raise(Puppet::ParseError, "staging_parse(): Wrong number of arguments " +
      "given (#{arguments.size} for 1, 2, 3)") if arguments.size < 1 || arguments.size > 3

    source    = arguments[0]
    path      = URI.parse(source).path

    raise Puppet::ParseError, "staging_parse(): #{source.inspect} has no URI " +
      "'path' component" if path.nil?

    info      = arguments[1] ? arguments[1] : 'filename'
    extension = arguments[2] ? arguments[2] : File.extname(path)

    case info
    when 'filename'
      result = File.basename(path)
    when 'basename'
      result = File.basename(path, extension)
    when 'extname'
      result = File.extname(path)
    when 'parent'
      result = File.expand_path(File.join(path, '..'))
    else
      raise Puppet::ParseError, "staging_parse(), unknown parse info #{info}."
    end

    return result
  end
end
# The define resource extracts compressed file to a staging location.
define staging::deploy (
  $source,               #: the source file location, supports local files, puppet://, http://, https://, ftp://
  $target,               #: the target extraction directory
  $staging_path = undef, #: the staging location for compressed file. defaults to ${staging::path}/${caller_module_name}
  $username     = undef, #: https or ftp username
  $certificate  = undef, #: https certifcate file
  $password     = undef, #: https or ftp user password or https certificate password
  $environment  = undef, #: environment variable for settings such as http_proxy
  $timeout      = undef, #: the time to wait for the file transfer to complete
  $user         = undef, #: extract file as this user
  $group        = undef, #: extract group as this group
  $creates      = undef, #: the file/folder created after extraction. if unspecified defaults to ${target}/${name}
  $unless       = undef, #: alternative way to conditionally extract file
  $onlyif       = undef  #: alternative way to conditionally extract file
) {

  staging::file { $name:
    source      => $source,
    target      => $staging_path,
    username    => $username,
    certificate => $certificate,
    password    => $password,
    environment => $environment,
    subdir      => $caller_module_name,
    timeout     => $timeout,
  }

  staging::extract { $name:
    target      => $target,
    source      => $staging_path,
    user        => $user,
    group       => $group,
    environment => $environment,
    subdir      => $caller_module_name,
    creates     => $creates,
    unless      => $unless,
    onlyif      => $onlyif,
    require     => Staging::File[$name],
  }

}
# Define resource to extract files from staging directories to target directories.
define staging::extract (
  $target,              #: the target extraction directory
  $source      = undef, #: the source compression file, supports tar, tar.gz, zip, war
  $creates     = undef, #: the file created after extraction. if unspecified defaults ${staging::path}/${caller_module_name}/${name} ${target}/${name}
  $unless      = undef, #: alternative way to conditionally check whether to extract file.
  $onlyif      = undef, #: alternative way to conditionally check whether to extract file.
  $user        = undef, #: extract file as this user.
  $group       = undef, #:  extract file as this group.
  $environment = undef, #: environment variables.
  $subdir      = $caller_module_name #: subdir per module in staging directory.
) {

  include staging

  if $source {
    $source_path = $source
  } else {
    $source_path = "${staging::path}/${subdir}/${name}"
  }

  # Use user supplied creates path, set default value if creates, unless or
  # onlyif is not supplied.
  if $creates {
    $creates_path = $creates
  } elsif ! ($unless or $onlyif) {
    if $name =~ /.tar.gz$/ {
      $folder       = staging_parse($name, 'basename', '.tar.gz')
    } elsif $name =~ /.tar.bz2$/ {
      $folder       = staging_parse($name, 'basename', '.tar.bz2')
    } else {
      $folder       = staging_parse($name, 'basename')
    }
    $creates_path = "${target}/${folder}"
  }

  if scope_defaults('Exec','path') {
    Exec{
      cwd         => $target,
      user        => $user,
      group       => $group,
      environment => $environment,
      creates     => $creates_path,
      unless      => $unless,
      onlyif      => $onlyif,
      logoutput   => on_failure,
    }
  } else {
    Exec{
      path        => $::path,
      cwd         => $target,
      user        => $user,
      group       => $group,
      environment => $environment,
      creates     => $creates_path,
      unless      => $unless,
      onlyif      => $onlyif,
      logoutput   => on_failure,
    }
  }

  case $name {
    /.tar$/: {
      $command = "tar xf ${source_path}"
    }

    /(.tgz|.tar.gz)$/: {
      if $::osfamily == 'Solaris' {
        $command = "gunzip -dc < ${source_path} | tar xf - "
      } else {
        $command = "tar xzf ${source_path}"
      }
    }

    /.tar.bz2$/: {
      $command = "tar xjf ${source_path}"
    }

    /.zip$/: {
      $command = "unzip ${source_path}"
    }

    /(.war|.jar)$/: {
      $command = "jar xf ${source_path}"
    }

    default: {
      fail("staging::extract: unsupported file format ${name}.")
    }
  }

  exec { "extract ${name}":
    command => $command,
  }
}
# #### Overview:
#
# Define resource to retrieve files to staging directories. It is
# intententionally not replacing files, as these intend to be large binaries
# that are versioned.
#
# #### Notes:
#
#   If you specify a different staging location, please manage the file
#   resource as necessary.
#
define staging::file (
  $source,              #: the source file location, supports local files, puppet://, http://, https://, ftp://
  $target      = undef, #: the target staging directory, if unspecified ${staging::path}/${caller_module_name}
  $username    = undef, #: https or ftp username
  $certificate = undef, #: https certificate file
  $password    = undef, #: https or ftp user password or https certificate password
  $environment = undef, #: environment variable for settings such as http_proxy, https_proxy, of ftp_proxy
  $timeout     = undef, #: the the time to wait for the file transfer to complete
  $curl_option = undef, #: options to pass to curl
  $wget_option = undef, #: options to pass to wget
  $subdir      = $caller_module_name
) {

  include staging

  $quoted_source = shellquote($source)

  if $target {
    $target_file = $target
    $staging_dir = staging_parse($target, 'parent')
  } else {
    $staging_dir = "${staging::path}/${subdir}"
    $target_file = "${staging_dir}/${name}"

    if ! defined(File[$staging_dir]) {
      file { $staging_dir:
        ensure=>directory,
      }
    }
  }

  Exec {
    path        => $staging::exec_path,
    environment => $environment,
    cwd         => $staging_dir,
    creates     => $target_file,
    timeout     => $timeout,
    logoutput   => on_failure,
  }

  case $::staging_http_get {
    'curl', default: {
      $http_get        = "curl ${curl_option} -f -L -o ${name} ${quoted_source}"
      $http_get_passwd = "curl ${curl_option} -f -L -o ${name} -u ${username}:${password} ${quoted_source}"
      $http_get_cert   = "curl ${curl_option} -f -L -o ${name} -E ${certificate}:${password} ${quoted_source}"
      $ftp_get         = "curl ${curl_option} -o ${name} ${quoted_source}"
      $ftp_get_passwd  = "curl ${curl_option} -o ${name} -u ${username}:${password} ${quoted_source}"
    }
    'wget': {
      $http_get        = "wget ${wget_option} -O ${name} ${quoted_source}"
      $http_get_passwd = "wget ${wget_option} -O ${name} --user=${username} --password=${password} ${quoted_source}"
      $http_get_cert   = "wget ${wget_option} -O ${name} --user=${username} --certificate=${certificate} ${quoted_source}"
      $ftp_get         = $http_get
      $ftp_get_passwd  = $http_get_passwd
    }
    'powershell':{
      $http_get           = "powershell.exe -Command \"\$wc = New-Object System.Net.WebClient;\$wc.DownloadFile('${source}','${target_file}')\""
      $ftp_get            = $http_get
      $http_get_password  = "powershell.exe -Command \"\$wc = (New-Object System.Net.WebClient);\$wc.Credentials = New-Object System.Net.NetworkCredential('${username}','${password}');\$wc.DownloadFile(${source},${target_file})\""
      $ftp_get_password   = $http_get_password
    }
  }

  case $source {
    /^\//: {
      file { $target_file:
        source  => $source,
        replace => false,
      }
    }
    /^puppet:\/\//: {
      file { $target_file:
        source  => $source,
        replace => false,
      }
    }
    /^http:\/\//: {
      if $username { $command = $http_get_passwd }
      else         { $command = $http_get        }
      exec { $target_file:
        command   => $command,
      }
    }
    /^https:\/\//: {
      if $username       { $command = $http_get_passwd }
      elsif $certificate { $command = $http_get_cert   }
      else               { $command = $http_get        }
      exec { $target_file:
        command => $command,
      }
    }
    /^ftp:\/\//: {
      if $username       { $command = $ftp_get_passwd }
      else               { $command = $ftp_get        }
      exec { $target_file:
        command     => $command,
      }
    }
    default: {
      fail("stage::file: do not recognize source ${source}.")
    }
  }

}
#   This module manages staging and extraction of files from various sources.
#
# #### Actions:
#
#   Creates the root staging directory. By default files will be created in a subdirectory matching the caller_module_name.
#
#      /opt/staging/
#                 |-- puppet
#                 |   `-- puppet.enterprise.2.0.tar.gz
#                 `-- tomcat
#                     `-- tomcat.5.0.tar.gz
#
class staging (
  $path      = $staging::params::path,     #: staging directory filepath
  $owner     = $staging::params::owner,    #: staging directory owner
  $group     = $staging::params::group,    #: staging directory group
  $mode      = $staging::params::mode,     #: staging directory permission
  $exec_path = $staging::params::exec_path #: executable default path
) inherits staging::params {

  file { $path:
    ensure => directory,
    owner  => $owner,
    group  => $group,
    mode   => $mode,
  }

}
# OS specific parameters
class staging::params {
  case $::osfamily {
    default: {
      $path      = '/opt/staging'
      $owner     = '0'
      $group     = '0'
      $mode      = '0755'
      $exec_path = '/usr/local/bin:/usr/bin:/bin'
    }
    'Solaris': {
      $path      = '/opt/staging'
      $owner     = '0'
      $group     = '0'
      $mode      = '0755'
      $exec_path = '/usr/local/bin:/usr/bin:/bin:/usr/sfw/bin'
    }
    'windows': {
      $path      = $::staging_windir
      $owner     = undef
      $group     = undef
      $mode      = '0755'
      $exec_path = $::path
    }
  }
}
require 'spec_helper'
describe 'staging::deploy', :type => :define do

  # forcing a more sane caller_module_name to match real usage.
  let(:facts) { { :caller_module_name => 'spec',
                  :osfamily           => 'RedHat',
                  :path               => '/usr/local/bin:/usr/bin:/bin', } }

  describe 'when deploying tar.gz' do
    let(:title) { 'sample.tar.gz' }
    let(:params) { { :source => 'puppet:///modules/staging/sample.tar.gz',
      :target => '/usr/local' } }

    it {
      should contain_file('/opt/staging')
      should contain_file('/opt/staging/spec/sample.tar.gz')
      should contain_exec('extract sample.tar.gz').with({
        :command => 'tar xzf /opt/staging/spec/sample.tar.gz',
        :path    => '/usr/local/bin:/usr/bin:/bin',
        :cwd     => '/usr/local',
        :creates => '/usr/local/sample'
      })
    }
  end

end
require 'spec_helper'
describe 'staging::extract', :type => :define do

  # forcing a more sane caller_module_name to match real usage.
  let(:facts) { { :caller_module_name => 'spec',
                  :osfamily           => 'RedHat',
                  :path               => '/usr/local/bin:/usr/bin:/bin' } }

  describe 'when deploying tar.gz' do
    let(:title) { 'sample.tar.gz' }
    let(:params) { { :target => '/opt' } }

    it {
      should contain_file('/opt/staging')
      should contain_exec('extract sample.tar.gz').with({
        :command => 'tar xzf /opt/staging/spec/sample.tar.gz',
        :path    => '/usr/local/bin:/usr/bin:/bin',
        :cwd     => '/opt',
        :creates => '/opt/sample'
      })
    }
  end

  describe 'when deploying zip' do
    let(:title) { 'sample.zip' }
    let(:params) { { :target => '/opt' } }

    it { should contain_file('/opt/staging')
      should contain_exec('extract sample.zip').with({
        :command => 'unzip /opt/staging/spec/sample.zip',
        :path    => '/usr/local/bin:/usr/bin:/bin',
        :cwd     => '/opt',
        :creates => '/opt/sample'
      })
    }
  end

  describe 'when deploying war' do
    let(:title) { 'sample.war' }
    let(:params) { { :target => '/opt' } }

    it { should contain_file('/opt/staging')
      should contain_exec('extract sample.war').with({
        :command => 'jar xf /opt/staging/spec/sample.war',
        :path    => '/usr/local/bin:/usr/bin:/bin',
        :cwd     => '/opt',
        :creates => '/opt/sample'
      })
    }
  end

  describe 'when deploying unknown' do
     let(:title) { 'sample.zzz'}
     let(:params) { { :target => '/opt' } }

     it { expect { should contain_exec("exec sample.zzz") }.to raise_error(Puppet::Error) }
  end
end
require 'spec_helper'
describe 'staging::file', :type => :define do

  # forcing a more sane caller_module_name to match real usage.
  let(:facts) { { :caller_module_name=> 'spec' } }

  describe 'when deploying via puppet' do
    let(:title) { 'sample.tar.gz' }
    let(:params) { { :source => 'puppet:///modules/staging/sample.tar.gz' } }

    it {
      should contain_file('/opt/staging')
      should contain_file('/opt/staging/spec/sample.tar.gz')
      should_not contain_exec('/opt/staging/spec/sample.tar.gz')
    }
  end

  describe 'when deploying via local' do
    let(:title) { 'sample.tar.gz' }
    let(:params) { { :source => '/nfs/sample.tar.gz',
      :target => '/usr/local/sample.tar.gz',
    } }

    it {
      should contain_file('/opt/staging')
      should contain_file('/usr/local/sample.tar.gz')
      should_not contain_exec('/opt/staging/spec/sample.tar.gz')
    }
  end

  describe 'when deploying via http' do
    let(:title) { 'sample.tar.gz' }
    let(:params) { { :source => 'http://webserver/sample.tar.gz' } }

    it {
      should contain_file('/opt/staging')
      should contain_exec('/opt/staging/spec/sample.tar.gz').with( {
        :command => 'curl  -f -L -o sample.tar.gz http://webserver/sample.tar.gz',
        :path        => '/usr/local/bin:/usr/bin:/bin',
        :environment => nil,
        :cwd         => '/opt/staging/spec',
        :creates     => '/opt/staging/spec/sample.tar.gz',
        :logoutput   => 'on_failure',
      })
    }
  end

  describe 'when deploying via http with custom curl options' do
    let(:title) { 'sample.tar.gz' }
    let(:params) { {
      :source => 'http://webserver/sample.tar.gz',
      :curl_option => '-b',
    } }

    it {
      should contain_file('/opt/staging')
      should contain_exec('/opt/staging/spec/sample.tar.gz').with( {
        :command => 'curl -b -f -L -o sample.tar.gz http://webserver/sample.tar.gz',
        :path        => '/usr/local/bin:/usr/bin:/bin',
        :environment => nil,
        :cwd         => '/opt/staging/spec',
        :creates     => '/opt/staging/spec/sample.tar.gz',
        :logoutput   => 'on_failure',
      })
    }
  end

  describe 'when deploying via http with parameters' do
    let(:title) { 'sample.tar.gz' }
    let(:params) { { :source => 'http://webserver/sample.tar.gz',
      :target => '/usr/local/sample.tar.gz',
    } }

    it { should contain_file('/opt/staging')
      should contain_exec('/usr/local/sample.tar.gz').with( {
        :command => 'curl  -f -L -o sample.tar.gz http://webserver/sample.tar.gz',
        :path        => '/usr/local/bin:/usr/bin:/bin',
        :environment => nil,
        :cwd         => '/usr/local',
        :creates     => '/usr/local/sample.tar.gz',
      })
    }
  end

  describe 'when deploying via https' do
     let(:title) { 'sample.tar.gz' }
     let(:params) { { :source => 'https://webserver/sample.tar.gz' } }

     it { should contain_file('/opt/staging') }
     it { should contain_exec('/opt/staging/spec/sample.tar.gz').with( {
       :command => 'curl  -f -L -o sample.tar.gz https://webserver/sample.tar.gz',
       :path        => '/usr/local/bin:/usr/bin:/bin',
       :environment => nil,
       :cwd         => '/opt/staging/spec',
       :creates     => '/opt/staging/spec/sample.tar.gz',
       :logoutput   => 'on_failure',
     }) }
  end

  describe 'when deploying via https with parameters' do
    let(:title) { 'sample.tar.gz' }
    let(:params) { { :source => 'https://webserver/sample.tar.gz',
      :username => 'puppet',
      :password => 'puppet',
    } }

    it {
      should contain_file('/opt/staging')
      should contain_exec('/opt/staging/spec/sample.tar.gz').with( {
        :command => 'curl  -f -L -o sample.tar.gz -u puppet:puppet https://webserver/sample.tar.gz',
        :path        => '/usr/local/bin:/usr/bin:/bin',
        :environment => nil,
        :cwd         => '/opt/staging/spec',
        :creates     => '/opt/staging/spec/sample.tar.gz',
        :logoutput   => 'on_failure',
      })
    }
  end

  describe 'when deploying via ftp' do
    let(:title) { 'sample.tar.gz' }
    let(:params) { { :source => 'ftp://webserver/sample.tar.gz' } }

    it {
      should contain_file('/opt/staging')
      should contain_exec('/opt/staging/spec/sample.tar.gz').with( {
        :command => 'curl  -o sample.tar.gz ftp://webserver/sample.tar.gz',
        :path        => '/usr/local/bin:/usr/bin:/bin',
        :environment => nil,
        :cwd         => '/opt/staging/spec',
        :creates     => '/opt/staging/spec/sample.tar.gz',
        :logoutput   => 'on_failure',
      })
    }
  end

  describe 'when deploying via ftp with parameters' do
    let(:title) { 'sample.tar.gz' }
    let(:params) { { :source => 'ftp://webserver/sample.tar.gz',
      :username => 'puppet',
      :password => 'puppet',
    } }

    it {
      should contain_file('/opt/staging')
      should contain_exec('/opt/staging/spec/sample.tar.gz').with( {
        :command => 'curl  -o sample.tar.gz -u puppet:puppet ftp://webserver/sample.tar.gz',
        :path        => '/usr/local/bin:/usr/bin:/bin',
        :environment => nil,
        :cwd         => '/opt/staging/spec',
        :creates     => '/opt/staging/spec/sample.tar.gz',
        :logoutput   => 'on_failure',
      })
    }
  end

end
:backends: - puppet

:hierarchy: - common

:puppet:
    :datasource: data
require 'rubygems'
require 'puppetlabs_spec_helper/module_spec_helper'
#!/usr/bin/env rspec
require 'spec_helper'

describe "the scope_defaults function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    Puppet::Parser::Functions.function("scope_defaults").should == "function_scope_defaults"
  end

  it "should raise a ParseError if there is less than 2 arguments" do
    expect{ scope.function_scope_defaults([]) }.
      to raise_error(Puppet::ParseError)
  end

  it "should raise a ParseError if there is more than 2 arguments" do
    expect{ scope.function_scope_defaults(['exec', 'path', 'error']) }.
      to raise_error(Puppet::ParseError)
  end

  it "should return false for invalid resource" do
    result = scope.function_scope_defaults(['foo', 'path'])
    result.should(eq(false))
  end

  it "should return false for resource without default attributes" do
    if scope.respond_to? :define_settings
      scope.define_settings('Exec', Puppet::Parser::Resource::Param.new(:name => :path, :value => "/bin"))
    else
      scope.setdefaults('Exec', Puppet::Parser::Resource::Param.new(:name => :path, :value => "/bin"))
    end
    result = scope.function_scope_defaults(['Exec', 'foo'])
    result.should(eq(false))
  end

  it "should return true for resource with default attributes" do
    if scope.respond_to? :define_settings
      scope.define_settings('Exec', Puppet::Parser::Resource::Param.new(:name => :path, :value => "/bin"))
    else
      scope.setdefaults('Exec', Puppet::Parser::Resource::Param.new(:name => :path, :value => "/bin"))
    end
    result = scope.function_scope_defaults(['Exec', 'path'])
    result.should(eq(true))
  end
end
#!/usr/bin/env rspec
require 'spec_helper'

describe "the staging parser function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    Puppet::Parser::Functions.function("staging_parse").should == "function_staging_parse"
  end

  it "should raise a ParseError if there is less than 1 arguments" do
    lambda { scope.function_staging_parse([]) }.should( raise_error(Puppet::ParseError))
  end

  it "should raise a ParseError if there is more than 3 arguments" do
    lambda { scope.function_staging_parse(['/etc', 'filename', '.zip', 'error']) }.should( raise_error(Puppet::ParseError))
  end

  it "should raise a ParseError if there is an invalid info request" do
    lambda { scope.function_staging_parse(['/etc', 'sheep', '.zip']) }.should( raise_error(Puppet::ParseError))
  end

  it "should raise a ParseError if 'source' doesn't have a URI path component" do
    lambda { scope.function_staging_parse(['uri:without-path']) }.should( raise_error(Puppet::ParseError, /has no URI 'path' component/))
  end

  it "should return the filename by default" do
    result = scope.function_staging_parse(["/etc/puppet/sample.tar.gz"])
    result.should(eq('sample.tar.gz'))
  end

  it "should return the file basename" do
    result = scope.function_staging_parse(["/etc/puppet/sample.tar.gz", "basename"])
    result.should(eq('sample.tar'))
  end

  it "should return the file basename with custom extensions" do
    result = scope.function_staging_parse(["/etc/puppet/sample.tar.gz", "basename", ".tar.gz"])
    result.should(eq('sample'))
  end

  it "should return the file extname" do
    result = scope.function_staging_parse(["/etc/puppet/sample.tar.gz", "extname"])
    result.should(eq('.gz'))
  end

  it "should return the file parent" do
    result = scope.function_staging_parse(["/etc/puppet/sample.tar.gz", "parent"])
    result.should(eq('/etc/puppet'))
  end
end
staging::deploy { 'sample.tar.gz':
  source => 'puppet:///modules/staging/sample.tar.gz',
  target => '/usr/local',
}
$caller_module_name = 'demo'

class { 'staging':
  path => '/tmp/staging',
}

staging::file { 'sample.tar.gz':
  source => 'puppet:///modules/staging/sample.tar.gz'
}

staging::extract { 'sample.tar.gz':
  target  => '/tmp/staging',
  creates => '/tmp/staging/sample',
  require => Staging::File['sample.tar.gz'],
}

staging::file { 'sample.tar.bz2':
  source => 'puppet:///modules/staging/sample.tar.bz2'
}

staging::extract { 'sample.tar.bz2':
  target  => '/tmp/staging',
  creates => '/tmp/staging/sample-tar-bz2',
  require => Staging::File['sample.tar.bz2'],
}
$caller_module_name = 'demo'

class { 'staging':
  path => '/tmp/staging',
}

staging::file { 'sample':
  source => 'puppet:///modules/staging/sample',
}

staging::file { 'passwd':
  source => '/etc/passwd',
}

staging::file { 'manpage.html':
  source => 'http://curl.haxx.se/docs/manpage.html',
}
include staging
Exec {
  path => '/bin',
}

if scope_defaults('Exec', 'path') {
  notice('good')
}
$file      = '/etc/puppetlabs/foo.bar.tar.gz'
$filename  = staging_parse($file)
$basename  = staging_parse($file, 'basename')
$extname   = staging_parse($file, 'extname')
$parent    = staging_parse($file, 'parent')
$rbasename = staging_parse($file, 'basename', '.tar.gz')

notice($filename)
notice($basename)
notice($extname)
notice($parent)
notice($rbasename)
##2014-11-10 - Supported Release 4.4.0
###Summary
This release has an overhauled readme, new private manifest function, and fixes many future parser bugs.

####Features
- All new shiny README
- New `private()` function for making private manifests (yay!)

####Bugfixes
- Code reuse in `bool2num()` and `zip()`
- Fix many functions to handle `generate()` no longer returning a string on new puppets
- `concat()` no longer modifies the first argument (whoops)
- strict variable support for `getvar()`, `member()`, `values_at`, and `has_interface_with()`
- `to_bytes()` handles PB and EB now
- Fix `tempfile` ruby requirement for `validate_augeas()` and `validate_cmd()`
- Fix `validate_cmd()` for windows
- Correct `validate_string()` docs to reflect non-handling of `undef`
- Fix `file_line` matching on older rubies


##2014-07-15 - Supported Release 4.3.2
###Summary

This release merely updates metadata.json so the module can be uninstalled and
upgraded via the puppet module command.

##2014-07-14 - Supported Release 4.3.1
### Summary
This supported release updates the metadata.json to work around upgrade behavior of the PMT.

#### Bugfixes
- Synchronize metadata.json with PMT-generated metadata to pass checksums

##2014-06-27 - Supported Release 4.3.0
### Summary
This release is the first supported release of the stdlib 4 series. It remains
backwards-compatible with the stdlib 3 series. It adds two new functions, one bugfix, and many testing updates.

#### Features
- New `bool2str()` function
- New `camalcase()` function

#### Bugfixes
- Fix `has_interface_with()` when interfaces fact is nil

##2014-06-04 - Release 4.2.2
### Summary

This release adds PE3.3 support in the metadata and fixes a few tests.

## 2014-05-08 - Release - 4.2.1
### Summary
This release moves a stray symlink that can cause problems.

## 2014-05-08 - Release - 4.2.0
### Summary
This release adds many new functions and fixes, and continues to be backwards compatible with stdlib 3.x

#### Features
- New `base64()` function
- New `deep_merge()` function
- New `delete_undef_values()` function
- New `delete_values()` function
- New `difference()` function
- New `intersection()` function
- New `is_bool()` function
- New `pick_default()` function
- New `union()` function
- New `validate_ipv4_address` function
- New `validate_ipv6_address` function
- Update `ensure_packages()` to take an option hash as a second parameter.
- Update `range()` to take an optional third argument for range step
- Update `validate_slength()` to take an optional third argument for minimum length
- Update `file_line` resource to take `after` and `multiple` attributes

#### Bugfixes
- Correct `is_string`, `is_domain_name`, `is_array`, `is_float`, and `is_function_available` for parsing odd types such as bools and hashes.
- Allow facts.d facts to contain `=` in the value
- Fix `root_home` fact on darwin systems
- Fix `concat()` to work with a second non-array argument
- Fix `floor()` to work with integer strings
- Fix `is_integer()` to return true if passed integer strings
- Fix `is_numeric()` to return true if passed integer strings
- Fix `merge()` to work with empty strings
- Fix `pick()` to raise the correct error type
- Fix `uriescape()` to use the default URI.escape list
- Add/update unit & acceptance tests.


##2014-03-04 - Supported Release - 3.2.1
###Summary
This is a supported release

####Bugfixes
- Fixed `is_integer`/`is_float`/`is_numeric` for checking the value of arithmatic expressions.

####Known bugs
* No known bugs


##### 2013-05-06 - Jeff McCune <jeff@puppetlabs.com> - 4.1.0

 * (#20582) Restore facter\_dot\_d to stdlib for PE users (3b887c8)
 * (maint) Update Gemfile with GEM\_FACTER\_VERSION (f44d535)

##### 2013-05-06 - Alex Cline <acline@us.ibm.com> - 4.1.0

 * Terser method of string to array conversion courtesy of ethooz. (d38bce0)

##### 2013-05-06 - Alex Cline <acline@us.ibm.com> 4.1.0

 * Refactor ensure\_resource expectations (b33cc24)

##### 2013-05-06 - Alex Cline <acline@us.ibm.com> 4.1.0

 * Changed str-to-array conversion and removed abbreviation. (de253db)

##### 2013-05-03 - Alex Cline <acline@us.ibm.com> 4.1.0

 * (#20548) Allow an array of resource titles to be passed into the ensure\_resource function (e08734a)

##### 2013-05-02 - Raphaël Pinson <raphael.pinson@camptocamp.com> - 4.1.0

 * Add a dirname function (2ba9e47)

##### 2013-04-29 - Mark Smith-Guerrero <msmithgu@gmail.com> - 4.1.0

 * (maint) Fix a small typo in hash() description (928036a)

##### 2013-04-12 - Jeff McCune <jeff@puppetlabs.com> - 4.0.2

 * Update user information in gemspec to make the intent of the Gem clear.

##### 2013-04-11 - Jeff McCune <jeff@puppetlabs.com> - 4.0.1

 * Fix README function documentation (ab3e30c)

##### 2013-04-11 - Jeff McCune <jeff@puppetlabs.com> - 4.0.0

 * stdlib 4.0 drops support with Puppet 2.7
 * stdlib 4.0 preserves support with Puppet 3

##### 2013-04-11 - Jeff McCune <jeff@puppetlabs.com> - 4.0.0

 * Add ability to use puppet from git via bundler (9c5805f)

##### 2013-04-10 - Jeff McCune <jeff@puppetlabs.com> - 4.0.0

 * (maint) Make stdlib usable as a Ruby GEM (e81a45e)

##### 2013-04-10 - Erik Dalén <dalen@spotify.com> - 4.0.0

 * Add a count function (f28550e)

##### 2013-03-31 - Amos Shapira <ashapira@atlassian.com> - 4.0.0

 * (#19998) Implement any2array (7a2fb80)

##### 2013-03-29 - Steve Huff <shuff@vecna.org> - 4.0.0

 * (19864) num2bool match fix (8d217f0)

##### 2013-03-20 - Erik Dalén <dalen@spotify.com> - 4.0.0

 * Allow comparisons of Numeric and number as String (ff5dd5d)

##### 2013-03-26 - Richard Soderberg <rsoderberg@mozilla.com> - 4.0.0

 * add suffix function to accompany the prefix function (88a93ac)

##### 2013-03-19 - Kristof Willaert <kristof.willaert@gmail.com> - 4.0.0

 * Add floor function implementation and unit tests (0527341)

##### 2012-04-03 - Eric Shamow <eric@puppetlabs.com> - 4.0.0

 * (#13610) Add is\_function\_available to stdlib (961dcab)

##### 2012-12-17 - Justin Lambert <jlambert@eml.cc> - 4.0.0

 * str2bool should return a boolean if called with a boolean (5d5a4d4)

##### 2012-10-23 - Uwe Stuehler <ustuehler@team.mobile.de> - 4.0.0

 * Fix number of arguments check in flatten() (e80207b)

##### 2013-03-11 - Jeff McCune <jeff@puppetlabs.com> - 4.0.0

 * Add contributing document (96e19d0)

##### 2013-03-04 - Raphaël Pinson <raphael.pinson@camptocamp.com> - 4.0.0

 * Add missing documentation for validate\_augeas and validate\_cmd to README.markdown (a1510a1)

##### 2013-02-14 - Joshua Hoblitt <jhoblitt@cpan.org> - 4.0.0

 * (#19272) Add has\_element() function (95cf3fe)

##### 2013-02-07 - Raphaël Pinson <raphael.pinson@camptocamp.com> - 4.0.0

 * validate\_cmd(): Use Puppet::Util::Execution.execute when available (69248df)

##### 2012-12-06 - Raphaël Pinson <raphink@gmail.com> - 4.0.0

 * Add validate\_augeas function (3a97c23)

##### 2012-12-06 - Raphaël Pinson <raphink@gmail.com> - 4.0.0

 * Add validate\_cmd function (6902cc5)

##### 2013-01-14 - David Schmitt <david@dasz.at> - 4.0.0

 * Add geppetto project definition (b3fc0a3)

##### 2013-01-02 - Jaka Hudoklin <jakahudoklin@gmail.com> - 4.0.0

 * Add getparam function to get defined resource parameters (20e0e07)

##### 2013-01-05 - Jeff McCune <jeff@puppetlabs.com> - 4.0.0

 * (maint) Add Travis CI Support (d082046)

##### 2012-12-04 - Jeff McCune <jeff@puppetlabs.com> - 4.0.0

 * Clarify that stdlib 3 supports Puppet 3 (3a6085f)

##### 2012-11-30 - Erik Dalén <dalen@spotify.com> - 4.0.0

 * maint: style guideline fixes (7742e5f)

##### 2012-11-09 - James Fryman <james@frymanet.com> - 4.0.0

 * puppet-lint cleanup (88acc52)

##### 2012-11-06 - Joe Julian <me@joejulian.name> - 4.0.0

 * Add function, uriescape, to URI.escape strings. Redmine #17459 (fd52b8d)

##### 2012-09-18 - Chad Metcalf <chad@wibidata.com> - 3.2.0

 * Add an ensure\_packages function. (8a8c09e)

##### 2012-11-23 - Erik DalÃƒÂ©n <dalen@spotify.com> - 3.2.0

 * (#17797) min() and max() functions (9954133)

##### 2012-05-23 - Peter Meier <peter.meier@immerda.ch> - 3.2.0

 * (#14670) autorequire a file\_line resource's path (dfcee63)

##### 2012-11-19 - Joshua Harlan Lifton <lifton@puppetlabs.com> - 3.2.0

 * Add join\_keys\_to\_values function (ee0f2b3)

##### 2012-11-17 - Joshua Harlan Lifton <lifton@puppetlabs.com> - 3.2.0

 * Extend delete function for strings and hashes (7322e4d)

##### 2012-08-03 - Gary Larizza <gary@puppetlabs.com> - 3.2.0

 * Add the pick() function (ba6dd13)

##### 2012-03-20 - Wil Cooley <wcooley@pdx.edu> - 3.2.0

 * (#13974) Add predicate functions for interface facts (f819417)

##### 2012-11-06 - Joe Julian <me@joejulian.name> - 3.2.0

 * Add function, uriescape, to URI.escape strings. Redmine #17459 (70f4a0e)

##### 2012-10-25 - Jeff McCune <jeff@puppetlabs.com> - 3.1.1

 * (maint) Fix spec failures resulting from Facter API changes (97f836f)

##### 2012-10-23 - Matthaus Owens <matthaus@puppetlabs.com> - 3.1.0

 * Add PE facts to stdlib (cdf3b05)

##### 2012-08-16 - Jeff McCune <jeff@puppetlabs.com> - 3.0.1

 * Fix accidental removal of facts\_dot\_d.rb in 3.0.0 release

##### 2012-08-16 - Jeff McCune <jeff@puppetlabs.com> - 3.0.0

 * stdlib 3.0 drops support with Puppet 2.6
 * stdlib 3.0 preserves support with Puppet 2.7

##### 2012-08-07 - Dan Bode <dan@puppetlabs.com> - 3.0.0

 * Add function ensure\_resource and defined\_with\_params (ba789de)

##### 2012-07-10 - Hailee Kenney <hailee@puppetlabs.com> - 3.0.0

 * (#2157) Remove facter\_dot\_d for compatibility with external facts (f92574f)

##### 2012-04-10 - Chris Price <chris@puppetlabs.com> - 3.0.0

 * (#13693) moving logic from local spec\_helper to puppetlabs\_spec\_helper (85f96df)

##### 2012-10-25 - Jeff McCune <jeff@puppetlabs.com> - 2.5.1

 * (maint) Fix spec failures resulting from Facter API changes (97f836f)

##### 2012-10-23 - Matthaus Owens <matthaus@puppetlabs.com> - 2.5.0

 * Add PE facts to stdlib (cdf3b05)

##### 2012-08-15 - Dan Bode <dan@puppetlabs.com> - 2.5.0

 * Explicitly load functions used by ensure\_resource (9fc3063)

##### 2012-08-13 - Dan Bode <dan@puppetlabs.com> - 2.5.0

 * Add better docs about duplicate resource failures (97d327a)

##### 2012-08-13 - Dan Bode <dan@puppetlabs.com> - 2.5.0

 * Handle undef for parameter argument (4f8b133)

##### 2012-08-07 - Dan Bode <dan@puppetlabs.com> - 2.5.0

 * Add function ensure\_resource and defined\_with\_params (a0cb8cd)

##### 2012-08-20 - Jeff McCune <jeff@puppetlabs.com> - 2.5.0

 * Disable tests that fail on 2.6.x due to #15912 (c81496e)

##### 2012-08-20 - Jeff McCune <jeff@puppetlabs.com> - 2.5.0

 * (Maint) Fix mis-use of rvalue functions as statements (4492913)

##### 2012-08-20 - Jeff McCune <jeff@puppetlabs.com> - 2.5.0

 * Add .rspec file to repo root (88789e8)

##### 2012-06-07 - Chris Price <chris@puppetlabs.com> - 2.4.0

 * Add support for a 'match' parameter to file\_line (a06c0d8)

##### 2012-08-07 - Erik DalÃƒÂ©n <dalen@spotify.com> - 2.4.0

 * (#15872) Add to\_bytes function (247b69c)

##### 2012-07-19 - Jeff McCune <jeff@puppetlabs.com> - 2.4.0

 * (Maint) use PuppetlabsSpec::PuppetInternals.scope (master) (deafe88)

##### 2012-07-10 - Hailee Kenney <hailee@puppetlabs.com> - 2.4.0

 * (#2157) Make facts\_dot\_d compatible with external facts (5fb0ddc)

##### 2012-03-16 - Steve Traylen <steve.traylen@cern.ch> - 2.4.0

 * (#13205) Rotate array/string randomley based on fqdn, fqdn\_rotate() (fef247b)

##### 2012-05-22 - Peter Meier <peter.meier@immerda.ch> - 2.3.3

 * fix regression in #11017 properly (f0a62c7)

##### 2012-05-10 - Jeff McCune <jeff@puppetlabs.com> - 2.3.3

 * Fix spec tests using the new spec\_helper (7d34333)

##### 2012-05-10 - Puppet Labs <support@puppetlabs.com> - 2.3.2

 * Make file\_line default to ensure => present (1373e70)
 * Memoize file\_line spec instance variables (20aacc5)
 * Fix spec tests using the new spec\_helper (1ebfa5d)
 * (#13595) initialize\_everything\_for\_tests couples modules Puppet ver (3222f35)
 * (#13439) Fix MRI 1.9 issue with spec\_helper (15c5fd1)
 * (#13439) Fix test failures with Puppet 2.6.x (665610b)
 * (#13439) refactor spec helper for compatibility with both puppet 2.7 and master (82194ca)
 * (#13494) Specify the behavior of zero padded strings (61891bb)

##### 2012-03-29 Puppet Labs <support@puppetlabs.com> - 2.1.3

* (#11607) Add Rakefile to enable spec testing
* (#12377) Avoid infinite loop when retrying require json

##### 2012-03-13 Puppet Labs <support@puppetlabs.com> - 2.3.1

* (#13091) Fix LoadError bug with puppet apply and puppet\_vardir fact

##### 2012-03-12 Puppet Labs <support@puppetlabs.com> - 2.3.0

* Add a large number of new Puppet functions
* Backwards compatibility preserved with 2.2.x

##### 2011-12-30 Puppet Labs <support@puppetlabs.com> - 2.2.1

* Documentation only release for the Forge

##### 2011-12-30 Puppet Labs <support@puppetlabs.com> - 2.1.2

* Documentation only release for PE 2.0.x

##### 2011-11-08 Puppet Labs <support@puppetlabs.com> - 2.2.0

* #10285 - Refactor json to use pson instead.
* Maint  - Add watchr autotest script
* Maint  - Make rspec tests work with Puppet 2.6.4
* #9859  - Add root\_home fact and tests

##### 2011-08-18 Puppet Labs <support@puppetlabs.com> - 2.1.1

* Change facts.d paths to match Facter 2.0 paths.
* /etc/facter/facts.d
* /etc/puppetlabs/facter/facts.d

##### 2011-08-17 Puppet Labs <support@puppetlabs.com> - 2.1.0

* Add R.I. Pienaar's facts.d custom facter fact
* facts defined in /etc/facts.d and /etc/puppetlabs/facts.d are
  automatically loaded now.

##### 2011-08-04 Puppet Labs <support@puppetlabs.com> - 2.0.0

* Rename whole\_line to file\_line
* This is an API change and as such motivating a 2.0.0 release according to semver.org.

##### 2011-08-04 Puppet Labs <support@puppetlabs.com> - 1.1.0

* Rename append\_line to whole\_line
* This is an API change and as such motivating a 1.1.0 release.

##### 2011-08-04 Puppet Labs <support@puppetlabs.com> - 1.0.0

* Initial stable release
* Add validate\_array and validate\_string functions
* Make merge() function work with Ruby 1.8.5
* Add hash merging function
* Add has\_key function
* Add loadyaml() function
* Add append\_line native

##### 2011-06-21 Jeff McCune <jeff@puppetlabs.com> - 0.1.7

* Add validate\_hash() and getvar() functions

##### 2011-06-15 Jeff McCune <jeff@puppetlabs.com> - 0.1.6

* Add anchor resource type to provide containment for composite classes

##### 2011-06-03 Jeff McCune <jeff@puppetlabs.com> - 0.1.5

* Add validate\_bool() function to stdlib

##### 0.1.4 2011-05-26 Jeff McCune <jeff@puppetlabs.com>

* Move most stages after main

##### 0.1.3 2011-05-25 Jeff McCune <jeff@puppetlabs.com>

* Add validate\_re() function

##### 0.1.2 2011-05-24 Jeff McCune <jeff@puppetlabs.com>

* Update to add annotated tag

##### 0.1.1 2011-05-24 Jeff McCune <jeff@puppetlabs.com>

* Add stdlib::stages class with a standard set of stages
Checklist (and a short version for the impatient)
=================================================

  * Commits:

    - Make commits of logical units.

    - Check for unnecessary whitespace with "git diff --check" before
      committing.

    - Commit using Unix line endings (check the settings around "crlf" in
      git-config(1)).

    - Do not check in commented out code or unneeded files.

    - The first line of the commit message should be a short
      description (50 characters is the soft limit, excluding ticket
      number(s)), and should skip the full stop.

    - Associate the issue in the message. The first line should include
      the issue number in the form "(#XXXX) Rest of message".

    - The body should provide a meaningful commit message, which:

      - uses the imperative, present tense: "change", not "changed" or
        "changes".

      - includes motivation for the change, and contrasts its
        implementation with the previous behavior.

    - Make sure that you have tests for the bug you are fixing, or
      feature you are adding.

    - Make sure the test suites passes after your commit:
      `bundle exec rspec spec/acceptance` More information on [testing](#Testing) below

    - When introducing a new feature, make sure it is properly
      documented in the README.md

  * Submission:

    * Pre-requisites:

      - Sign the [Contributor License Agreement](https://cla.puppetlabs.com/)

      - Make sure you have a [GitHub account](https://github.com/join)

      - [Create a ticket](http://projects.puppetlabs.com/projects/modules/issues/new), or [watch the ticket](http://projects.puppetlabs.com/projects/modules/issues) you are patching for.

    * Preferred method:

      - Fork the repository on GitHub.

      - Push your changes to a topic branch in your fork of the
        repository. (the format ticket/1234-short_description_of_change is
        usually preferred for this project).

      - Submit a pull request to the repository in the puppetlabs
        organization.

The long version
================

  1.  Make separate commits for logically separate changes.

      Please break your commits down into logically consistent units
      which include new or changed tests relevant to the rest of the
      change.  The goal of doing this is to make the diff easier to
      read for whoever is reviewing your code.  In general, the easier
      your diff is to read, the more likely someone will be happy to
      review it and get it into the code base.

      If you are going to refactor a piece of code, please do so as a
      separate commit from your feature or bug fix changes.

      We also really appreciate changes that include tests to make
      sure the bug is not re-introduced, and that the feature is not
      accidentally broken.

      Describe the technical detail of the change(s).  If your
      description starts to get too long, that is a good sign that you
      probably need to split up your commit into more finely grained
      pieces.

      Commits which plainly describe the things which help
      reviewers check the patch and future developers understand the
      code are much more likely to be merged in with a minimum of
      bike-shedding or requested changes.  Ideally, the commit message
      would include information, and be in a form suitable for
      inclusion in the release notes for the version of Puppet that
      includes them.

      Please also check that you are not introducing any trailing
      whitespace or other "whitespace errors".  You can do this by
      running "git diff --check" on your changes before you commit.

  2.  Sign the Contributor License Agreement

      Before we can accept your changes, we do need a signed Puppet
      Labs Contributor License Agreement (CLA).

      You can access the CLA via the [Contributor License Agreement link](https://cla.puppetlabs.com/)

      If you have any questions about the CLA, please feel free to
      contact Puppet Labs via email at cla-submissions@puppetlabs.com.

  3.  Sending your patches

      To submit your changes via a GitHub pull request, we _highly_
      recommend that you have them on a topic branch, instead of
      directly on "master".
      It makes things much easier to keep track of, especially if
      you decide to work on another thing before your first change
      is merged in.

      GitHub has some pretty good
      [general documentation](http://help.github.com/) on using
      their site.  They also have documentation on
      [creating pull requests](http://help.github.com/send-pull-requests/).

      In general, after pushing your topic branch up to your
      repository on GitHub, you can switch to the branch in the
      GitHub UI and click "Pull Request" towards the top of the page
      in order to open a pull request.


  4.  Update the related GitHub issue.

      If there is a GitHub issue associated with the change you
      submitted, then you should update the ticket to include the
      location of your branch, along with any other commentary you
      may wish to make.

Testing
=======

Getting Started

Our puppet modules provide [`Gemfile`](./Gemfile)s which can tell a ruby
package manager such as [bundler](http://bundler.io/) what Ruby packages,
or Gems, are required to build, develop, and test this software.

Please make sure you have [bundler installed](http://bundler.io/#getting-started)
on your system, then use it to install all dependencies needed for this project,
by running

```shell
% bundle install
Fetching gem metadata from https://rubygems.org/........
Fetching gem metadata from https://rubygems.org/..
Using rake (10.1.0)
Using builder (3.2.2)
Using rspec-system-puppet (2.2.0)
Using serverspec (0.6.3)
Using rspec-system-serverspec (1.0.0)
Using bundler (1.3.5)
Your bundle is complete!
Use `bundle show [gemname]` to see where a bundled gem is installed.
```

NOTE some systems may require you to run this command with sudo.

If you already have those gems installed, make sure they are up-to-date:

```shell
% bundle update
```

With all dependencies in place and up-to-date we can now run the tests:

```shell
% rake spec
```

This will execute all the [rspec tests](http://rspec-puppet.com/) tests
under [spec/defines](./spec/defines), [spec/classes](./spec/classes),
and so on. rspec tests may have the same kind of dependencies as the
module they are testing. While the module defines in its [Modulefile](./Modulefile),
rspec tests define them in [.fixtures.yml](./fixtures.yml).

Some puppet modules also come with [beaker](https://github.com/puppetlabs/beaker)
tests. These tests spin up a virtual machine under
[VirtualBox](https://www.virtualbox.org/)) with, controlling it with
[Vagrant](http://www.vagrantup.com/) to actually simulate scripted test
scenarios. In order to run these, you will need both of those tools
installed on your system.

You can run them by issuing the following command

```shell
% rake spec_clean
% rspec spec/acceptance
```

This will now download a pre-fabricated image configured in the [default node-set](./spec/acceptance/nodesets/default.yml),
install puppet, copy this module and install its dependencies per [spec/spec_helper_acceptance.rb](./spec/spec_helper_acceptance.rb)
and then run all the tests under [spec/acceptance](./spec/acceptance).

Writing Tests

XXX getting started writing tests.

If you have commit access to the repository
===========================================

Even if you have commit access to the repository, you will still need to
go through the process above, and have someone else review and merge
in your changes.  The rule is that all changes must be reviewed by a
developer on the project (that did not write the code) to ensure that
all changes go through a code review process.

Having someone other than the author of the topic branch recorded as
performing the merge is the record that they performed the code
review.


Additional Resources
====================

* [Getting additional help](http://projects.puppetlabs.com/projects/puppet/wiki/Getting_Help)

* [Writing tests](http://projects.puppetlabs.com/projects/puppet/wiki/Development_Writing_Tests)

* [Patchwork](https://patchwork.puppetlabs.com)

* [Contributor License Agreement](https://projects.puppetlabs.com/contributor_licenses/sign)

* [General GitHub documentation](http://help.github.com/)

* [GitHub pull request documentation](http://help.github.com/send-pull-requests/)

source ENV['GEM_SOURCE'] || 'https://rubygems.org'

def location_for(place, fake_version = nil)
  if place =~ /^(git[:@][^#]*)#(.*)/
    [fake_version, { :git => $1, :branch => $2, :require => false }].compact
  elsif place =~ /^file:\/\/(.*)/
    ['>= 0', { :path => File.expand_path($1), :require => false }]
  else
    [place, { :require => false }]
  end
end

group :development, :unit_tests do
  gem 'rake', '~> 10.1.0',       :require => false
  gem 'rspec-puppet',            :require => false
  gem 'puppetlabs_spec_helper',  :require => false
  gem 'puppet-lint',             :require => false
  gem 'pry',                     :require => false
  gem 'simplecov',               :require => false
end

group :system_tests do
  gem 'beaker-rspec',            :require => false
  gem 'serverspec',              :require => false
end

ENV['GEM_PUPPET_VERSION'] ||= ENV['PUPPET_GEM_VERSION']
puppetversion = ENV['GEM_PUPPET_VERSION']
if puppetversion
  gem 'puppet', *location_for(puppetversion)
else
  gem 'puppet', :require => false
end

# vim:ft=ruby
Copyright (C) 2011 Puppet Labs Inc

and some parts:

Copyright (C) 2011 Krzysztof Wilczynski

Puppet Labs can be contacted at: info@puppetlabs.com

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
#stdlib

[![Build Status](https://travis-ci.org/puppetlabs/puppetlabs-stdlib.png?branch=master)](https://travis-ci.org/puppetlabs/puppetlabs-stdlib)

####Table of Contents

1. [Overview](#overview)
2. [Module Description - What the module does and why it is useful](#module-description)
3. [Setup - The basics of getting started with stdlib](#setup)
4. [Usage - Configuration options and additional functionality](#usage)
5. [Reference - An under-the-hood peek at what the module is doing and how](#reference)
5. [Limitations - OS compatibility, etc.](#limitations)
6. [Development - Guide for contributing to the module](#development)

##Overview

Adds a standard library of resources for Puppet modules.    

##Module Description

This module provides a standard library of resources for the development of Puppet
modules. Puppet modules make heavy use of this standard library. The stdlib module adds the following resources to Puppet:

 * Stages
 * Facts
 * Functions
 * Defined resource types
 * Types
 * Providers

##Setup

Installing the stdlib module adds the functions, facts, and resources of this standard library to Puppet. 

##Usage

After you've installed stdlib, all of its functions, facts, and resources are available for module use or development. 

If you want to use a standardized set of run stages for Puppet, `include stdlib` in your manifest. 

##Reference

### Classes 

#### Public Classes

* `stdlib`: Most of stdlib's features are automatically loaded by Puppet. To use standardized run stages in Puppet, declare this class in your manifest with `include stdlib`.

  When declared, stdlib declares all other classes in the module. The only other class currently included in the module is `stdlib::stages`.

  The stdlib class has no parameters.

#### Private Classes

* `stdlib::stages`: This class manages a standard set of run stages for Puppet. It is managed by the stdlib class and should not be declared independently.

  The `stdlib::stages` class declares various run stages for deploying infrastructure, language runtimes, and application layers. The high level stages are (in order):

  * setup
  * main
  * runtime
  * setup_infra
  * deploy_infra
  * setup_app
  * deploy_app
  * deploy

  Sample usage:

  ```
  node default {
    include stdlib
    class { java: stage => 'runtime' }
  }
  ```

### Functions

* `abs`: Returns the absolute value of a number; for example, '-34.56' becomes '34.56'. Takes a single integer and float value as an argument. *Type*: rvalue

* `any2array`: This converts any object to an array containing that object. Empty argument lists are converted to an empty array. Arrays are left untouched. Hashes are converted to arrays of alternating keys and values. *Type*: rvalue

* `base64`: Converts a string to and from base64 encoding.
Requires an action ('encode', 'decode') and either a plain or base64-encoded
string. *Type*: rvalue

* `bool2num`: Converts a boolean to a number. Converts values:
  * 'false', 'f', '0', 'n', and 'no' to 0.
  * 'true', 't', '1', 'y', and 'yes' to 1.
  Requires a single boolean or string as an input. *Type*: rvalue

* `capitalize`: Capitalizes the first letter of a string or array of strings.
Requires either a single string or an array as an input. *Type*: rvalue

* `chomp`: Removes the record separator from the end of a string or an array of
strings; for example, 'hello\n' becomes 'hello'. Requires a single string or array as an input. *Type*: rvalue

* `chop`: Returns a new string with the last character removed. If the string ends with '\r\n', both characters are removed. Applying `chop` to an empty string returns an empty string. If you want to merely remove record separators, then you should use the `chomp` function. Requires a string or an array of strings as input. *Type*: rvalue

* `concat`: Appends the contents of array 2 onto array 1. For example, `concat(['1','2','3'],'4')` results in: ['1','2','3','4']. *Type*: rvalue

* `count`: Takes an array as first argument and an optional second argument. Count the number of elements in array that matches second argument. If called with only an array, it counts the number of elements that are **not** nil/undef. *Type*: rvalue

* `defined_with_params`: Takes a resource reference and an optional hash of attributes. Returns 'true' if a resource with the specified attributes has already been added to the catalog. Returns 'false' otherwise.

  ```
  user { 'dan':
    ensure => present,
  }

  if ! defined_with_params(User[dan], {'ensure' => 'present' }) {
    user { 'dan': ensure => present, }
  }
  ```
  
  *Type*: rvalue

* `delete`: Deletes all instances of a given element from an array, substring from a
string, or key from a hash. For example, `delete(['a','b','c','b'], 'b')` returns ['a','c']; `delete('abracadabra', 'bra')` returns 'acada'. *Type*: rvalue

* `delete_at`: Deletes a determined indexed value from an array. For example, `delete_at(['a','b','c'], 1)` returns ['a','c']. *Type*: rvalue

* `delete_values`: Deletes all instances of a given value from a hash. For example, `delete_values({'a'=>'A','b'=>'B','c'=>'C','B'=>'D'}, 'B')` returns {'a'=>'A','c'=>'C','B'=>'D'} *Type*: rvalue

* `delete_undef_values`: Deletes all instances of the undef value from an array or hash. For example, `$hash = delete_undef_values({a=>'A', b=>'', c=>undef, d => false})` returns {a => 'A', b => '', d => false}. *Type*: rvalue

* `difference`: Returns the difference between two arrays.
The returned array is a copy of the original array, removing any items that
also appear in the second array. For example, `difference(["a","b","c"],["b","c","d"])` returns ["a"].

* `dirname`: Returns the `dirname` of a path. For example, `dirname('/path/to/a/file.ext')` returns '/path/to/a'.

* `downcase`: Converts the case of a string or of all strings in an array to lowercase. *Type*: rvalue

* `empty`: Returns 'true' if the variable is empty. *Type*: rvalue

* `ensure_packages`: Takes a list of packages and only installs them if they don't already exist. It optionally takes a hash as a second parameter to be passed as the third argument to the `ensure_resource()` function. *Type*: statement

* `ensure_resource`: Takes a resource type, title, and a list of attributes that describe a resource.

  ```
  user { 'dan':
    ensure => present,
  }
  ```

  This example only creates the resource if it does not already exist:

    `ensure_resource('user', 'dan', {'ensure' => 'present' })`

  If the resource already exists, but does not match the specified parameters, this function attempts to recreate the resource, leading to a duplicate resource definition error.

  An array of resources can also be passed in, and each will be created with the type and parameters specified if it doesn't already exist.

  `ensure_resource('user', ['dan','alex'], {'ensure' => 'present'})`

  *Type*: statement

* `file_line`: This resource ensures that a given line is contained within a file. You can also use match to replace existing lines.

  *Example:*
  
  ```
  file_line { 'sudo_rule':
    path => '/etc/sudoers',
    line => '%sudo ALL=(ALL) ALL',
  }

  file_line { 'change_mount':
    path  => '/etc/fstab',
    line  => '10.0.0.1:/vol/data /opt/data nfs defaults 0 0',
    match => '^172.16.17.2:/vol/old',
  }
  ```
  
  *Type*: resource

* `flatten`: This function flattens any deeply nested arrays and returns a single flat array as a result. For example, `flatten(['a', ['b', ['c']]])` returns ['a','b','c']. *Type*: rvalue

* `floor`: Returns the largest integer less than or equal to the argument.
Takes a single numeric value as an argument. *Type*: rvalue

* `fqdn_rotate`: Rotates an array a random number of times based on a node's fqdn. *Type*: rvalue

* `get_module_path`: Returns the absolute path of the specified module for the current environment.

  `$module_path = get_module_path('stdlib')`

  *Type*: rvalue

* `getparam`: Takes a resource reference and the name of the parameter and
returns the value of the resource's parameter. For example, the following code returns 'param_value'.

  *Example:*

  ```
  define example_resource($param) {
  }

  example_resource { "example_resource_instance":
    param => "param_value"
  }

  getparam(Example_resource["example_resource_instance"], "param")
  ```

  *Type*: rvalue

* `getvar`: Lookup a variable in a remote namespace.

  For example:

  ```
  $foo = getvar('site::data::foo')
  # Equivalent to $foo = $site::data::foo
  ```

  This is useful if the namespace itself is stored in a string:

  ```
  $datalocation = 'site::data'
  $bar = getvar("${datalocation}::bar")
  # Equivalent to $bar = $site::data::bar
  ```

  *Type*: rvalue

* `grep`: This function searches through an array and returns any elements that match the provided regular expression. For example, `grep(['aaa','bbb','ccc','aaaddd'], 'aaa')` returns ['aaa','aaaddd']. *Type*: rvalue

* `has_interface_with`: Returns boolean based on kind and value:
  * macaddress
  * netmask
  * ipaddress
  * network

  *Examples:*

  ```
  has_interface_with("macaddress", "x:x:x:x:x:x")
  has_interface_with("ipaddress", "127.0.0.1")    => true
  ```
    
  If no kind is given, then the presence of the interface is checked:

  ```
  has_interface_with("lo")                        => true
  ```

  *Type*: rvalue

* `has_ip_address`: Returns true if the client has the requested IP address on some interface. This function iterates through the `interfaces` fact and checks the `ipaddress_IFACE` facts, performing a simple string comparison. *Type*: rvalue

* `has_ip_network`: Returns true if the client has an IP address within the requested network. This function iterates through the 'interfaces' fact and checks the 'network_IFACE' facts, performing a simple string comparision. *Type*: rvalue

* `has_key`: Determine if a hash has a certain key value.

  *Example*:

  ```
  $my_hash = {'key_one' => 'value_one'}
  if has_key($my_hash, 'key_two') {
    notice('we will not reach here')
  }
  if has_key($my_hash, 'key_one') {
    notice('this will be printed')
  }
  ```
  
  *Type*: rvalue

* `hash`: This function converts an array into a hash. For example, `hash(['a',1,'b',2,'c',3])` returns {'a'=>1,'b'=>2,'c'=>3}. *Type*: rvalue

* `intersection`: This function returns an array an intersection of two. For example, `intersection(["a","b","c"],["b","c","d"])` returns ["b","c"].

* `is_array`: Returns 'true' if the variable passed to this function is an array. *Type*: rvalue

* `is_bool`: Returns 'true' if the variable passed to this function is a boolean. *Type*: rvalue

* `is_domain_name`: Returns 'true' if the string passed to this function is a syntactically correct domain name. *Type*: rvalue

* `is_float`: Returns 'true' if the variable passed to this function is a float. *Type*: rvalue

* `is_function_available`: This function accepts a string as an argument and determines whether the Puppet runtime has access to a function by that name. It returns 'true' if the function exists, 'false' if not. *Type*: rvalue

* `is_hash`: Returns 'true' if the variable passed to this function is a hash. *Type*: rvalue

* `is_integer`: Returns 'true' if the variable returned to this string is an integer. *Type*: rvalue

* `is_ip_address`: Returns 'true' if the string passed to this function is a valid IP address. *Type*: rvalue

* `is_mac_address`: Returns 'true' if the string passed to this function is a valid MAC address. *Type*: rvalue

* `is_numeric`: Returns 'true' if the variable passed to this function is a number. *Type*: rvalue

* `is_string`: Returns 'true' if the variable passed to this function is a string. *Type*: rvalue

* `join`: This function joins an array into a string using a separator. For example, `join(['a','b','c'], ",")` results in: "a,b,c". *Type*: rvalue

* `join_keys_to_values`: This function joins each key of a hash to that key's corresponding value with a separator. Keys and values are cast to strings. The return value is an array in which each element is one joined key/value pair. For example, `join_keys_to_values({'a'=>1,'b'=>2}, " is ")` results in ["a is 1","b is 2"]. *Type*: rvalue

* `keys`: Returns the keys of a hash as an array. *Type*: rvalue

* `loadyaml`: Load a YAML file containing an array, string, or hash, and return the data in the corresponding native data type. For example:

  ```
  $myhash = loadyaml('/etc/puppet/data/myhash.yaml')
  ```

  *Type*: rvalue

* `lstrip`: Strips leading spaces to the left of a string. *Type*: rvalue

* `max`: Returns the highest value of all arguments. Requires at least one argument. *Type*: rvalue

* `member`: This function determines if a variable is a member of an array. For example, `member(['a','b'], 'b')` returns 'true', while `member(['a','b'], 'c')`  returns 'false'. *Type*: rvalue

* `merge`: Merges two or more hashes together and returns the resulting hash.

  *Example*:
  
  ```
  $hash1 = {'one' => 1, 'two' => 2}
  $hash2 = {'two' => 'dos', 'three' => 'tres'}
  $merged_hash = merge($hash1, $hash2)
  # The resulting hash is equivalent to:
  # $merged_hash =  {'one' => 1, 'two' => 'dos', 'three' => 'tres'}
  ```
  
  When there is a duplicate key, the key in the rightmost hash "wins." *Type*: rvalue

* `min`: Returns the lowest value of all arguments. Requires at least one argument. *Type*: rvalue

* `num2bool`: This function converts a number or a string representation of a number into a true boolean. Zero or anything non-numeric becomes 'false'. Numbers greater than 0 become 'true'. *Type*: rvalue

* `parsejson`: This function accepts JSON as a string and converts into the correct Puppet structure. *Type*: rvalue

* `parseyaml`: This function accepts YAML as a string and converts it into the correct Puppet structure. *Type*: rvalue

* `pick`: From a list of values, returns the first value that is not undefined or an empty string. Takes any number of arguments, and raises an error if all values are undefined or empty.

  ```
  $real_jenkins_version = pick($::jenkins_version, '1.449')
  ```
  
 *Type*: rvalue

* `prefix`: This function applies a prefix to all elements in an array. For example, `prefix(['a','b','c'], 'p')` returns ['pa','pb','pc']. *Type*: rvalue


* `private`: This function sets the current class or definition as private.
Calling the class or definition from outside the current module will fail. For example, `private()` called in class `foo::bar` outputs the following message if class is called from outside module `foo`:

  ```
  Class foo::bar is private
  ```
  
  You can specify the error message you want to use:
  
  ```
  private("You're not supposed to do that!")
  ```

  *Type*: statement

* `range`: When given range in the form of '(start, stop)', `range` extrapolates a range as an array. For example, `range("0", "9")` returns [0,1,2,3,4,5,6,7,8,9]. Zero-padded strings are converted to integers automatically, so `range("00", "09")` returns [0,1,2,3,4,5,6,7,8,9].

  Non-integer strings are accepted; `range("a", "c")` returns ["a","b","c"], and `range("host01", "host10")` returns ["host01", "host02", ..., "host09", "host10"]. 
  
  *Type*: rvalue

* `reject`: This function searches through an array and rejects all elements that match the provided regular expression. For example, `reject(['aaa','bbb','ccc','aaaddd'], 'aaa')` returns ['bbb','ccc']. *Type*: rvalue

* `reverse`: Reverses the order of a string or array. *Type*: rvalue

* `rstrip`: Strips leading spaces to the right of the string.*Type*: rvalue

* `shuffle`: Randomizes the order of a string or array elements. *Type*: rvalue

* `size`: Returns the number of elements in a string or array. *Type*: rvalue

* `sort`: Sorts strings and arrays lexically. *Type*: rvalue

* `squeeze`: Returns a new string where runs of the same character that occur in this set are replaced by a single character. *Type*: rvalue

* `str2bool`: This converts a string to a boolean. This attempts to convert strings that contain values such as '1', 't', 'y', and 'yes' to 'true' and strings that contain values such as '0', 'f', 'n', and 'no' to 'false'. *Type*: rvalue

* `str2saltedsha512`: This converts a string to a salted-SHA512 password hash, used for OS X versions >= 10.7. Given any string, this function returns a hex version of a salted-SHA512 password hash, which can be inserted into your Puppet
manifests as a valid password attribute. *Type*: rvalue

* `strftime`: This function returns formatted time. For example,  `strftime("%s")` returns the time since epoch, and `strftime("%Y=%m-%d")` returns the date. *Type*: rvalue

  *Format:*
  
    * `%a`: The abbreviated weekday name ('Sun')
    * `%A`: The  full  weekday  name ('Sunday')
    * `%b`: The abbreviated month name ('Jan')
    * `%B`: The  full  month  name ('January')
    * `%c`: The preferred local date and time representation
    * `%C`: Century (20 in 2009)
    * `%d`: Day of the month (01..31)
    * `%D`: Date (%m/%d/%y)
    * `%e`: Day of the month, blank-padded ( 1..31)
    * `%F`: Equivalent to %Y-%m-%d (the ISO 8601 date format)
    * `%h`: Equivalent to %b
    * `%H`: Hour of the day, 24-hour clock (00..23)
    * `%I`: Hour of the day, 12-hour clock (01..12)
    * `%j`: Day of the year (001..366)
    * `%k`: Hour, 24-hour clock, blank-padded ( 0..23)
    * `%l`: Hour, 12-hour clock, blank-padded ( 0..12)
    * `%L`: Millisecond of the second (000..999)
    * `%m`: Month of the year (01..12)
    * `%M`: Minute of the hour (00..59)
    * `%n`: Newline (\n)
    * `%N`: Fractional seconds digits, default is 9 digits (nanosecond)
      * `%3N`: Millisecond (3 digits)
      * `%6N`: Microsecond (6 digits)
      * `%9N`: Nanosecond (9 digits)
    * `%p`: Meridian indicator ('AM'  or  'PM')
    * `%P`: Meridian indicator ('am'  or  'pm')
    * `%r`: Time, 12-hour (same as %I:%M:%S %p)
    * `%R`: Time, 24-hour (%H:%M)
    * `%s`: Number of seconds since 1970-01-01 00:00:00 UTC.
    * `%S`: Second of the minute (00..60)
    * `%t`: Tab character (	)
    * `%T`: Time, 24-hour (%H:%M:%S)
    * `%u`: Day of the week as a decimal, Monday being 1. (1..7)
    * `%U`: Week  number  of the current year, starting with the first Sunday as the first day of the first week (00..53)
    * `%v`: VMS date (%e-%b-%Y)
    * `%V`: Week number of year according to ISO 8601 (01..53)
    * `%W`: Week  number of the current year, starting with the first Monday as the first day of the first week (00..53)
    * `%w`: Day of the week (Sunday is 0, 0..6)
    * `%x`: Preferred representation for the date alone, no time
    * `%X`: Preferred representation for the time alone, no date
    * `%y`: Year without a century (00..99)
    * `%Y`: Year with century
    * `%z`: Time zone as  hour offset from UTC (e.g. +0900)
    * `%Z`: Time zone name
    * `%%`: Literal '%' character


* `strip`: This function removes leading and trailing whitespace from a string or from every string inside an array. For example, `strip("    aaa   ")` results in "aaa". *Type*: rvalue

* `suffix`: This function applies a suffix to all elements in an array. For example, `suffix(['a','b','c'], 'p')` returns ['ap','bp','cp']. *Type*: rvalue

* `swapcase`: This function swaps the existing case of a string. For example, `swapcase("aBcD")` results in "AbCd". *Type*: rvalue

* `time`: This function returns the current time since epoch as an integer. For example, `time()` returns something like '1311972653'. *Type*: rvalue

* `to_bytes`: Converts the argument into bytes, for example 4 kB becomes 4096.
Takes a single string value as an argument. *Type*: rvalue

* `type`: Returns the type when passed a variable. Type can be a string, array, hash, float, integer, or boolean. *Type*: rvalue

* `union`: This function returns a union of two arrays. For example, `union(["a","b","c"],["b","c","d"])` returns ["a","b","c","d"].

* `unique`: This function removes duplicates from strings and arrays. For example, `unique("aabbcc")` returns 'abc'.

You can also use this with arrays. For example, `unique(["a","a","b","b","c","c"])` returns ["a","b","c"]. *Type*: rvalue

* `upcase`: Converts a string or an array of strings to uppercase. For example, `upcase("abcd")` returns 'ABCD'. *Type*: rvalue

* `uriescape`: Urlencodes a string or array of strings. Requires either a single string or an array as an input. *Type*: rvalue

* `validate_absolute_path`: Validate that the string represents an absolute path in the filesystem. This function works for Windows and Unix-style paths.
  The following values will pass:

  ```
  $my_path = "C:/Program Files (x86)/Puppet Labs/Puppet"
  validate_absolute_path($my_path)
  $my_path2 = "/var/lib/puppet"
  validate_absolute_path($my_path2)
  ```

  The following values will fail, causing compilation to abort:

  ```
  validate_absolute_path(true)
  validate_absolute_path([ 'var/lib/puppet', '/var/foo' ])
  validate_absolute_path([ '/var/lib/puppet', 'var/foo' ])
  $undefined = undef
  validate_absolute_path($undefined)
  ```
  
  *Type*: statement

* `validate_array`: Validate that all passed values are array data structures. Abort catalog compilation if any value fails this check. 

  The following values will pass:

  ```
  $my_array = [ 'one', 'two' ]
  validate_array($my_array)
  ```

  The following values will fail, causing compilation to abort:

  ```
  validate_array(true)
  validate_array('some_string')
  $undefined = undef
  validate_array($undefined)
  ```

  *Type*: statement

* `validate_augeas`: Performs validation of a string using an Augeas lens.
The first argument of this function should be the string to test, and the second argument should be the name of the Augeas lens to use. If Augeas fails to parse the string with the lens, the compilation aborts with a parse error.

  A third optional argument lists paths which should **not** be found in the file. The `$file` variable points to the location of the temporary file being tested in the Augeas tree.

  For example, to make sure your passwd content never contains user `foo`:

  ```
  validate_augeas($passwdcontent, 'Passwd.lns', ['$file/foo'])
  ```
  
  To ensure that no users use the '/bin/barsh' shell:

  ```
  validate_augeas($passwdcontent, 'Passwd.lns', ['$file/*[shell="/bin/barsh"]']
  ```
  
  You can pass a fourth argument as the error message raised and shown to the user:

  ```
  validate_augeas($sudoerscontent, 'Sudoers.lns', [], 'Failed to validate sudoers content with Augeas')
  ```

  *Type*: statement

* `validate_bool`: Validate that all passed values are either true or false. Abort catalog compilation if any value fails this check.

  The following values will pass:
  
  ```
  $iamtrue = true
  validate_bool(true)
  validate_bool(true, true, false, $iamtrue)
  ```
  
  The following values will fail, causing compilation to abort:

  ```
  $some_array = [ true ]
  validate_bool("false")
  validate_bool("true")
  validate_bool($some_array)
  ```

  *Type*: statement

* `validate_cmd`: Performs validation of a string with an external command. The first argument of this function should be the string to test, and the second argument should be the path to a test command taking a file as last argument. If the command, launched against a tempfile containing the passed string, returns a non-null value, compilation aborts with a parse error.

  You can pass a third argument as the error message raised and shown to the user:

  ```
  validate_cmd($sudoerscontent, '/usr/sbin/visudo -c -f', 'Visudo failed to validate sudoers content')
  ```
  
  *Type*: statement

* `validate_hash`: Validates that all passed values are hash data structures. Abort catalog compilation if any value fails this check.

  The following values will pass:

  ```
  $my_hash = { 'one' => 'two' }
  validate_hash($my_hash)
  ```

  The following values will fail, causing compilation to abort:

  ```
  validate_hash(true)
  validate_hash('some_string')
  $undefined = undef
  validate_hash($undefined)
  ```
  
  *Type*: statement

* `validate_re`: Performs simple validation of a string against one or more regular expressions. The first argument of this function should be the string to
test, and the second argument should be a stringified regular expression
(without the // delimiters) or an array of regular expressions. If none
of the regular expressions match the string passed in, compilation aborts with a parse error.

  You can pass a third argument as the error message raised and shown to the user.

  The following strings validate against the regular expressions:

  ```
  validate_re('one', '^one$')
  validate_re('one', [ '^one', '^two' ])
  ```

  The following string fails to validate, causing compilation to abort:

  ```
  validate_re('one', [ '^two', '^three' ])
  ```

  To set the error message: 
  
  ```
  validate_re($::puppetversion, '^2.7', 'The $puppetversion fact value does not match 2.7')
  ```

  *Type*: statement

* `validate_slength`: Validates that the first argument is a string (or an array of strings), and is less than or equal to the length of the second argument. It fails if the first argument is not a string or array of strings, or if arg 2 is not convertable to a number.

  The following values pass:
  
  ```
  validate_slength("discombobulate",17)
  validate_slength(["discombobulate","moo"],17)
  ```
  
  The following values fail:

  ```
  validate_slength("discombobulate",1)
  validate_slength(["discombobulate","thermometer"],5)
  ```
  
  *Type*: statement

* `validate_string`: Validates that all passed values are string data structures. Aborts catalog compilation if any value fails this check.

  The following values pass:

  ```
  $my_string = "one two"
  validate_string($my_string, 'three')
  ```

  The following values fail, causing compilation to abort:

  ```
  validate_string(true)
  validate_string([ 'some', 'array' ])
  $undefined = undef
  validate_string($undefined)
  ```

  *Type*: statement

* `values`: When given a hash, this function returns the values of that hash.

  *Examples:*

  ```
  $hash = {
    'a' => 1,
    'b' => 2,
    'c' => 3,
  }
  values($hash)
  ```

  The example above returns [1,2,3].

  *Type*: rvalue

* `values_at`: Finds value inside an array based on location. The first argument is the array you want to analyze, and the second element can be a combination of:

  * A single numeric index
  * A range in the form of 'start-stop' (eg. 4-9)
  * An array combining the above

  For example, `values_at(['a','b','c'], 2)` returns ['c']; `values_at(['a','b','c'], ["0-1"])` returns ['a','b']; and `values_at(['a','b','c','d','e'], [0, "2-3"])` returns ['a','c','d'].

  *Type*: rvalue

* `zip`: Takes one element from first array and merges corresponding elements from second array. This generates a sequence of n-element arrays, where n is one more than the count of arguments. For example, `zip(['1','2','3'],['4','5','6'])` results in ["1", "4"], ["2", "5"], ["3", "6"]. *Type*: rvalue

##Limitations

###Version Compatibility

Versions | Puppet 2.6 | Puppet 2.7 | Puppet 3.x | Puppet 4.x | 
:---------------|:-----:|:---:|:---:|:----:
**stdlib 2.x**  | **yes** | **yes** | no | no
**stdlib 3.x**  | no    | **yes**  | **yes** | no
**stdlib 4.x**  | no    | **yes**  | **yes** | no
**stdlib 5.x**  | no    | no  | **yes**  | **yes**

**stdlib 5.x**: When released, stdlib 5.x will drop support for Puppet 2.7.x. Please see [this discussion](https://github.com/puppetlabs/puppetlabs-stdlib/pull/176#issuecomment-30251414).

##Development

Puppet Labs modules on the Puppet Forge are open projects, and community contributions are essential for keeping them great. We can’t access the huge number of platforms and myriad of hardware, software, and deployment configurations that Puppet is intended to serve.

We want to keep it as easy as possible to contribute changes so that our modules work in your environment. There are a few guidelines that we need contributors to follow so that we can have a chance of keeping on top of things.

You can read the complete module contribution guide on the [Puppet Labs wiki](http://projects.puppetlabs.com/projects/module-site/wiki/Module_contributing).

To report or research a bug with any part of this module, please go to
[http://tickets.puppetlabs.com/browse/PUP](http://tickets.puppetlabs.com/browse/PUP).

##Contributors

The list of contributors can be found at: https://github.com/puppetlabs/puppetlabs-stdlib/graphs/contributors




Puppet Specific Facts
=====================

Facter is meant to stand alone and apart from Puppet.  However, Facter often
runs inside Puppet and all custom facts included in the stdlib module will
almost always be evaluated in the context of Puppet and Facter working
together.

Still, we don't want to write custom facts that blow up in the users face if
Puppet is not loaded in memory.  This is often the case if the user runs
`facter` without also supplying the `--puppet` flag.

Ah! But Jeff, the custom fact won't be in the `$LOAD_PATH` unless the user
supplies `--facter`! You might say...

Not (always) true I say!  If the user happens to have a CWD of
`<modulepath>/stdlib/lib` then the facts will automatically be evaluated and
blow up.

In any event, it's pretty easy to write a fact that has no value if Puppet is
not loaded.  Simply do it like this:

    Facter.add(:node_vardir) do
      setcode do
        # This will be nil if Puppet is not available.
        Facter::Util::PuppetSettings.with_puppet do
          Puppet[:vardir]
        end
      end
    end

The `Facter::Util::PuppetSettings.with_puppet` method accepts a block and
yields to it only if the Puppet library is loaded.  If the Puppet library is
not loaded, then the method silently returns `nil` which Facter interprets as
an undefined fact value.  The net effect is that the fact won't be set.
NOTE
====

This project's specs depend on puppet core, and thus they require the
`puppetlabs_spec_helper` project.  For more information please see the README
in that project, which can be found here: [puppetlabs spec
helper](https://github.com/puppetlabs/puppetlabs_spec_helper)
# Contributing to this module #

 * Work in a topic branch
 * Submit a github pull request
 * Address any comments / feeback
 * Merge into master using --no-ff

# Releasing this module #

 * This module adheres to http://semver.org/
 * Look for API breaking changes using git diff vX.Y.Z..master
   * If no API breaking changes, the minor version may be bumped.
   * If there are API breaking changes, the major version must be bumped.
   * If there are only small minor changes, the patch version may be bumped.
 * Update the CHANGELOG
 * Update the Modulefile
 * Commit these changes with a message along the lines of "Update CHANGELOG and
   Modulefile for release"
 * Create an annotated tag with git tag -a vX.Y.Z -m 'version X.Y.Z' (NOTE the
   leading v as per semver.org)
 * Push the tag with git push origin --tags
 * Build a new package with puppet-module or the rake build task if it exists
 * Publish the new package to the forge
 * Bonus points for an announcement to puppet-users.
require 'rubygems'
require 'puppetlabs_spec_helper/rake_tasks'
require 'puppet-lint/tasks/puppet-lint'
PuppetLint.configuration.send('disable_80chars')
PuppetLint.configuration.ignore_paths = ["spec/**/*.pp", "pkg/**/*.pp"]

desc "Validate manifests, templates, and ruby files in lib."
task :validate do
  Dir['manifests/**/*.pp'].each do |manifest|
    sh "puppet parser validate --noop #{manifest}"
  end
  Dir['lib/**/*.rb'].each do |lib_file|
    sh "ruby -c #{lib_file}"
  end
  Dir['templates/**/*.erb'].each do |template|
    sh "erb -P -x -T '-' #{template} | ruby -c"
  end
end
{
  "CHANGELOG.md": "f6f72416f5eca4c5a1bb637133b370ce",
  "CONTRIBUTING.md": "d911815dd7d0d90b90bb35382a6e3298",
  "Gemfile": "79b9a1e16b5bd1d4224109e197591894",
  "LICENSE": "38a048b9d82e713d4e1b2573e370a756",
  "README.markdown": "82cb9399cc2913f1cc6bc9efd3551228",
  "README_DEVELOPER.markdown": "220a8b28521b5c5d2ea87c4ddb511165",
  "README_SPECS.markdown": "82bb4c6abbb711f40778b162ec0070c1",
  "RELEASE_PROCESS.markdown": "94b92bc99ac4106ba1a74d5c04e520f9",
  "Rakefile": "dfa334598bfd087adf11533a72d71106",
  "lib/facter/facter_dot_d.rb": "1f1fcf1bde3443e42a445d3573602304",
  "lib/facter/pe_version.rb": "4a9353952963b011759f3e6652a10da5",
  "lib/facter/puppet_vardir.rb": "c7ddc97e8a84ded3dd93baa5b9b3283d",
  "lib/facter/root_home.rb": "d9c8276acdceb7340d95f60c36dcdcc5",
  "lib/facter/util/puppet_settings.rb": "9f1d2593d0ae56bfca89d4b9266aeee1",
  "lib/puppet/parser/functions/abs.rb": "32161bd0435fdfc2aec2fc559d2b454b",
  "lib/puppet/parser/functions/any2array.rb": "a81e71d6b67a551d38770ba9a1948a75",
  "lib/puppet/parser/functions/base64.rb": "ae25adf92295df67ebd9edfabc9ecdd6",
  "lib/puppet/parser/functions/bool2num.rb": "f953f5fc094c2ae3908a72d8840ba291",
  "lib/puppet/parser/functions/bool2str.rb": "34497af8db94754542b9d4cfacc8a27f",
  "lib/puppet/parser/functions/camelcase.rb": "71c67b71eac4b7f46a0dd22cb915d2e6",
  "lib/puppet/parser/functions/capitalize.rb": "da131748a9d32da9eb0b6438e39377eb",
  "lib/puppet/parser/functions/chomp.rb": "2b7dc42f9967edd34cfa0ba9a97229ca",
  "lib/puppet/parser/functions/chop.rb": "0ec76f54afd94201f35785dfeb2092b5",
  "lib/puppet/parser/functions/concat.rb": "5c0cfccb20d5553e5a7d14ba1aa70fc5",
  "lib/puppet/parser/functions/count.rb": "9eb74eccd93e2b3c87fd5ea14e329eba",
  "lib/puppet/parser/functions/deep_merge.rb": "d83696855578fb81b64b9e92b9c7cc7c",
  "lib/puppet/parser/functions/defined_with_params.rb": "ffab4433d03f32b551f2ea024a2948fc",
  "lib/puppet/parser/functions/delete.rb": "96e569dac96b8c9387e9303445d73048",
  "lib/puppet/parser/functions/delete_at.rb": "6bc24b79390d463d8be95396c963381a",
  "lib/puppet/parser/functions/delete_undef_values.rb": "b32d4a3925753b2eb2c318cbd7f14404",
  "lib/puppet/parser/functions/delete_values.rb": "39b147f7d369bb5f809044b6341954a2",
  "lib/puppet/parser/functions/difference.rb": "e31b95fbaf974cf853a510177368bfb9",
  "lib/puppet/parser/functions/dirname.rb": "bef7214eb89db3eb8f7ee5fc9dca0233",
  "lib/puppet/parser/functions/downcase.rb": "73121616d73339cf8dd10e0de61a6c50",
  "lib/puppet/parser/functions/empty.rb": "0b6ca9d0550a39c1ca50fc3d1ecbc98c",
  "lib/puppet/parser/functions/ensure_packages.rb": "fbed5c0c9bf82b7746e01f15f89d184f",
  "lib/puppet/parser/functions/ensure_resource.rb": "6678127386e77bbc0f09db7b5a32ab6a",
  "lib/puppet/parser/functions/flatten.rb": "25777b76f9719162a8bab640e5595b7a",
  "lib/puppet/parser/functions/floor.rb": "42cad4c689231a51526c55a6f0985d1f",
  "lib/puppet/parser/functions/fqdn_rotate.rb": "37be809c17902c1ecf9bb2b20f0bfacd",
  "lib/puppet/parser/functions/get_module_path.rb": "d4bf50da25c0b98d26b75354fa1bcc45",
  "lib/puppet/parser/functions/getparam.rb": "4dd7a0e35f4a3780dcfc9b19b4e0006e",
  "lib/puppet/parser/functions/getvar.rb": "ab01ce68140bbdd84162a519a14ece3b",
  "lib/puppet/parser/functions/grep.rb": "5682995af458b05f3b53dd794c4bf896",
  "lib/puppet/parser/functions/has_interface_with.rb": "ee3a1d6193951939b492a69ef170faac",
  "lib/puppet/parser/functions/has_ip_address.rb": "ee207f47906455a5aa49c4fb219dd325",
  "lib/puppet/parser/functions/has_ip_network.rb": "b4d726c8b2a0afac81ced8a3a28aa731",
  "lib/puppet/parser/functions/has_key.rb": "7cd9728c38f0b0065f832dabd62b0e7e",
  "lib/puppet/parser/functions/hash.rb": "9d072527dfc7354b69292e9302906530",
  "lib/puppet/parser/functions/intersection.rb": "924ac4aceec7b896952166a7ec08fdb1",
  "lib/puppet/parser/functions/is_array.rb": "875ca4356cb0d7a10606fb146b4a3d11",
  "lib/puppet/parser/functions/is_bool.rb": "e693b7c4b5366cff1380b6e0c7dd7b11",
  "lib/puppet/parser/functions/is_domain_name.rb": "cf72726c0fec831eb703ec9deea739eb",
  "lib/puppet/parser/functions/is_float.rb": "10e0d3ecf75fac15e415aee79acf70dc",
  "lib/puppet/parser/functions/is_function_available.rb": "628428bbcd9313ce09783d9484330e09",
  "lib/puppet/parser/functions/is_hash.rb": "8c7d9a05084dab0389d1b779c8a05b1a",
  "lib/puppet/parser/functions/is_integer.rb": "c665be82686aa4729959bb42c66a7510",
  "lib/puppet/parser/functions/is_ip_address.rb": "a714a736c1560e8739aaacd9030cca00",
  "lib/puppet/parser/functions/is_mac_address.rb": "288bd4b38d4df42a83681f13e7eaaee0",
  "lib/puppet/parser/functions/is_numeric.rb": "93ddc9d4c0834a5e5e0562d7b3cdce91",
  "lib/puppet/parser/functions/is_string.rb": "2bd9a652bbb2668323eee6c57729ff64",
  "lib/puppet/parser/functions/join.rb": "a285a05c015ae278608f6454aef211ea",
  "lib/puppet/parser/functions/join_keys_to_values.rb": "f29da49531228f6ca5b3aa0df00a14c2",
  "lib/puppet/parser/functions/keys.rb": "eb6ac815ea14fbf423580ed903ef7bad",
  "lib/puppet/parser/functions/loadyaml.rb": "2b912f257aa078e376d3b3f6a86c2a00",
  "lib/puppet/parser/functions/lstrip.rb": "20a9b1fa077c16f34e0ef5448b895698",
  "lib/puppet/parser/functions/max.rb": "f652fd0b46ef7d2fbdb42b141f8fdd1d",
  "lib/puppet/parser/functions/member.rb": "09c58cbfe10f50c034d376ada80a706b",
  "lib/puppet/parser/functions/merge.rb": "f3dcc5c83440cdda2036cce69b61a14b",
  "lib/puppet/parser/functions/min.rb": "0d2a1b7e735ab251c5469e735fa3f4c6",
  "lib/puppet/parser/functions/num2bool.rb": "605c12fa518c87ed2c66ae153e0686ce",
  "lib/puppet/parser/functions/parsejson.rb": "e7f968c34928107b84cd0860daf50ab1",
  "lib/puppet/parser/functions/parseyaml.rb": "00f10ec1e2b050e23d80c256061ebdd7",
  "lib/puppet/parser/functions/pick.rb": "bf01f13bbfe2318e7f6a302ac7c4433f",
  "lib/puppet/parser/functions/pick_default.rb": "ad3ea60262de408767786d37a54d45dc",
  "lib/puppet/parser/functions/prefix.rb": "aebbea0290be82a4ae89ddfffbee1125",
  "lib/puppet/parser/functions/private.rb": "065102bb39f665d65420c97dda740a40",
  "lib/puppet/parser/functions/range.rb": "17a05dbae8f562f882450f9e648d4e2d",
  "lib/puppet/parser/functions/reject.rb": "689f6a7c961a55fe9dcd240921f4c7f9",
  "lib/puppet/parser/functions/reverse.rb": "b234b54b8cd62b2d67ccd70489ffdccf",
  "lib/puppet/parser/functions/rstrip.rb": "b4e4ada41f7c1d2fcad073ce6344980f",
  "lib/puppet/parser/functions/shuffle.rb": "d50f72b0aeb921e64d2482f62488e2f3",
  "lib/puppet/parser/functions/size.rb": "8972d48c0f9e487d659bd7326b40b642",
  "lib/puppet/parser/functions/sort.rb": "504b033b438461ca4f9764feeb017833",
  "lib/puppet/parser/functions/squeeze.rb": "541f85b4203b55c9931d3d6ecd5c75f8",
  "lib/puppet/parser/functions/str2bool.rb": "6320f1a50fd28ec027981cd1fb8ffdd0",
  "lib/puppet/parser/functions/str2saltedsha512.rb": "49afad7b386be38ce53deaefef326e85",
  "lib/puppet/parser/functions/strftime.rb": "e02e01a598ca5d7d6eee0ba22440304a",
  "lib/puppet/parser/functions/strip.rb": "85d70ab95492e3e4ca5f0b5ec3f284a9",
  "lib/puppet/parser/functions/suffix.rb": "109279db4180441e75545dbd5f273298",
  "lib/puppet/parser/functions/swapcase.rb": "b17a9f3cb0271451d309e4b4f52dd651",
  "lib/puppet/parser/functions/time.rb": "08d88d52abd1e230e3a2f82107545d48",
  "lib/puppet/parser/functions/to_bytes.rb": "65437027687b6172173b3a211a799e37",
  "lib/puppet/parser/functions/type.rb": "62f914d6c90662aaae40c5539701be60",
  "lib/puppet/parser/functions/union.rb": "137998fe47decf25aede20f0c0155a4c",
  "lib/puppet/parser/functions/unique.rb": "c1bb4a8aeebd09ba3e4c8bc3702cfd60",
  "lib/puppet/parser/functions/upcase.rb": "086a7a470f738c4cb4cfc44591f1c00a",
  "lib/puppet/parser/functions/uriescape.rb": "4638c351a373450495d6ce38e708ec67",
  "lib/puppet/parser/functions/validate_absolute_path.rb": "385137ac24a2dec6cecc4e6ea75be442",
  "lib/puppet/parser/functions/validate_array.rb": "72b29289b8af1cfc3662ef9be78911b8",
  "lib/puppet/parser/functions/validate_augeas.rb": "b57e68fca390759782885474dc3ab2d0",
  "lib/puppet/parser/functions/validate_bool.rb": "a712634a000024398b3c6cd4ecc46463",
  "lib/puppet/parser/functions/validate_cmd.rb": "232dff623067f137bff364c67186dc05",
  "lib/puppet/parser/functions/validate_hash.rb": "e9cfaca68751524efe16ecf2f958a9a0",
  "lib/puppet/parser/functions/validate_ipv4_address.rb": "a8fb6f0ca36aa460d462c07c2af5d5a2",
  "lib/puppet/parser/functions/validate_ipv6_address.rb": "4699238e4cad60e7e1428905523eaeb7",
  "lib/puppet/parser/functions/validate_re.rb": "c6664b3943bc820415a43f16372dc2a9",
  "lib/puppet/parser/functions/validate_slength.rb": "7e67c213509b9383707819cc612b2a29",
  "lib/puppet/parser/functions/validate_string.rb": "cf6a20877a27b1073d63fdd522af50bb",
  "lib/puppet/parser/functions/values.rb": "066a6e4170e5034edb9a80463dff2bb5",
  "lib/puppet/parser/functions/values_at.rb": "325a899e0201e8df5bd483fec6f12d76",
  "lib/puppet/parser/functions/zip.rb": "a89d5e802bc1e63e52020c2ddbaaca2c",
  "lib/puppet/provider/file_line/ruby.rb": "bed19aaf4d9d06b646c554e1cdf37d2d",
  "lib/puppet/type/anchor.rb": "bbd36bb49c3b554f8602d8d3df366c0c",
  "lib/puppet/type/file_line.rb": "7ce47aac33472d0aa8401622f6a4297c",
  "manifests/init.pp": "f2ba5f36e7227ed87bbb69034fc0de8b",
  "manifests/stages.pp": "cc6ed1751d334b0ea278c0335c7f0b5a",
  "metadata.json": "7f488e74c5cb2e4a98ca81e831ca9385",
  "spec/acceptance/abs_spec.rb": "538db8d037db814b455a6d741e91bb8d",
  "spec/acceptance/any2array_spec.rb": "de86ead0205acbb3eca3a8a4792bdac8",
  "spec/acceptance/base64_spec.rb": "1684d5dd176dd5bbd4c3c6b1e64fbcea",
  "spec/acceptance/bool2num_spec.rb": "bf53ceac40d0a67551c618b11809f3f8",
  "spec/acceptance/build_csv.rb": "f28ef587de764ade1513091c4906412c",
  "spec/acceptance/capitalize_spec.rb": "e77ea2c37144a75a67969c0d0839adfd",
  "spec/acceptance/chomp_spec.rb": "fb0862a6b7eeb3c290e280788e705061",
  "spec/acceptance/chop_spec.rb": "4e7ab2d3a441b88b667a0d8ea5b174c1",
  "spec/acceptance/concat_spec.rb": "3a0dae19a34bb13d406c8e0ec87d8fe5",
  "spec/acceptance/count_spec.rb": "d82cfcad2461b16872455d6347a8b114",
  "spec/acceptance/deep_merge_spec.rb": "c335a947f1666e185e0210e661f1c78a",
  "spec/acceptance/defined_with_params_spec.rb": "f27c54ade9872c63c69316f62b03c119",
  "spec/acceptance/delete_at_spec.rb": "9c028b703ee0286565c9877757678f3f",
  "spec/acceptance/delete_spec.rb": "31e6dfcb9cc7c16b20d47c00e6a85a1d",
  "spec/acceptance/delete_undef_values_spec.rb": "6e6a66aee0c383c843b5f92ef8c8410c",
  "spec/acceptance/delete_values_spec.rb": "22c9b4914d4cbc0153aa3862cb4fb50e",
  "spec/acceptance/difference_spec.rb": "289f4f1788feaacb304ffd54971c7e7e",
  "spec/acceptance/dirname_spec.rb": "84db53878c4400a6c684c924cff05cfc",
  "spec/acceptance/downcase_spec.rb": "0f094849b94a94df491ee01186473104",
  "spec/acceptance/empty_spec.rb": "35c1f43e8a3e1fe7dd4335ef86e7efcc",
  "spec/acceptance/ensure_packages_spec.rb": "de93ff46bcdff523f5636d05b449f6be",
  "spec/acceptance/ensure_resource_spec.rb": "3e3e9b26ec6cd770469998e3eff49e00",
  "spec/acceptance/flatten_spec.rb": "83fb08cc168a105c1d5d0df66b1d9e84",
  "spec/acceptance/floor_spec.rb": "d7267b2914b1da6406224abb7489ca86",
  "spec/acceptance/fqdn_rotate_spec.rb": "468eed4b9bffa698fbf9219b8ae8435c",
  "spec/acceptance/get_module_path_spec.rb": "2658cdcd1abd4b7d20f53c4aced3c72a",
  "spec/acceptance/getparam_spec.rb": "4d32dc5a0ee34d045242c36d77a3b482",
  "spec/acceptance/getvar_spec.rb": "ba2f081a88be97c0e7004a6296294f23",
  "spec/acceptance/grep_spec.rb": "98818b8b0557b80d6ff519f70ea7617c",
  "spec/acceptance/has_interface_with_spec.rb": "30e27096050c43b7efdb5e6c0d54f53b",
  "spec/acceptance/has_ip_address_spec.rb": "2812117ec4b88556039e8488d53c0cb0",
  "spec/acceptance/has_ip_network_spec.rb": "ca75b43ff1256ead9052f2db7620db99",
  "spec/acceptance/has_key_spec.rb": "6509a26a0886f7d591eaa926b2f92407",
  "spec/acceptance/hash_spec.rb": "1c626457ba056bdd3936e28aa5bf503e",
  "spec/acceptance/intersection_spec.rb": "40f586af7f95408a5d4a2882a4aa98f1",
  "spec/acceptance/is_array_spec.rb": "c2ff70ce59b90b50a5aed67abaa5399d",
  "spec/acceptance/is_bool_spec.rb": "c001fdecff6b0a3c9dc78774987a0b15",
  "spec/acceptance/is_domain_name_spec.rb": "63e84285c26d8717fd5d4dda01e3f432",
  "spec/acceptance/is_float_spec.rb": "2f0164b4d732166aa46055a2cf7b4ea9",
  "spec/acceptance/is_function_available_spec.rb": "7745eba89f8719c9ca7ebf04d5b005f7",
  "spec/acceptance/is_hash_spec.rb": "cff723cd8fddac45033af5dc8406d4e4",
  "spec/acceptance/is_integer_spec.rb": "c09201d17d3914bba197872897fa3413",
  "spec/acceptance/is_ip_address_spec.rb": "aa14cf9abf404c3fe1e761ea957871fe",
  "spec/acceptance/is_mac_address_spec.rb": "30ff4c6a63be58daa3568305617ca2a7",
  "spec/acceptance/is_numeric_spec.rb": "fb9829c7a1a8d4a58836df6ff4c3386d",
  "spec/acceptance/is_string_spec.rb": "df3022de123b72f0022728eb2d8ce857",
  "spec/acceptance/join_keys_to_values_spec.rb": "8aa128bbaeea65aab8d92badee3ca2b5",
  "spec/acceptance/join_spec.rb": "c6378ed481265152bba9871fc5501ee6",
  "spec/acceptance/keys_spec.rb": "20486e3ebee53e50dc9de3b78b9d6ae6",
  "spec/acceptance/loadyaml_spec.rb": "bd440cb6779026bd07d83f1aceb2781b",
  "spec/acceptance/lstrip_spec.rb": "e29ab4039b65660ec2bd76a298adcae0",
  "spec/acceptance/max_spec.rb": "209cda4b83d677743afb1a8870330618",
  "spec/acceptance/member_spec.rb": "d6088a4fa6321791a3067d9b9cf8914a",
  "spec/acceptance/merge_spec.rb": "5f168188fa0d6b31ba5b3dac49fb609c",
  "spec/acceptance/min_spec.rb": "152a7db28434a0d0378561d4f64cddcc",
  "spec/acceptance/nodesets/centos-59-x64.yml": "57eb3e471b9042a8ea40978c467f8151",
  "spec/acceptance/nodesets/centos-6-vcloud.yml": "bdf9ce9d3b0f0b4995666ae9d64d878d",
  "spec/acceptance/nodesets/centos-64-x64-pe.yml": "ec075d95760df3d4702abea1ce0a829b",
  "spec/acceptance/nodesets/centos-64-x64.yml": "092dd2c588a9f87fa1fb12997c0723ef",
  "spec/acceptance/nodesets/centos-65-x64.yml": "3e5c36e6aa5a690229e720f4048bb8af",
  "spec/acceptance/nodesets/default.yml": "3e5c36e6aa5a690229e720f4048bb8af",
  "spec/acceptance/nodesets/fedora-18-x64.yml": "80e41b1ee16ea489f53164bfdae58855",
  "spec/acceptance/nodesets/sles-11-x64.yml": "44e4c6c15c018333bfa9840a5e702f66",
  "spec/acceptance/nodesets/ubuntu-server-10044-x64.yml": "75e86400b7889888dc0781c0ae1a1297",
  "spec/acceptance/nodesets/ubuntu-server-12042-x64.yml": "d30d73e34cd50b043c7d14e305955269",
  "spec/acceptance/nodesets/ubuntu-server-1404-x64.yml": "5f0aed10098ac5b78e4217bb27c7aaf0",
  "spec/acceptance/nodesets/windows-2003-i386.yml": "b518fc01fab99ee6a9afccec5bc0c1c4",
  "spec/acceptance/nodesets/windows-2003-x86_64.yml": "5c783eaa8ea4734edc836e89e923dfa1",
  "spec/acceptance/nodesets/windows-2008-x86_64.yml": "3082234eafcfaf7a9579d9ebdb8bc409",
  "spec/acceptance/nodesets/windows-2008r2-x86_64.yml": "dfeff32a4cc3fffa872c8281d990a840",
  "spec/acceptance/nodesets/windows-2012-x86_64.yml": "8bed73362ee1f43d21ea1903a729f955",
  "spec/acceptance/nodesets/windows-2012r2-x86_64.yml": "3f4f6112d24db02989b8ab79d3a1256f",
  "spec/acceptance/num2bool_spec.rb": "e4a00b913b08c68a689837e9f9336cb2",
  "spec/acceptance/parsejson_spec.rb": "ea3973d412ad6f72425fdfac6fbb2bb4",
  "spec/acceptance/parseyaml_spec.rb": "7bbfeed73d0626f69daedfc151957967",
  "spec/acceptance/pick_default_spec.rb": "1bc2562380ef6f6cded5ec90a03922be",
  "spec/acceptance/pick_spec.rb": "272c54c8f9398f499768331bdb4276ee",
  "spec/acceptance/prefix_spec.rb": "da620568c6771e7d492ec1ff697c531c",
  "spec/acceptance/range_spec.rb": "65e5b98ceca257658604d988fbec7d03",
  "spec/acceptance/reject_spec.rb": "b5185f1a6071c9bdc7aca92e6f899c3e",
  "spec/acceptance/reverse_spec.rb": "7bdee543e82532e97bbf7a067140031c",
  "spec/acceptance/rstrip_spec.rb": "28a64ceb7cb5ae8a93d31f49816190ab",
  "spec/acceptance/shuffle_spec.rb": "8a8652e57d56f2b4946cdf4d20052b7a",
  "spec/acceptance/size_spec.rb": "ae17d8a55921a0570972200c7c9327e1",
  "spec/acceptance/sort_spec.rb": "d44b1b8c090f0f00a2f38515fda431ea",
  "spec/acceptance/squeeze_spec.rb": "adcd65fa4e72203b97f1f14c8835c2cd",
  "spec/acceptance/str2bool_spec.rb": "55ad165ceef6b9ba32bf20ca3b53b44c",
  "spec/acceptance/str2saltedsha512_spec.rb": "b684c4214d06ae3d5bae055262a5ccaa",
  "spec/acceptance/strftime_spec.rb": "0f4eadbd74445b35de4a42c9790fbcc1",
  "spec/acceptance/strip_spec.rb": "6767da5bc735beb5362aeee6ff692c9e",
  "spec/acceptance/suffix_spec.rb": "07dfc7eed48b75fcc1b93d0308243eda",
  "spec/acceptance/swapcase_spec.rb": "5c3c1bc19a09fed6e01881f79b0b4ea5",
  "spec/acceptance/time_spec.rb": "044b2f634a1fa6ecc735998d68a93b73",
  "spec/acceptance/to_bytes_spec.rb": "f9df1f234b9409f5eaf56ef24e651c36",
  "spec/acceptance/type_spec.rb": "4297e038a8ff7e6ecb859b8b68c7b3a6",
  "spec/acceptance/union_spec.rb": "b6092941e0574f3c60910bebf84d2844",
  "spec/acceptance/unique_spec.rb": "9b00b21cefde3b5391f50eeb9cd2493b",
  "spec/acceptance/unsupported_spec.rb": "09b9265ecb05252cd5e5a18327c7ae97",
  "spec/acceptance/upcase_spec.rb": "ffd1d6f9e6ec24131fb78983c53a75f9",
  "spec/acceptance/uriescape_spec.rb": "13daa387714cbfc63b587aaa8dbf7fcd",
  "spec/acceptance/validate_absolute_path_spec.rb": "8b9ebfae80329231d84fcab606a3eeaf",
  "spec/acceptance/validate_array_spec.rb": "382641719e754622ffae562d10e38bf7",
  "spec/acceptance/validate_augeas_spec.rb": "c26b8ca2184a9dd87033a0c6f0553093",
  "spec/acceptance/validate_bool_spec.rb": "08bc139459204cf0a35098a5bc30ab95",
  "spec/acceptance/validate_cmd_spec.rb": "e9260c49d880e4de54f77bf4fd70cff4",
  "spec/acceptance/validate_hash_spec.rb": "70ceacc18a0dee97b26ab2e50f925706",
  "spec/acceptance/validate_ipv4_address_spec.rb": "dc901bbd05c3764a93cb49154cea6e4b",
  "spec/acceptance/validate_ipv6_address_spec.rb": "c0872c56230ac2800cd5723eaa5bc53a",
  "spec/acceptance/validate_re_spec.rb": "b289909078d6ae0d015419f518566698",
  "spec/acceptance/validate_slength_spec.rb": "f0a05c1c2b895b096cb7326df4821594",
  "spec/acceptance/validate_string_spec.rb": "6c9ced99fb1e263e66e25427d24f8f7b",
  "spec/acceptance/values_at_spec.rb": "669b26c4d47742051472003518c3aa61",
  "spec/acceptance/values_spec.rb": "9681223bb1bd755c28946ef0bcd6ece9",
  "spec/acceptance/zip_spec.rb": "86d1b555745ee873da68c71f1e46ed21",
  "spec/classes/anchor_spec.rb": "40600ba2845f9bd360a9504a347f12ba",
  "spec/functions/abs_spec.rb": "6c3a4f6072cf28132c29ff42791c0d11",
  "spec/functions/any2array_spec.rb": "2feb23a3615dc55d5e99ae8617f4aca3",
  "spec/functions/base64_spec.rb": "c93bdf30f5894728fe6558eb24955e26",
  "spec/functions/bool2num_spec.rb": "12d7f3074beaf3a8b5c06da39b8f5a88",
  "spec/functions/capitalize_spec.rb": "da52f8dd560b2a2ed57f13019b0b8302",
  "spec/functions/chomp_spec.rb": "dea81927a4c134e2a47500969324c70e",
  "spec/functions/chop_spec.rb": "3b0d0335f5e3347b7a9815e58b923657",
  "spec/functions/concat_spec.rb": "bd6e4ec0d455f69551b7ad724f3d3940",
  "spec/functions/count_spec.rb": "25e6e666561ced6d644d62bd71a648c6",
  "spec/functions/deep_merge_spec.rb": "84f4f2cc194de907143ea17a3d40687e",
  "spec/functions/defined_with_params_spec.rb": "498e064c37bb330dc80420e877e4e57d",
  "spec/functions/delete_at_spec.rb": "012b3399d4a7101fc4cd4938e9bd2d50",
  "spec/functions/delete_spec.rb": "0f064eca1423a58b56cead619f260eec",
  "spec/functions/delete_undef_values_spec.rb": "d61453c547c8816128e0a5e358821248",
  "spec/functions/delete_values_spec.rb": "737cf476b579fb7b549280eb20d13ae7",
  "spec/functions/difference_spec.rb": "2d7c07bc8bcb82831fcfe2f2a9958605",
  "spec/functions/dirname_spec.rb": "bd7a8f3b16d9fa7a2836eeca3d70069f",
  "spec/functions/downcase_spec.rb": "0864d43eb33e5d46a5943c2d117bfa40",
  "spec/functions/empty_spec.rb": "046c8206121e364eb9b11bfb378e591b",
  "spec/functions/ensure_packages_spec.rb": "f1b60599078cdcb3cff1368346108264",
  "spec/functions/ensure_resource_spec.rb": "7765dde3b9fc54b7dddb6597e0f7b523",
  "spec/functions/flatten_spec.rb": "a830987eb5b26a1b4325a7737fb9a7e2",
  "spec/functions/floor_spec.rb": "d53e184f732c7b0fa49664645d6fb63d",
  "spec/functions/fqdn_rotate_spec.rb": "46ff7d4e643cd42960bcfda145c8aa0d",
  "spec/functions/get_module_path_spec.rb": "632de3cddb0980998b1f7f819feda3b4",
  "spec/functions/getparam_spec.rb": "292346901bc0083a983fc166fee44675",
  "spec/functions/getvar_spec.rb": "e0fa7cde8c415d099cd31888670ca2fc",
  "spec/functions/grep_spec.rb": "aa5ab60a3899a4286152fbd5d3218bd3",
  "spec/functions/has_interface_with_spec.rb": "2abef34f38bf2369434f27ab5ab02e0f",
  "spec/functions/has_ip_address_spec.rb": "89d2a1e161ba9efdec36f90e1b7737bf",
  "spec/functions/has_ip_network_spec.rb": "b0c080fa6fa27f03a0999a07b4cfbd08",
  "spec/functions/has_key_spec.rb": "63f35c643a8a0ac1f3281b2981b4ab26",
  "spec/functions/hash_spec.rb": "f85918bdeb33c2b0dc276fda46528d56",
  "spec/functions/intersection_spec.rb": "fa5e91bec7bcf48c5d4b66e2824ba629",
  "spec/functions/is_array_spec.rb": "82266ebdbc4002dc4471eb19095a617d",
  "spec/functions/is_bool_spec.rb": "f8075f0d7b79b5568a646d97fb4e8115",
  "spec/functions/is_domain_name_spec.rb": "533fea73283081f95c1196f2b347091c",
  "spec/functions/is_float_spec.rb": "adf03894b9e78f1e66831ba52ac20f49",
  "spec/functions/is_function_available.rb": "193666f87f9a739a77335d9171411f5f",
  "spec/functions/is_hash_spec.rb": "f1906d7cacf56f0ed26f703a3c4e19c4",
  "spec/functions/is_integer_spec.rb": "5ed8c0620c64a4e8a6a07105816ae1f4",
  "spec/functions/is_ip_address_spec.rb": "1c3ce0f2f9b6354d6ea7ffa36731d94c",
  "spec/functions/is_mac_address_spec.rb": "60b1ea6464e10f3c8a095af0b69a1f4a",
  "spec/functions/is_numeric_spec.rb": "6ceee608830d8d3c37a0d52d253e5ed1",
  "spec/functions/is_string_spec.rb": "b67b213edc19f0bd97b2e4e561b4688b",
  "spec/functions/join_keys_to_values_spec.rb": "444289422833c4d932432cba336d79ff",
  "spec/functions/join_spec.rb": "35fe86a4a49befe39452eb861f3c66ff",
  "spec/functions/keys_spec.rb": "6ada6f2263dda5a22b0505bab90c1543",
  "spec/functions/loadyaml_spec.rb": "7d688e8382dd47db93dc4c710f8d6010",
  "spec/functions/lstrip_spec.rb": "3161f3673f327aed9488958bbb91d720",
  "spec/functions/max_spec.rb": "0ced8af1760cb387e7b8f4bc014fc94b",
  "spec/functions/member_spec.rb": "102a75fe2285938464741852f221f1fa",
  "spec/functions/merge_spec.rb": "791ea69c46145b9c39f65f8d241a1205",
  "spec/functions/min_spec.rb": "b13e21751bfacc850019fa4c7c177536",
  "spec/functions/num2bool_spec.rb": "837bc45de67428a3c1faf8e22bb7dcf1",
  "spec/functions/parsejson_spec.rb": "76e923a21cc6ddd38edf9a18e52991ae",
  "spec/functions/parseyaml_spec.rb": "ebc620457c14d268a3f313277ab5ff46",
  "spec/functions/pick_default_spec.rb": "dbfcee6a55488e8cb0af0866e1297f8c",
  "spec/functions/pick_spec.rb": "c7ae8b1aa7eb615c9164d3cccfc891fb",
  "spec/functions/prefix_spec.rb": "8b9202ab77ece34dc6d964e17228484a",
  "spec/functions/private_spec.rb": "0c0c0ccc8d247e49a73cda07f845b6cc",
  "spec/functions/range_spec.rb": "035bef6664d31631deb3066fde6422a2",
  "spec/functions/reject_spec.rb": "12cd8e9b98234dbfca06b33af4152bf3",
  "spec/functions/reverse_spec.rb": "4dc357880ba5d3716c53d73e2045466a",
  "spec/functions/rstrip_spec.rb": "af0d0c8b18c772f10e8227b3e9d8a54a",
  "spec/functions/shuffle_spec.rb": "de716009e14609112b0209570dc69b06",
  "spec/functions/size_spec.rb": "7551af6a9055650c863431ee6f9c82f5",
  "spec/functions/sort_spec.rb": "c548fee79b5e86e5371371dbb36982db",
  "spec/functions/squeeze_spec.rb": "aa7d260c8840e0eb4b72def5e0f63d96",
  "spec/functions/str2bool_spec.rb": "1b854776e182f528d72f624a581e1a19",
  "spec/functions/str2saltedsha512_spec.rb": "284430b18af76f42d60ad2db4c5e265a",
  "spec/functions/strftime_spec.rb": "55b2abeecb65d147136d6af49ce61924",
  "spec/functions/strip_spec.rb": "ac5316d9357fecba9ac55bdb0eb0ac29",
  "spec/functions/suffix_spec.rb": "217ff8dc2f509b860af7c7c9ff73134b",
  "spec/functions/swapcase_spec.rb": "686d6ff7c7a1fd473d2a74a1c3bbe8ca",
  "spec/functions/time_spec.rb": "1a2db01a57ed1437b19cdeaaabc2c77e",
  "spec/functions/to_bytes_spec.rb": "f0b0fbb9919bbe3882ca0d8f8db2c3b8",
  "spec/functions/type_spec.rb": "67d0cd9eebdf68262477b39657915d20",
  "spec/functions/union_spec.rb": "db5d5a0aa8c29725936e2488ccbcfd0a",
  "spec/functions/unique_spec.rb": "42f9b82d1df269a1b34f4562369b8b84",
  "spec/functions/upcase_spec.rb": "a22d1d5e6554a2393203f20e2eac37d0",
  "spec/functions/uriescape_spec.rb": "e09f0f54dbc8bccddac06236d7920f7c",
  "spec/functions/validate_absolute_path_spec.rb": "5a0b98675070e511810dab9e60dc43b6",
  "spec/functions/validate_array_spec.rb": "bcd231229554785c4270ca92ef99cb60",
  "spec/functions/validate_augeas_spec.rb": "eee1a0c3ef3051bda525b1e17d577ab0",
  "spec/functions/validate_bool_spec.rb": "7aeb6085fc9601c6bbe6c49e56d209a4",
  "spec/functions/validate_cmd_spec.rb": "efc88e8e21481acd36c7f948b1f226ea",
  "spec/functions/validate_hash_spec.rb": "8529c74051ceb71e6b1b97c9cecdf625",
  "spec/functions/validate_ipv4_address_spec.rb": "19f2f44fbbdf7a2e69aeaa2f0f402695",
  "spec/functions/validate_ipv6_address_spec.rb": "2d8617be4405bdbd84d140ba8be6c184",
  "spec/functions/validate_re_spec.rb": "d8ab477f9afcb748f144588ebb3a28a3",
  "spec/functions/validate_slength_spec.rb": "438738f1ac9363d5a7cd8c3ee09fe14c",
  "spec/functions/validate_string_spec.rb": "64a4f681084cba55775a070f7fab5e0c",
  "spec/functions/values_at_spec.rb": "cdfc313cc283400f1aed75f4cbd0ab4f",
  "spec/functions/values_spec.rb": "2ea5dd37e6ac9c89f4b434c7ed7cc45e",
  "spec/functions/zip_spec.rb": "d67e3424e60de00ff26e73516f4bf6da",
  "spec/lib/puppet_spec/compiler.rb": "3c1f03dd8ac2f6f90d7e8f879a3ce4c0",
  "spec/lib/puppet_spec/database.rb": "c74c0cf62980beea88c7749f876ccfa7",
  "spec/lib/puppet_spec/files.rb": "906da85e399302cee403e10e357d3f4c",
  "spec/lib/puppet_spec/fixtures.rb": "0722c5ccbfcba1fc27da1900e54b4463",
  "spec/lib/puppet_spec/matchers.rb": "dd30ba6b936e8c267511d67acb087c35",
  "spec/lib/puppet_spec/modules.rb": "445d2739aa8754568a14816280727d70",
  "spec/lib/puppet_spec/pops.rb": "adf661defa460b7189e3750535533d34",
  "spec/lib/puppet_spec/scope.rb": "01aeb89bdc2d29a2528ced26ec6402ec",
  "spec/lib/puppet_spec/settings.rb": "5da4e0dad8bf6b21cc4437c73753a56d",
  "spec/lib/puppet_spec/verbose.rb": "71dbccd9a45ed89d12fd1c44456a6820",
  "spec/monkey_patches/alias_should_to_must.rb": "b19ee31563afb91a72f9869f9d7362ff",
  "spec/monkey_patches/publicize_methods.rb": "c690e444b77c871375d321e413e28ca1",
  "spec/spec.opts": "a600ded995d948e393fbe2320ba8e51c",
  "spec/spec_helper.rb": "b7a797512ad4ae4395fa5d1ff524e1f0",
  "spec/spec_helper_acceptance.rb": "ffb989c77153f8206c9be08f32278147",
  "spec/unit/facter/facter_dot_d_spec.rb": "420339a544851f2c7ee6fa4c651bdce8",
  "spec/unit/facter/pe_version_spec.rb": "af4d4428a7625a19de1751ce1bb09d5c",
  "spec/unit/facter/root_home_spec.rb": "2dabfc67279e85714e0d4479bd149e78",
  "spec/unit/facter/util/puppet_settings_spec.rb": "7b4afdfe4b80ee6463564bda2c4af344",
  "spec/unit/puppet/parser/functions/bool2str_spec.rb": "c0a7f753889d0e65c25db5b0eebad7ac",
  "spec/unit/puppet/parser/functions/camelcase_spec.rb": "332621f98485c651b281aa4b5ac82b5d",
  "spec/unit/puppet/provider/file_line/ruby_spec.rb": "03b43eac27a171529c6d31595933a802",
  "spec/unit/puppet/type/anchor_spec.rb": "06a669dffa44d716bf19b4e7f5f1d75d",
  "spec/unit/puppet/type/file_line_spec.rb": "294c3d0ac5658ddbace74aafd25d3c56",
  "tests/file_line.pp": "67727539aa7b7dd76f06626fe734f7f7",
  "tests/has_interface_with.pp": "59c98b4af0d39fc11d1ef4c7a6dc8f7a",
  "tests/has_ip_address.pp": "93ce02915f67ddfb43a049b2b84ef391",
  "tests/has_ip_network.pp": "abc05686797a776ea8c054657e6f7456",
  "tests/init.pp": "1d98070412c76824e66db4b7eb74d433"
}
# A Facter plugin that loads facts from /etc/facter/facts.d
# and /etc/puppetlabs/facter/facts.d.
#
# Facts can be in the form of JSON, YAML or Text files
# and any executable that returns key=value pairs.
#
# In the case of scripts you can also create a file that
# contains a cache TTL.  For foo.sh store the ttl as just
# a number in foo.sh.ttl
#
# The cache is stored in /tmp/facts_cache.yaml as a mode
# 600 file and will have the end result of not calling your
# fact scripts more often than is needed

class Facter::Util::DotD
  require 'yaml'

  def initialize(dir="/etc/facts.d", cache_file="/tmp/facts_cache.yml")
    @dir = dir
    @cache_file = cache_file
    @cache = nil
    @types = {".txt" => :txt, ".json" => :json, ".yaml" => :yaml}
  end

  def entries
    Dir.entries(@dir).reject{|f| f =~ /^\.|\.ttl$/}.sort.map {|f| File.join(@dir, f) }
  rescue
    []
  end

  def fact_type(file)
    extension = File.extname(file)

    type = @types[extension] || :unknown

    type = :script if type == :unknown && File.executable?(file)

    return type
  end

  def txt_parser(file)
    File.readlines(file).each do |line|
      if line =~ /^([^=]+)=(.+)$/
        var = $1; val = $2

        Facter.add(var) do
          setcode { val }
        end
      end
    end
  rescue Exception => e
    Facter.warn("Failed to handle #{file} as text facts: #{e.class}: #{e}")
  end

  def json_parser(file)
    begin
      require 'json'
    rescue LoadError
      retry if require 'rubygems'
      raise
    end

    JSON.load(File.read(file)).each_pair do |f, v|
      Facter.add(f) do
        setcode { v }
      end
    end
  rescue Exception => e
    Facter.warn("Failed to handle #{file} as json facts: #{e.class}: #{e}")
  end

  def yaml_parser(file)
    require 'yaml'

    YAML.load_file(file).each_pair do |f, v|
      Facter.add(f) do
        setcode { v }
      end
    end
  rescue Exception => e
    Facter.warn("Failed to handle #{file} as yaml facts: #{e.class}: #{e}")
  end

  def script_parser(file)
    result = cache_lookup(file)
    ttl = cache_time(file)

    unless result
      result = Facter::Util::Resolution.exec(file)

      if ttl > 0
        Facter.debug("Updating cache for #{file}")
        cache_store(file, result)
        cache_save!
      end
    else
      Facter.debug("Using cached data for #{file}")
    end

    result.split("\n").each do |line|
      if line =~ /^(.+)=(.+)$/
        var = $1; val = $2

        Facter.add(var) do
          setcode { val }
        end
      end
    end
  rescue Exception => e
    Facter.warn("Failed to handle #{file} as script facts: #{e.class}: #{e}")
    Facter.debug(e.backtrace.join("\n\t"))
  end

  def cache_save!
    cache = load_cache
    File.open(@cache_file, "w", 0600) {|f| f.write(YAML.dump(cache)) }
  rescue
  end

  def cache_store(file, data)
    load_cache

    @cache[file] = {:data => data, :stored => Time.now.to_i}
  rescue
  end

  def cache_lookup(file)
    cache = load_cache

    return nil if cache.empty?

    ttl = cache_time(file)

    if cache[file]
      now = Time.now.to_i

      return cache[file][:data] if ttl == -1
      return cache[file][:data] if (now - cache[file][:stored]) <= ttl
      return nil
    else
      return nil
    end
  rescue
    return nil
  end

  def cache_time(file)
    meta = file + ".ttl"

    return File.read(meta).chomp.to_i
  rescue
    return 0
  end

  def load_cache
    unless @cache
      if File.exist?(@cache_file)
        @cache = YAML.load_file(@cache_file)
      else
        @cache = {}
      end
    end

    return @cache
  rescue
    @cache = {}
    return @cache
  end

  def create
    entries.each do |fact|
      type = fact_type(fact)
      parser = "#{type}_parser"

      if respond_to?("#{type}_parser")
        Facter.debug("Parsing #{fact} using #{parser}")

        send(parser, fact)
      end
    end
  end
end


mdata = Facter.version.match(/(\d+)\.(\d+)\.(\d+)/)
if mdata
  (major, minor, patch) = mdata.captures.map { |v| v.to_i }
  if major < 2
    # Facter 1.7 introduced external facts support directly
    unless major == 1 and minor > 6
      Facter::Util::DotD.new("/etc/facter/facts.d").create
      Facter::Util::DotD.new("/etc/puppetlabs/facter/facts.d").create

      # Windows has a different configuration directory that defaults to a vendor
      # specific sub directory of the %COMMON_APPDATA% directory.
      if Dir.const_defined? 'COMMON_APPDATA' then
        windows_facts_dot_d = File.join(Dir::COMMON_APPDATA, 'PuppetLabs', 'facter', 'facts.d')
        Facter::Util::DotD.new(windows_facts_dot_d).create
      end
    end
  end
end
# Fact: is_pe, pe_version, pe_major_version, pe_minor_version, pe_patch_version
#
# Purpose: Return various facts about the PE state of the system
#
# Resolution: Uses a regex match against puppetversion to determine whether the
#   machine has Puppet Enterprise installed, and what version (overall, major,
#   minor, patch) is installed.
#
# Caveats:
#
Facter.add("pe_version") do
  setcode do
    pe_ver = Facter.value("puppetversion").match(/Puppet Enterprise (\d+\.\d+\.\d+)/)
    pe_ver[1] if pe_ver
  end
end

Facter.add("is_pe") do
  setcode do
    if Facter.value(:pe_version).to_s.empty? then
      false
    else
      true
    end
  end
end

Facter.add("pe_major_version") do
  confine :is_pe => true
  setcode do
    if pe_version = Facter.value(:pe_version)
      pe_version.to_s.split('.')[0]
    end
  end
end

Facter.add("pe_minor_version") do
  confine :is_pe => true
  setcode do
    if pe_version = Facter.value(:pe_version)
      pe_version.to_s.split('.')[1]
    end
  end
end

Facter.add("pe_patch_version") do
  confine :is_pe => true
  setcode do
    if pe_version = Facter.value(:pe_version)
      pe_version.to_s.split('.')[2]
    end
  end
end
# This facter fact returns the value of the Puppet vardir setting for the node
# running puppet or puppet agent.  The intent is to enable Puppet modules to
# automatically have insight into a place where they can place variable data,
# regardless of the node's platform.
#
# The value should be directly usable in a File resource path attribute.


begin
  require 'facter/util/puppet_settings'
rescue LoadError => e
  # puppet apply does not add module lib directories to the $LOAD_PATH (See
  # #4248). It should (in the future) but for the time being we need to be
  # defensive which is what this rescue block is doing.
  rb_file = File.join(File.dirname(__FILE__), 'util', 'puppet_settings.rb')
  load rb_file if File.exists?(rb_file) or raise e
end

Facter.add(:puppet_vardir) do
  setcode do
    # This will be nil if Puppet is not available.
    Facter::Util::PuppetSettings.with_puppet do
      Puppet[:vardir]
    end
  end
end
# A facter fact to determine the root home directory.
# This varies on PE supported platforms and may be
# reconfigured by the end user.

module Facter::Util::RootHome
  class << self
  def get_root_home
    root_ent = Facter::Util::Resolution.exec("getent passwd root")
    # The home directory is the sixth element in the passwd entry
    # If the platform doesn't have getent, root_ent will be nil and we should
    # return it straight away.
    root_ent && root_ent.split(":")[5]
  end
  end
end

Facter.add(:root_home) do
  setcode { Facter::Util::RootHome.get_root_home }
end

Facter.add(:root_home) do
  confine :kernel => :darwin
  setcode do
    str = Facter::Util::Resolution.exec("dscacheutil -q user -a name root")
    hash = {}
    str.split("\n").each do |pair|
      key,value = pair.split(/:/)
      hash[key] = value
    end
    hash['dir'].strip
  end
end
module Facter
  module Util
    module PuppetSettings
      # This method is intended to provide a convenient way to evaluate a
      # Facter code block only if Puppet is loaded.  This is to account for the
      # situation where the fact happens to be in the load path, but Puppet is
      # not loaded for whatever reason.  Perhaps the user is simply running
      # facter without the --puppet flag and they happen to be working in a lib
      # directory of a module.
      def self.with_puppet
        begin
          Module.const_get("Puppet")
        rescue NameError
          nil
        else
          yield
        end
      end
    end
  end
end
#
# abs.rb
#

module Puppet::Parser::Functions
  newfunction(:abs, :type => :rvalue, :doc => <<-EOS
    Returns the absolute value of a number, for example -34.56 becomes
    34.56. Takes a single integer and float value as an argument.
    EOS
  ) do |arguments|

    raise(Puppet::ParseError, "abs(): Wrong number of arguments " +
      "given (#{arguments.size} for 1)") if arguments.size < 1

    value = arguments[0]

    # Numbers in Puppet are often string-encoded which is troublesome ...
    if value.is_a?(String)
      if value.match(/^-?(?:\d+)(?:\.\d+){1}$/)
        value = value.to_f
      elsif value.match(/^-?\d+$/)
        value = value.to_i
      else
        raise(Puppet::ParseError, 'abs(): Requires float or ' +
          'integer to work with')
      end
    end

    # We have numeric value to handle ...
    result = value.abs

    return result
  end
end

# vim: set ts=2 sw=2 et :
#
# any2array.rb
#

module Puppet::Parser::Functions
  newfunction(:any2array, :type => :rvalue, :doc => <<-EOS
This converts any object to an array containing that object. Empty argument
lists are converted to an empty array. Arrays are left untouched. Hashes are
converted to arrays of alternating keys and values.
    EOS
  ) do |arguments|

    if arguments.empty?
        return []
    end

    if arguments.length == 1
        if arguments[0].kind_of?(Array)
            return arguments[0]
        elsif arguments[0].kind_of?(Hash)
            result = []
            arguments[0].each do |key, value|
                result << key << value
            end
            return result
        end
    end

    return arguments
  end
end

# vim: set ts=2 sw=2 et :
module Puppet::Parser::Functions

  newfunction(:base64, :type => :rvalue, :doc => <<-'ENDHEREDOC') do |args|

    Base64 encode or decode a string based on the command and the string submitted

    Usage:

      $encodestring = base64('encode','thestring')
      $decodestring = base64('decode','dGhlc3RyaW5n')

    ENDHEREDOC

    require 'base64'

    raise Puppet::ParseError, ("base64(): Wrong number of arguments (#{args.length}; must be = 2)") unless args.length == 2

    actions = ['encode','decode']

    unless actions.include?(args[0])
      raise Puppet::ParseError, ("base64(): the first argument must be one of 'encode' or 'decode'")
    end

    unless args[1].is_a?(String)
      raise Puppet::ParseError, ("base64(): the second argument must be a string to base64")
    end

    case args[0]
      when 'encode'
        result = Base64.encode64(args[1])
      when 'decode'
        result = Base64.decode64(args[1])
    end

    return result
  end
end
#
# bool2num.rb
#

module Puppet::Parser::Functions
  newfunction(:bool2num, :type => :rvalue, :doc => <<-EOS
    Converts a boolean to a number. Converts the values:
      false, f, 0, n, and no to 0
      true, t, 1, y, and yes to 1
    Requires a single boolean or string as an input.
    EOS
  ) do |arguments|

    raise(Puppet::ParseError, "bool2num(): Wrong number of arguments " +
      "given (#{arguments.size} for 1)") if arguments.size < 1

    value = function_str2bool([arguments[0]])

    # We have real boolean values as well ...
    result = value ? 1 : 0

    return result
  end
end

# vim: set ts=2 sw=2 et :
#
# bool2str.rb
#

module Puppet::Parser::Functions
  newfunction(:bool2str, :type => :rvalue, :doc => <<-EOS
    Converts a boolean to a string.
    Requires a single boolean as an input.
    EOS
  ) do |arguments|

    raise(Puppet::ParseError, "bool2str(): Wrong number of arguments " +
      "given (#{arguments.size} for 1)") if arguments.size < 1

    value = arguments[0]
    klass = value.class

    # We can have either true or false, and nothing else
    unless [FalseClass, TrueClass].include?(klass)
      raise(Puppet::ParseError, 'bool2str(): Requires a boolean to work with')
    end

    return value.to_s
  end
end

# vim: set ts=2 sw=2 et :
#
#  camelcase.rb
#

module Puppet::Parser::Functions
  newfunction(:camelcase, :type => :rvalue, :doc => <<-EOS
Converts the case of a string or all strings in an array to camel case.
    EOS
  ) do |arguments|

    raise(Puppet::ParseError, "camelcase(): Wrong number of arguments " +
      "given (#{arguments.size} for 1)") if arguments.size < 1

    value = arguments[0]
    klass = value.class

    unless [Array, String].include?(klass)
      raise(Puppet::ParseError, 'camelcase(): Requires either ' +
        'array or string to work with')
    end

    if value.is_a?(Array)
      # Numbers in Puppet are often string-encoded which is troublesome ...
      result = value.collect { |i| i.is_a?(String) ? i.split('_').map{|e| e.capitalize}.join : i }
    else
      result = value.split('_').map{|e| e.capitalize}.join
    end

    return result
  end
end

# vim: set ts=2 sw=2 et :
#
#  capitalize.rb
#

module Puppet::Parser::Functions
  newfunction(:capitalize, :type => :rvalue, :doc => <<-EOS
    Capitalizes the first letter of a string or array of strings.
    Requires either a single string or an array as an input.
    EOS
  ) do |arguments|

    raise(Puppet::ParseError, "capitalize(): Wrong number of arguments " +
      "given (#{arguments.size} for 1)") if arguments.size < 1

    value = arguments[0]

    unless value.is_a?(Array) || value.is_a?(String)
      raise(Puppet::ParseError, 'capitalize(): Requires either ' +
        'array or string to work with')
    end

    if value.is_a?(Array)
      # Numbers in Puppet are often string-encoded which is troublesome ...
      result = value.collect { |i| i.is_a?(String) ? i.capitalize : i }
    else
      result = value.capitalize
    end

    return result
  end
end

# vim: set ts=2 sw=2 et :
#
#  chomp.rb
#

module Puppet::Parser::Functions
  newfunction(:chomp, :type => :rvalue, :doc => <<-'EOS'
    Removes the record separator from the end of a string or an array of
    strings, for example `hello\n` becomes `hello`.
    Requires a single string or array as an input.
    EOS
  ) do |arguments|

    raise(Puppet::ParseError, "chomp(): Wrong number of arguments " +
      "given (#{arguments.size} for 1)") if arguments.size < 1

    value = arguments[0]

    unless value.is_a?(Array) || value.is_a?(String)
      raise(Puppet::ParseError, 'chomp(): Requires either ' +
        'array or string to work with')
    end

    if value.is_a?(Array)
      # Numbers in Puppet are often string-encoded which is troublesome ...
      result = value.collect { |i| i.is_a?(String) ? i.chomp : i }
    else
      result = value.chomp
    end

    return result
  end
end

# vim: set ts=2 sw=2 et :
#
#  chop.rb
#

module Puppet::Parser::Functions
  newfunction(:chop, :type => :rvalue, :doc => <<-'EOS'
    Returns a new string with the last character removed. If the string ends
    with `\r\n`, both characters are removed. Applying chop to an empty
    string returns an empty string. If you wish to merely remove record
    separators then you should use the `chomp` function.
    Requires a string or array of strings as input.
    EOS
  ) do |arguments|

    raise(Puppet::ParseError, "chop(): Wrong number of arguments " +
      "given (#{arguments.size} for 1)") if arguments.size < 1

    value = arguments[0]

    unless value.is_a?(Array) || value.is_a?(String)
      raise(Puppet::ParseError, 'chop(): Requires either an ' +
        'array or string to work with')
    end

    if value.is_a?(Array)
      # Numbers in Puppet are often string-encoded which is troublesome ...
      result = value.collect { |i| i.is_a?(String) ? i.chop : i }
    else
      result = value.chop
    end

    return result
  end
end

# vim: set ts=2 sw=2 et :
#
# concat.rb
#

module Puppet::Parser::Functions
  newfunction(:concat, :type => :rvalue, :doc => <<-EOS
Appends the contents of array 2 onto array 1.

*Example:*

    concat(['1','2','3'],['4','5','6'])

Would result in:

  ['1','2','3','4','5','6']
    EOS
  ) do |arguments|

    # Check that 2 arguments have been given ...
    raise(Puppet::ParseError, "concat(): Wrong number of arguments " +
      "given (#{arguments.size} for 2)") if arguments.size != 2

    a = arguments[0]
    b = arguments[1]

    # Check that the first parameter is an array
    unless a.is_a?(Array)
      raise(Puppet::ParseError, 'concat(): Requires array to work with')
    end

    result = a + Array(b)

    return result
  end
end

# vim: set ts=2 sw=2 et :
module Puppet::Parser::Functions
  newfunction(:count, :type => :rvalue, :arity => -2, :doc => <<-EOS
Takes an array as first argument and an optional second argument.
Count the number of elements in array that matches second argument.
If called with only an array it counts the number of elements that are not nil/undef.
    EOS
  ) do |args|

    if (args.size > 2) then
      raise(ArgumentError, "count(): Wrong number of arguments "+
        "given #{args.size} for 1 or 2.")
    end

    collection, item = args

    if item then
      collection.count item
    else
      collection.count { |obj| obj != nil && obj != :undef && obj != '' }
    end
  end
end
module Puppet::Parser::Functions
  newfunction(:deep_merge, :type => :rvalue, :doc => <<-'ENDHEREDOC') do |args|
    Recursively merges two or more hashes together and returns the resulting hash.

    For example:

        $hash1 = {'one' => 1, 'two' => 2, 'three' => { 'four' => 4 } }
        $hash2 = {'two' => 'dos', 'three' => { 'five' => 5 } }
        $merged_hash = deep_merge($hash1, $hash2)
        # The resulting hash is equivalent to:
        # $merged_hash = { 'one' => 1, 'two' => 'dos', 'three' => { 'four' => 4, 'five' => 5 } }

    When there is a duplicate key that is a hash, they are recursively merged.
    When there is a duplicate key that is not a hash, the key in the rightmost hash will "win."

    ENDHEREDOC

    if args.length < 2
      raise Puppet::ParseError, ("deep_merge(): wrong number of arguments (#{args.length}; must be at least 2)")
    end

    deep_merge = Proc.new do |hash1,hash2|
      hash1.merge(hash2) do |key,old_value,new_value|
        if old_value.is_a?(Hash) && new_value.is_a?(Hash)
          deep_merge.call(old_value, new_value)
        else
          new_value
        end
      end
    end

    result = Hash.new
    args.each do |arg|
      next if arg.is_a? String and arg.empty? # empty string is synonym for puppet's undef
      # If the argument was not a hash, skip it.
      unless arg.is_a?(Hash)
        raise Puppet::ParseError, "deep_merge: unexpected argument type #{arg.class}, only expects hash arguments"
      end

      result = deep_merge.call(result, arg)
    end
    return( result )
  end
end
# Test whether a given class or definition is defined
require 'puppet/parser/functions'

Puppet::Parser::Functions.newfunction(:defined_with_params,
                                      :type => :rvalue,
                                      :doc => <<-'ENDOFDOC'
Takes a resource reference and an optional hash of attributes.

Returns true if a resource with the specified attributes has already been added
to the catalog, and false otherwise.

    user { 'dan':
      ensure => present,
    }

    if ! defined_with_params(User[dan], {'ensure' => 'present' }) {
      user { 'dan': ensure => present, }
    }
ENDOFDOC
) do |vals|
  reference, params = vals
  raise(ArgumentError, 'Must specify a reference') unless reference
  if (! params) || params == ''
    params = {}
  end
  ret = false
  if resource = findresource(reference.to_s)
    matches = params.collect do |key, value|
      resource[key] == value
    end
    ret = params.empty? || !matches.include?(false)
  end
  Puppet.debug("Resource #{reference} was not determined to be defined")
  ret
end
#
# delete.rb
#

# TODO(Krzysztof Wilczynski): We need to add support for regular expression ...

module Puppet::Parser::Functions
  newfunction(:delete, :type => :rvalue, :doc => <<-EOS
Deletes all instances of a given element from an array, substring from a
string, or key from a hash.

*Examples:*

    delete(['a','b','c','b'], 'b')
    Would return: ['a','c']

    delete({'a'=>1,'b'=>2,'c'=>3}, 'b')
    Would return: {'a'=>1,'c'=>3}

    delete('abracadabra', 'bra')
    Would return: 'acada'
    EOS
  ) do |arguments|

    if (arguments.size != 2) then
      raise(Puppet::ParseError, "delete(): Wrong number of arguments "+
        "given #{arguments.size} for 2.")
    end

    collection = arguments[0].dup
    item = arguments[1]

    case collection
    when Array, Hash
      collection.delete item
    when String
      collection.gsub! item, ''
    else
      raise(TypeError, "delete(): First argument must be an Array, " +
            "String, or Hash. Given an argument of class #{collection.class}.")
    end
    collection
  end
end

# vim: set ts=2 sw=2 et :
#
# delete_at.rb
#

module Puppet::Parser::Functions
  newfunction(:delete_at, :type => :rvalue, :doc => <<-EOS
Deletes a determined indexed value from an array.

*Examples:*

    delete_at(['a','b','c'], 1)

Would return: ['a','c']
    EOS
  ) do |arguments|

    raise(Puppet::ParseError, "delete_at(): Wrong number of arguments " +
      "given (#{arguments.size} for 2)") if arguments.size < 2

    array = arguments[0]

    unless array.is_a?(Array)
      raise(Puppet::ParseError, 'delete_at(): Requires array to work with')
    end

    index = arguments[1]

    if index.is_a?(String) and not index.match(/^\d+$/)
      raise(Puppet::ParseError, 'delete_at(): You must provide ' +
        'non-negative numeric index')
    end

    result = array.clone

    # Numbers in Puppet are often string-encoded which is troublesome ...
    index = index.to_i

    if index > result.size - 1 # First element is at index 0 is it not?
      raise(Puppet::ParseError, 'delete_at(): Given index ' +
        'exceeds size of array given')
    end

    result.delete_at(index) # We ignore the element that got deleted ...

    return result
  end
end

# vim: set ts=2 sw=2 et :
module Puppet::Parser::Functions
  newfunction(:delete_undef_values, :type => :rvalue, :doc => <<-EOS
Returns a copy of input hash or array with all undefs deleted.

*Examples:*

    $hash = delete_undef_values({a=>'A', b=>'', c=>undef, d => false})

Would return: {a => 'A', b => '', d => false}

    $array = delete_undef_values(['A','',undef,false])

Would return: ['A','',false]

      EOS
    ) do |args|

    raise(Puppet::ParseError,
          "delete_undef_values(): Wrong number of arguments given " +
          "(#{args.size})") if args.size < 1

    unless args[0].is_a? Array or args[0].is_a? Hash
      raise(Puppet::ParseError,
            "delete_undef_values(): expected an array or hash, got #{args[0]} type  #{args[0].class} ")
    end
    result = args[0].dup
    if result.is_a?(Hash)
      result.delete_if {|key, val| val.equal? :undef}
    elsif result.is_a?(Array)
      result.delete :undef
    end
    result
  end
end
module Puppet::Parser::Functions
  newfunction(:delete_values, :type => :rvalue, :doc => <<-EOS
Deletes all instances of a given value from a hash.

*Examples:*

    delete_values({'a'=>'A','b'=>'B','c'=>'C','B'=>'D'}, 'B')

Would return: {'a'=>'A','c'=>'C','B'=>'D'}

      EOS
    ) do |arguments|

    raise(Puppet::ParseError,
          "delete_values(): Wrong number of arguments given " +
          "(#{arguments.size} of 2)") if arguments.size != 2

    hash, item = arguments

    if not hash.is_a?(Hash)
      raise(TypeError, "delete_values(): First argument must be a Hash. " + \
                       "Given an argument of class #{hash.class}.")
    end
    hash.dup.delete_if { |key, val| item == val }
  end
end
#
# difference.rb
#

module Puppet::Parser::Functions
  newfunction(:difference, :type => :rvalue, :doc => <<-EOS
This function returns the difference between two arrays.
The returned array is a copy of the original array, removing any items that
also appear in the second array.

*Examples:*

    difference(["a","b","c"],["b","c","d"])

Would return: ["a"]
    EOS
  ) do |arguments|

    # Two arguments are required
    raise(Puppet::ParseError, "difference(): Wrong number of arguments " +
      "given (#{arguments.size} for 2)") if arguments.size != 2

    first = arguments[0]
    second = arguments[1]

    unless first.is_a?(Array) && second.is_a?(Array)
      raise(Puppet::ParseError, 'difference(): Requires 2 arrays')
    end

    result = first - second

    return result
  end
end

# vim: set ts=2 sw=2 et :
module Puppet::Parser::Functions
  newfunction(:dirname, :type => :rvalue, :doc => <<-EOS
    Returns the dirname of a path.
    EOS
  ) do |arguments|

    raise(Puppet::ParseError, "dirname(): Wrong number of arguments " +
      "given (#{arguments.size} for 1)") if arguments.size < 1

    path = arguments[0]
    return File.dirname(path)
  end
end

# vim: set ts=2 sw=2 et :
#
#  downcase.rb
#

module Puppet::Parser::Functions
  newfunction(:downcase, :type => :rvalue, :doc => <<-EOS
Converts the case of a string or all strings in an array to lower case.
    EOS
  ) do |arguments|

    raise(Puppet::ParseError, "downcase(): Wrong number of arguments " +
      "given (#{arguments.size} for 1)") if arguments.size < 1

    value = arguments[0]

    unless value.is_a?(Array) || value.is_a?(String)
      raise(Puppet::ParseError, 'downcase(): Requires either ' +
        'array or string to work with')
    end

    if value.is_a?(Array)
      # Numbers in Puppet are often string-encoded which is troublesome ...
      result = value.collect { |i| i.is_a?(String) ? i.downcase : i }
    else
      result = value.downcase
    end

    return result
  end
end

# vim: set ts=2 sw=2 et :
#
# empty.rb
#

module Puppet::Parser::Functions
  newfunction(:empty, :type => :rvalue, :doc => <<-EOS
Returns true if the variable is empty.
    EOS
  ) do |arguments|

    raise(Puppet::ParseError, "empty(): Wrong number of arguments " +
      "given (#{arguments.size} for 1)") if arguments.size < 1

    value = arguments[0]

    unless value.is_a?(Array) || value.is_a?(Hash) || value.is_a?(String)
      raise(Puppet::ParseError, 'empty(): Requires either ' +
        'array, hash or string to work with')
    end

    result = value.empty?

    return result
  end
end

# vim: set ts=2 sw=2 et :
#
# ensure_packages.rb
#

module Puppet::Parser::Functions
  newfunction(:ensure_packages, :type => :statement, :doc => <<-EOS
Takes a list of packages and only installs them if they don't already exist.
It optionally takes a hash as a second parameter that will be passed as the
third argument to the ensure_resource() function.
    EOS
  ) do |arguments|

    if arguments.size > 2 or arguments.size == 0
      raise(Puppet::ParseError, "ensure_packages(): Wrong number of arguments " +
        "given (#{arguments.size} for 1 or 2)")
    elsif arguments.size == 2 and !arguments[1].is_a?(Hash) 
      raise(Puppet::ParseError, 'ensure_packages(): Requires second argument to be a Hash')
    end

    packages = Array(arguments[0])

    if arguments[1]
      defaults = { 'ensure' => 'present' }.merge(arguments[1])
    else
      defaults = { 'ensure' => 'present' }
    end

    Puppet::Parser::Functions.function(:ensure_resource)
    packages.each { |package_name|
      function_ensure_resource(['package', package_name, defaults ])
    }
  end
end

# vim: set ts=2 sw=2 et :
# Test whether a given class or definition is defined
require 'puppet/parser/functions'

Puppet::Parser::Functions.newfunction(:ensure_resource,
                                      :type => :statement,
                                      :doc => <<-'ENDOFDOC'
Takes a resource type, title, and a list of attributes that describe a
resource.

    user { 'dan':
      ensure => present,
    }

This example only creates the resource if it does not already exist:

    ensure_resource('user', 'dan', {'ensure' => 'present' })

If the resource already exists but does not match the specified parameters,
this function will attempt to recreate the resource leading to a duplicate
resource definition error.

An array of resources can also be passed in and each will be created with
the type and parameters specified if it doesn't already exist.

    ensure_resource('user', ['dan','alex'], {'ensure' => 'present'})

ENDOFDOC
) do |vals|
  type, title, params = vals
  raise(ArgumentError, 'Must specify a type') unless type
  raise(ArgumentError, 'Must specify a title') unless title
  params ||= {}

  items = [title].flatten

  items.each do |item|
    Puppet::Parser::Functions.function(:defined_with_params)
    if function_defined_with_params(["#{type}[#{item}]", params])
      Puppet.debug("Resource #{type}[#{item}] not created because it already exists")
    else
      Puppet::Parser::Functions.function(:create_resources)
      function_create_resources([type.capitalize, { item => params }])
    end
  end
end
#
# flatten.rb
#

module Puppet::Parser::Functions
  newfunction(:flatten, :type => :rvalue, :doc => <<-EOS
This function flattens any deeply nested arrays and returns a single flat array
as a result.

*Examples:*

    flatten(['a', ['b', ['c']]])

Would return: ['a','b','c']
    EOS
  ) do |arguments|

    raise(Puppet::ParseError, "flatten(): Wrong number of arguments " +
      "given (#{arguments.size} for 1)") if arguments.size != 1

    array = arguments[0]

    unless array.is_a?(Array)
      raise(Puppet::ParseError, 'flatten(): Requires array to work with')
    end

    result = array.flatten

    return result
  end
end

# vim: set ts=2 sw=2 et :
module Puppet::Parser::Functions
  newfunction(:floor, :type => :rvalue, :doc => <<-EOS
    Returns the largest integer less or equal to the argument.
    Takes a single numeric value as an argument.
    EOS
  ) do |arguments|

    raise(Puppet::ParseError, "floor(): Wrong number of arguments " +
          "given (#{arguments.size} for 1)") if arguments.size != 1

    begin
      arg = Float(arguments[0])
    rescue TypeError, ArgumentError => e
      raise(Puppet::ParseError, "floor(): Wrong argument type " +
            "given (#{arguments[0]} for Numeric)")
    end

    raise(Puppet::ParseError, "floor(): Wrong argument type " +
          "given (#{arg.class} for Numeric)") if arg.is_a?(Numeric) == false

    arg.floor
  end
end

# vim: set ts=2 sw=2 et :
#
# fqdn_rotate.rb
#

module Puppet::Parser::Functions
  newfunction(:fqdn_rotate, :type => :rvalue, :doc => <<-EOS
Rotates an array a random number of times based on a nodes fqdn.
    EOS
  ) do |arguments|

    raise(Puppet::ParseError, "fqdn_rotate(): Wrong number of arguments " +
      "given (#{arguments.size} for 1)") if arguments.size < 1

    value = arguments[0]
    require 'digest/md5'

    unless value.is_a?(Array) || value.is_a?(String)
      raise(Puppet::ParseError, 'fqdn_rotate(): Requires either ' +
        'array or string to work with')
    end

    result = value.clone

    string = value.is_a?(String) ? true : false

    # Check whether it makes sense to rotate ...
    return result if result.size <= 1

    # We turn any string value into an array to be able to rotate ...
    result = string ? result.split('') : result

    elements = result.size

    srand(Digest::MD5.hexdigest([lookupvar('::fqdn'),arguments].join(':')).hex)
    rand(elements).times {
       result.push result.shift
    }

    result = string ? result.join : result

    return result
  end
end

# vim: set ts=2 sw=2 et :
module Puppet::Parser::Functions
  newfunction(:get_module_path, :type =>:rvalue, :doc => <<-EOT
    Returns the absolute path of the specified module for the current
    environment.

    Example:
      $module_path = get_module_path('stdlib')
  EOT
  ) do |args|
    raise(Puppet::ParseError, "get_module_path(): Wrong number of arguments, expects one") unless args.size == 1
    if module_path = Puppet::Module.find(args[0], compiler.environment.to_s)
      module_path.path
    else
      raise(Puppet::ParseError, "Could not find module #{args[0]} in environment #{compiler.environment}")
    end
  end
end
# Test whether a given class or definition is defined
require 'puppet/parser/functions'

Puppet::Parser::Functions.newfunction(:getparam,
                                      :type => :rvalue,
                                      :doc => <<-'ENDOFDOC'
Takes a resource reference and name of the parameter and
returns value of resource's parameter.

*Examples:*

    define example_resource($param) {
    }

    example_resource { "example_resource_instance":
        param => "param_value"
    }

    getparam(Example_resource["example_resource_instance"], "param")

Would return: param_value
ENDOFDOC
) do |vals|
  reference, param = vals
  raise(ArgumentError, 'Must specify a reference') unless reference
  raise(ArgumentError, 'Must specify name of a parameter') unless param and param.instance_of? String

  return '' if param.empty?

  if resource = findresource(reference.to_s)
    return resource[param] if resource[param]
  end

  return ''
end
module Puppet::Parser::Functions

  newfunction(:getvar, :type => :rvalue, :doc => <<-'ENDHEREDOC') do |args|
    Lookup a variable in a remote namespace.

    For example:

        $foo = getvar('site::data::foo')
        # Equivalent to $foo = $site::data::foo

    This is useful if the namespace itself is stored in a string:

        $datalocation = 'site::data'
        $bar = getvar("${datalocation}::bar")
        # Equivalent to $bar = $site::data::bar
    ENDHEREDOC

    unless args.length == 1
      raise Puppet::ParseError, ("getvar(): wrong number of arguments (#{args.length}; must be 1)")
    end

    begin
      self.lookupvar("#{args[0]}")
    rescue Puppet::ParseError # Eat the exception if strict_variables = true is set
    end

  end

end
#
# grep.rb
#

module Puppet::Parser::Functions
  newfunction(:grep, :type => :rvalue, :doc => <<-EOS
This function searches through an array and returns any elements that match
the provided regular expression.

*Examples:*

    grep(['aaa','bbb','ccc','aaaddd'], 'aaa')

Would return:

    ['aaa','aaaddd']
    EOS
  ) do |arguments|

    if (arguments.size != 2) then
      raise(Puppet::ParseError, "grep(): Wrong number of arguments "+
        "given #{arguments.size} for 2")
    end

    a = arguments[0]
    pattern = Regexp.new(arguments[1])

    a.grep(pattern)

  end
end

# vim: set ts=2 sw=2 et :
#
# has_interface_with
#

module Puppet::Parser::Functions
  newfunction(:has_interface_with, :type => :rvalue, :doc => <<-EOS
Returns boolean based on kind and value:
  * macaddress
  * netmask
  * ipaddress
  * network

has_interface_with("macaddress", "x:x:x:x:x:x")
has_interface_with("ipaddress", "127.0.0.1")    => true
etc.

If no "kind" is given, then the presence of the interface is checked:
has_interface_with("lo")                        => true
    EOS
  ) do |args|

    raise(Puppet::ParseError, "has_interface_with(): Wrong number of arguments " +
          "given (#{args.size} for 1 or 2)") if args.size < 1 or args.size > 2

    interfaces = lookupvar('interfaces')

    # If we do not have any interfaces, then there are no requested attributes
    return false if (interfaces == :undefined || interfaces.nil?)

    interfaces = interfaces.split(',')

    if args.size == 1
      return interfaces.member?(args[0])
    end

    kind, value = args

    # Bug with 3.7.1 - 3.7.3  when using future parser throws :undefined_variable
    # https://tickets.puppetlabs.com/browse/PUP-3597
    factval = nil
    catch :undefined_variable do
      factval = lookupvar(kind)
    end
    if factval == value
      return true
    end

    result = false
    interfaces.each do |iface|
      iface.downcase!
      factval = nil
      begin
        # Bug with 3.7.1 - 3.7.3 when using future parser throws :undefined_variable
        # https://tickets.puppetlabs.com/browse/PUP-3597
        catch :undefined_variable do
          factval = lookupvar("#{kind}_#{iface}")
        end
      rescue Puppet::ParseError # Eat the exception if strict_variables = true is set
      end
      if value == factval
        result = true
        break
      end
    end

    result
  end
end
#
# has_ip_address
#

module Puppet::Parser::Functions
  newfunction(:has_ip_address, :type => :rvalue, :doc => <<-EOS
Returns true if the client has the requested IP address on some interface.

This function iterates through the 'interfaces' fact and checks the
'ipaddress_IFACE' facts, performing a simple string comparison.
    EOS
  ) do |args|

    raise(Puppet::ParseError, "has_ip_address(): Wrong number of arguments " +
          "given (#{args.size} for 1)") if args.size != 1

    Puppet::Parser::Functions.autoloader.load(:has_interface_with) \
      unless Puppet::Parser::Functions.autoloader.loaded?(:has_interface_with)

    function_has_interface_with(['ipaddress', args[0]])

  end
end

# vim:sts=2 sw=2
#
# has_ip_network
#

module Puppet::Parser::Functions
  newfunction(:has_ip_network, :type => :rvalue, :doc => <<-EOS
Returns true if the client has an IP address within the requested network.

This function iterates through the 'interfaces' fact and checks the
'network_IFACE' facts, performing a simple string comparision.
    EOS
  ) do |args|

    raise(Puppet::ParseError, "has_ip_network(): Wrong number of arguments " +
          "given (#{args.size} for 1)") if args.size != 1

    Puppet::Parser::Functions.autoloader.load(:has_interface_with) \
      unless Puppet::Parser::Functions.autoloader.loaded?(:has_interface_with)

    function_has_interface_with(['network', args[0]])

  end
end

# vim:sts=2 sw=2
module Puppet::Parser::Functions

  newfunction(:has_key, :type => :rvalue, :doc => <<-'ENDHEREDOC') do |args|
    Determine if a hash has a certain key value.

    Example:

        $my_hash = {'key_one' => 'value_one'}
        if has_key($my_hash, 'key_two') {
          notice('we will not reach here')
        }
        if has_key($my_hash, 'key_one') {
          notice('this will be printed')
        }

    ENDHEREDOC

    unless args.length == 2
      raise Puppet::ParseError, ("has_key(): wrong number of arguments (#{args.length}; must be 2)")
    end
    unless args[0].is_a?(Hash)
      raise Puppet::ParseError, "has_key(): expects the first argument to be a hash, got #{args[0].inspect} which is of type #{args[0].class}"
    end
    args[0].has_key?(args[1])

  end

end
#
# hash.rb
#

module Puppet::Parser::Functions
  newfunction(:hash, :type => :rvalue, :doc => <<-EOS
This function converts an array into a hash.

*Examples:*

    hash(['a',1,'b',2,'c',3])

Would return: {'a'=>1,'b'=>2,'c'=>3}
    EOS
  ) do |arguments|

    raise(Puppet::ParseError, "hash(): Wrong number of arguments " +
      "given (#{arguments.size} for 1)") if arguments.size < 1

    array = arguments[0]

    unless array.is_a?(Array)
      raise(Puppet::ParseError, 'hash(): Requires array to work with')
    end

    result = {}

    begin
      # This is to make it compatible with older version of Ruby ...
      array  = array.flatten
      result = Hash[*array]
    rescue Exception
      raise(Puppet::ParseError, 'hash(): Unable to compute ' +
        'hash from array given')
    end

    return result
  end
end

# vim: set ts=2 sw=2 et :
#
# intersection.rb
#

module Puppet::Parser::Functions
  newfunction(:intersection, :type => :rvalue, :doc => <<-EOS
This function returns an array an intersection of two.

*Examples:*

    intersection(["a","b","c"],["b","c","d"])

Would return: ["b","c"]
    EOS
  ) do |arguments|

    # Two arguments are required
    raise(Puppet::ParseError, "intersection(): Wrong number of arguments " +
      "given (#{arguments.size} for 2)") if arguments.size != 2

    first = arguments[0]
    second = arguments[1]

    unless first.is_a?(Array) && second.is_a?(Array)
      raise(Puppet::ParseError, 'intersection(): Requires 2 arrays')
    end

    result = first & second

    return result
  end
end

# vim: set ts=2 sw=2 et :
#
# is_array.rb
#

module Puppet::Parser::Functions
  newfunction(:is_array, :type => :rvalue, :doc => <<-EOS
Returns true if the variable passed to this function is an array.
    EOS
  ) do |arguments|

    raise(Puppet::ParseError, "is_array(): Wrong number of arguments " +
      "given (#{arguments.size} for 1)") if arguments.size < 1

    type = arguments[0]

    result = type.is_a?(Array)

    return result
  end
end

# vim: set ts=2 sw=2 et :
#
# is_bool.rb
#

module Puppet::Parser::Functions
  newfunction(:is_bool, :type => :rvalue, :doc => <<-EOS
Returns true if the variable passed to this function is a boolean.
    EOS
  ) do |arguments|

    raise(Puppet::ParseError, "is_bool(): Wrong number of arguments " +
      "given (#{arguments.size} for 1)") if arguments.size != 1

    type = arguments[0]

    result = type.is_a?(TrueClass) || type.is_a?(FalseClass)

    return result
  end
end

# vim: set ts=2 sw=2 et :
#
# is_domain_name.rb
#

module Puppet::Parser::Functions
  newfunction(:is_domain_name, :type => :rvalue, :doc => <<-EOS
Returns true if the string passed to this function is a syntactically correct domain name.
    EOS
  ) do |arguments|

    if (arguments.size != 1) then
      raise(Puppet::ParseError, "is_domain_name(): Wrong number of arguments "+
        "given #{arguments.size} for 1")
    end

    domain = arguments[0]

    # Limits (rfc1035, 3.1)
    domain_max_length=255
    label_min_length=1
    label_max_length=63

    # Only allow string types
    return false unless domain.is_a?(String)

    # Allow ".", it is the top level domain
    return true if domain == '.'

    # Remove the final dot, if present.
    domain.chomp!('.')

    # Check the whole domain
    return false if domain.empty?
    return false if domain.length > domain_max_length

    # Check each label in the domain
    labels = domain.split('.')
    vlabels = labels.each do |label|
      break if label.length < label_min_length
      break if label.length > label_max_length
      break if label[-1..-1] == '-'
      break if label[0..0] == '-'
      break unless /^[a-z\d-]+$/i.match(label)
    end
    return vlabels == labels

  end
end

# vim: set ts=2 sw=2 et :
#
# is_float.rb
#

module Puppet::Parser::Functions
  newfunction(:is_float, :type => :rvalue, :doc => <<-EOS
Returns true if the variable passed to this function is a float.
    EOS
  ) do |arguments|

    if (arguments.size != 1) then
      raise(Puppet::ParseError, "is_float(): Wrong number of arguments "+
        "given #{arguments.size} for 1")
    end

    value = arguments[0]

    # Only allow Numeric or String types
    return false unless value.is_a?(Numeric) or value.is_a?(String)

    if value != value.to_f.to_s and !value.is_a? Float then
      return false
    else
      return true
    end

  end
end

# vim: set ts=2 sw=2 et :
#
# is_function_available.rb
#

module Puppet::Parser::Functions
  newfunction(:is_function_available, :type => :rvalue, :doc => <<-EOS
This function accepts a string as an argument, determines whether the
Puppet runtime has access to a function by that name.  It returns a
true if the function exists, false if not.
    EOS
  ) do |arguments|

    if (arguments.size != 1) then
      raise(Puppet::ParseError, "is_function_available?(): Wrong number of arguments "+
        "given #{arguments.size} for 1")
    end

    # Only allow String types
    return false unless arguments[0].is_a?(String)

    function = Puppet::Parser::Functions.function(arguments[0].to_sym)
    function.is_a?(String) and not function.empty?
  end
end

# vim: set ts=2 sw=2 et :
#
# is_hash.rb
#

module Puppet::Parser::Functions
  newfunction(:is_hash, :type => :rvalue, :doc => <<-EOS
Returns true if the variable passed to this function is a hash.
    EOS
  ) do |arguments|

    raise(Puppet::ParseError, "is_hash(): Wrong number of arguments " +
      "given (#{arguments.size} for 1)") if arguments.size != 1

    type = arguments[0]

    result = type.is_a?(Hash)

    return result
  end
end

# vim: set ts=2 sw=2 et :
#
# is_integer.rb
#

module Puppet::Parser::Functions
  newfunction(:is_integer, :type => :rvalue, :doc => <<-EOS
Returns true if the variable passed to this function is an Integer or
a decimal (base 10) integer in String form. The string may
start with a '-' (minus). A value of '0' is allowed, but a leading '0' digit may not
be followed by other digits as this indicates that the value is octal (base 8).

If given any other argument `false` is returned.
    EOS
  ) do |arguments|

    if (arguments.size != 1) then
      raise(Puppet::ParseError, "is_integer(): Wrong number of arguments "+
        "given #{arguments.size} for 1")
    end

    value = arguments[0]

    # Regex is taken from the lexer of puppet
    # puppet/pops/parser/lexer.rb but modified to match also
    # negative values and disallow numbers prefixed with multiple
    # 0's
    #
    # TODO these parameter should be a constant but I'm not sure
    # if there is no risk to declare it inside of the module
    # Puppet::Parser::Functions

    # Integer numbers like
    # -1234568981273
    # 47291
    numeric = %r{^-?(?:(?:[1-9]\d*)|0)$}

    if value.is_a? Integer or (value.is_a? String and value.match numeric)
      return true
    else
      return false
    end
  end
end

# vim: set ts=2 sw=2 et :
#
# is_ip_address.rb
#

module Puppet::Parser::Functions
  newfunction(:is_ip_address, :type => :rvalue, :doc => <<-EOS
Returns true if the string passed to this function is a valid IP address.
    EOS
  ) do |arguments|

    require 'ipaddr'

    if (arguments.size != 1) then
      raise(Puppet::ParseError, "is_ip_address(): Wrong number of arguments "+
        "given #{arguments.size} for 1")
    end

    begin
      ip = IPAddr.new(arguments[0])
    rescue ArgumentError
      return false
    end

    if ip.ipv4? or ip.ipv6? then
      return true
    else
      return false
    end
  end
end

# vim: set ts=2 sw=2 et :
#
# is_mac_address.rb
#

module Puppet::Parser::Functions
  newfunction(:is_mac_address, :type => :rvalue, :doc => <<-EOS
Returns true if the string passed to this function is a valid mac address.
    EOS
  ) do |arguments|

    if (arguments.size != 1) then
      raise(Puppet::ParseError, "is_mac_address(): Wrong number of arguments "+
        "given #{arguments.size} for 1")
    end

    mac = arguments[0]

    if /^[a-fA-F0-9]{1,2}:[a-fA-F0-9]{1,2}:[a-fA-F0-9]{1,2}:[a-fA-F0-9]{1,2}:[a-fA-F0-9]{1,2}:[a-fA-F0-9]{1,2}$/.match(mac) then
      return true
    else
      return false
    end

  end
end

# vim: set ts=2 sw=2 et :
#
# is_numeric.rb
#

module Puppet::Parser::Functions
  newfunction(:is_numeric, :type => :rvalue, :doc => <<-EOS
Returns true if the given argument is a Numeric (Integer or Float),
or a String containing either a valid integer in decimal base 10 form, or
a valid floating point string representation.

The function recognizes only decimal (base 10) integers and float but not
integers in hex (base 16) or octal (base 8) form.

The string representation may start with a '-' (minus). If a decimal '.' is used,
it must be followed by at least one digit.

Valid examples:

  77435
  10e-12
  -8475
  0.2343
  -23.561e3
    EOS
  ) do |arguments|

    if (arguments.size != 1) then
      raise(Puppet::ParseError, "is_numeric(): Wrong number of arguments "+
        "given #{arguments.size} for 1")
    end

    value = arguments[0]

    # Regex is taken from the lexer of puppet
    # puppet/pops/parser/lexer.rb but modified to match also
    # negative values and disallow invalid octal numbers or
    # numbers prefixed with multiple 0's (except in hex numbers)
    #
    # TODO these parameters should be constants but I'm not sure
    # if there is no risk to declare them inside of the module
    # Puppet::Parser::Functions

    # TODO decide if this should be used
    # HEX numbers like
    # 0xaa230F
    # 0X1234009C
    # 0x0012
    # -12FcD
    #numeric_hex = %r{^-?0[xX][0-9A-Fa-f]+$}

    # TODO decide if this should be used
    # OCTAL numbers like
    # 01234567
    # -045372
    #numeric_oct = %r{^-?0[1-7][0-7]*$}

    # Integer/Float numbers like
    # -0.1234568981273
    # 47291
    # 42.12345e-12
    numeric = %r{^-?(?:(?:[1-9]\d*)|0)(?:\.\d+)?(?:[eE]-?\d+)?$}

    if value.is_a? Numeric or (value.is_a? String and (
      value.match(numeric) #or
    #  value.match(numeric_hex) or
    #  value.match(numeric_oct)
    ))
      return true
    else
      return false
    end
  end
end

# vim: set ts=2 sw=2 et :
#
# is_string.rb
#

module Puppet::Parser::Functions
  newfunction(:is_string, :type => :rvalue, :doc => <<-EOS
Returns true if the variable passed to this function is a string.
    EOS
  ) do |arguments|

    raise(Puppet::ParseError, "is_string(): Wrong number of arguments " +
      "given (#{arguments.size} for 1)") if arguments.size < 1

    type = arguments[0]

    result = type.is_a?(String)

    if result and (type == type.to_f.to_s or type == type.to_i.to_s) then
      return false
    end

    return result
  end
end

# vim: set ts=2 sw=2 et :
#
# join.rb
#

module Puppet::Parser::Functions
  newfunction(:join, :type => :rvalue, :doc => <<-EOS
This function joins an array into a string using a separator.

*Examples:*

    join(['a','b','c'], ",")

Would result in: "a,b,c"
    EOS
  ) do |arguments|

    # Technically we support two arguments but only first is mandatory ...
    raise(Puppet::ParseError, "join(): Wrong number of arguments " +
      "given (#{arguments.size} for 1)") if arguments.size < 1

    array = arguments[0]

    unless array.is_a?(Array)
      raise(Puppet::ParseError, 'join(): Requires array to work with')
    end

    suffix = arguments[1] if arguments[1]

    if suffix
      unless suffix.is_a?(String)
        raise(Puppet::ParseError, 'join(): Requires string to work with')
      end
    end

    result = suffix ? array.join(suffix) : array.join

    return result
  end
end

# vim: set ts=2 sw=2 et :
#
# join.rb
#

module Puppet::Parser::Functions
  newfunction(:join_keys_to_values, :type => :rvalue, :doc => <<-EOS
This function joins each key of a hash to that key's corresponding value with a
separator. Keys and values are cast to strings. The return value is an array in
which each element is one joined key/value pair.

*Examples:*

    join_keys_to_values({'a'=>1,'b'=>2}, " is ")

Would result in: ["a is 1","b is 2"]
    EOS
  ) do |arguments|

    # Validate the number of arguments.
    if arguments.size != 2
      raise(Puppet::ParseError, "join_keys_to_values(): Takes exactly two " +
            "arguments, but #{arguments.size} given.")
    end

    # Validate the first argument.
    hash = arguments[0]
    if not hash.is_a?(Hash)
      raise(TypeError, "join_keys_to_values(): The first argument must be a " +
            "hash, but a #{hash.class} was given.")
    end

    # Validate the second argument.
    separator = arguments[1]
    if not separator.is_a?(String)
      raise(TypeError, "join_keys_to_values(): The second argument must be a " +
            "string, but a #{separator.class} was given.")
    end

    # Join the keys to their values.
    hash.map do |k,v|
      String(k) + separator + String(v)
    end

  end
end

# vim: set ts=2 sw=2 et :
#
# keys.rb
#

module Puppet::Parser::Functions
  newfunction(:keys, :type => :rvalue, :doc => <<-EOS
Returns the keys of a hash as an array.
    EOS
  ) do |arguments|

    raise(Puppet::ParseError, "keys(): Wrong number of arguments " +
      "given (#{arguments.size} for 1)") if arguments.size < 1

    hash = arguments[0]

    unless hash.is_a?(Hash)
      raise(Puppet::ParseError, 'keys(): Requires hash to work with')
    end

    result = hash.keys

    return result
  end
end

# vim: set ts=2 sw=2 et :
module Puppet::Parser::Functions

  newfunction(:loadyaml, :type => :rvalue, :doc => <<-'ENDHEREDOC') do |args|
    Load a YAML file containing an array, string, or hash, and return the data
    in the corresponding native data type.

    For example:

        $myhash = loadyaml('/etc/puppet/data/myhash.yaml')
    ENDHEREDOC

    unless args.length == 1
      raise Puppet::ParseError, ("loadyaml(): wrong number of arguments (#{args.length}; must be 1)")
    end

    YAML.load_file(args[0])

  end

end
#
#  lstrip.rb
#

module Puppet::Parser::Functions
  newfunction(:lstrip, :type => :rvalue, :doc => <<-EOS
Strips leading spaces to the left of a string.
    EOS
  ) do |arguments|

    raise(Puppet::ParseError, "lstrip(): Wrong number of arguments " +
      "given (#{arguments.size} for 1)") if arguments.size < 1

    value = arguments[0]

    unless value.is_a?(Array) || value.is_a?(String)
      raise(Puppet::ParseError, 'lstrip(): Requires either ' +
        'array or string to work with')
    end

    if value.is_a?(Array)
      # Numbers in Puppet are often string-encoded which is troublesome ...
      result = value.collect { |i| i.is_a?(String) ? i.lstrip : i }
    else
      result = value.lstrip
    end

    return result
  end
end

# vim: set ts=2 sw=2 et :
module Puppet::Parser::Functions
  newfunction(:max, :type => :rvalue, :doc => <<-EOS
    Returns the highest value of all arguments.
    Requires at least one argument.
    EOS
  ) do |args|

    raise(Puppet::ParseError, "max(): Wrong number of arguments " +
          "need at least one") if args.size == 0

    # Sometimes we get numbers as numerics and sometimes as strings.
    # We try to compare them as numbers when possible
    return args.max do |a,b|
      if a.to_s =~ /\A-?\d+(.\d+)?\z/ and b.to_s =~ /\A-?\d+(.\d+)?\z/ then
        a.to_f <=> b.to_f
      else
        a.to_s <=> b.to_s
      end
    end
  end
end
#
# member.rb
#

# TODO(Krzysztof Wilczynski): We need to add support for regular expression ...
# TODO(Krzysztof Wilczynski): Support for strings and hashes too ...

module Puppet::Parser::Functions
  newfunction(:member, :type => :rvalue, :doc => <<-EOS
This function determines if a variable is a member of an array.

*Examples:*

    member(['a','b'], 'b')

Would return: true

    member(['a','b'], 'c')

Would return: false
    EOS
  ) do |arguments|

    raise(Puppet::ParseError, "member(): Wrong number of arguments " +
      "given (#{arguments.size} for 2)") if arguments.size < 2

    array = arguments[0]

    unless array.is_a?(Array)
      raise(Puppet::ParseError, 'member(): Requires array to work with')
    end

    item = arguments[1]


    raise(Puppet::ParseError, 'member(): You must provide item ' +
      'to search for within array given') if item.respond_to?('empty?') && item.empty?

    result = array.include?(item)

    return result
  end
end

# vim: set ts=2 sw=2 et :
module Puppet::Parser::Functions
  newfunction(:merge, :type => :rvalue, :doc => <<-'ENDHEREDOC') do |args|
    Merges two or more hashes together and returns the resulting hash.

    For example:

        $hash1 = {'one' => 1, 'two', => 2}
        $hash2 = {'two' => 'dos', 'three', => 'tres'}
        $merged_hash = merge($hash1, $hash2)
        # The resulting hash is equivalent to:
        # $merged_hash =  {'one' => 1, 'two' => 'dos', 'three' => 'tres'}

    When there is a duplicate key, the key in the rightmost hash will "win."

    ENDHEREDOC

    if args.length < 2
      raise Puppet::ParseError, ("merge(): wrong number of arguments (#{args.length}; must be at least 2)")
    end

    # The hash we accumulate into
    accumulator = Hash.new
    # Merge into the accumulator hash
    args.each do |arg|
      next if arg.is_a? String and arg.empty? # empty string is synonym for puppet's undef
      unless arg.is_a?(Hash)
        raise Puppet::ParseError, "merge: unexpected argument type #{arg.class}, only expects hash arguments"
      end
      accumulator.merge!(arg)
    end
    # Return the fully merged hash
    accumulator
  end
end
module Puppet::Parser::Functions
  newfunction(:min, :type => :rvalue, :doc => <<-EOS
    Returns the lowest value of all arguments.
    Requires at least one argument.
    EOS
  ) do |args|

    raise(Puppet::ParseError, "min(): Wrong number of arguments " +
          "need at least one") if args.size == 0

    # Sometimes we get numbers as numerics and sometimes as strings.
    # We try to compare them as numbers when possible
    return args.min do |a,b|
      if a.to_s =~ /\A^-?\d+(.\d+)?\z/ and b.to_s =~ /\A-?\d+(.\d+)?\z/ then
        a.to_f <=> b.to_f
      else
        a.to_s <=> b.to_s
      end
    end
  end
end
#
# num2bool.rb
#

module Puppet::Parser::Functions
  newfunction(:num2bool, :type => :rvalue, :doc => <<-EOS
This function converts a number or a string representation of a number into a
true boolean. Zero or anything non-numeric becomes false. Numbers higher then 0
become true.
    EOS
  ) do |arguments|

    raise(Puppet::ParseError, "num2bool(): Wrong number of arguments " +
      "given (#{arguments.size} for 1)") if arguments.size != 1

    number = arguments[0]

    case number
    when Numeric
      # Yay, it's a number
    when String
      begin
        number = Float(number)
      rescue ArgumentError => ex
        raise(Puppet::ParseError, "num2bool(): '#{number}' does not look like a number: #{ex.message}")
      end
    else
      begin
        number = number.to_s
      rescue NoMethodError => ex
        raise(Puppet::ParseError, "num2bool(): Unable to parse argument: #{ex.message}")
      end
    end

    # Truncate Floats
    number = number.to_i

    # Return true for any positive number and false otherwise
    return number > 0
  end
end

# vim: set ts=2 sw=2 et :
#
# parsejson.rb
#

module Puppet::Parser::Functions
  newfunction(:parsejson, :type => :rvalue, :doc => <<-EOS
This function accepts JSON as a string and converts into the correct Puppet
structure.
    EOS
  ) do |arguments|

    if (arguments.size != 1) then
      raise(Puppet::ParseError, "parsejson(): Wrong number of arguments "+
        "given #{arguments.size} for 1")
    end

    json = arguments[0]

    # PSON is natively available in puppet
    PSON.load(json)
  end
end

# vim: set ts=2 sw=2 et :
#
# parseyaml.rb
#

module Puppet::Parser::Functions
  newfunction(:parseyaml, :type => :rvalue, :doc => <<-EOS
This function accepts YAML as a string and converts it into the correct
Puppet structure.
    EOS
  ) do |arguments|

    if (arguments.size != 1) then
      raise(Puppet::ParseError, "parseyaml(): Wrong number of arguments "+
        "given #{arguments.size} for 1")
    end

    require 'yaml'

    YAML::load(arguments[0])

  end
end

# vim: set ts=2 sw=2 et :
module Puppet::Parser::Functions
 newfunction(:pick, :type => :rvalue, :doc => <<-EOS

This function is similar to a coalesce function in SQL in that it will return
the first value in a list of values that is not undefined or an empty string
(two things in Puppet that will return a boolean false value). Typically,
this function is used to check for a value in the Puppet Dashboard/Enterprise
Console, and failover to a default value like the following:

  $real_jenkins_version = pick($::jenkins_version, '1.449')

The value of $real_jenkins_version will first look for a top-scope variable
called 'jenkins_version' (note that parameters set in the Puppet Dashboard/
Enterprise Console are brought into Puppet as top-scope variables), and,
failing that, will use a default value of 1.449.

EOS
) do |args|
   args = args.compact
   args.delete(:undef)
   args.delete(:undefined)
   args.delete("")
   if args[0].to_s.empty? then
     fail Puppet::ParseError, "pick(): must receive at least one non empty value"
   else
     return args[0]
   end
 end
end
module Puppet::Parser::Functions
 newfunction(:pick_default, :type => :rvalue, :doc => <<-EOS

This function is similar to a coalesce function in SQL in that it will return
the first value in a list of values that is not undefined or an empty string
(two things in Puppet that will return a boolean false value). If no value is
found, it will return the last argument.

Typically, this function is used to check for a value in the Puppet
Dashboard/Enterprise Console, and failover to a default value like the
following:

  $real_jenkins_version = pick_default($::jenkins_version, '1.449')

The value of $real_jenkins_version will first look for a top-scope variable
called 'jenkins_version' (note that parameters set in the Puppet Dashboard/
Enterprise Console are brought into Puppet as top-scope variables), and,
failing that, will use a default value of 1.449.

Note that, contrary to the pick() function, the pick_default does not fail if
all arguments are empty. This allows pick_default to use an empty value as
default.

EOS
) do |args|
   fail "Must receive at least one argument." if args.empty?
   default = args.last
   args = args[0..-2].compact
   args.delete(:undef)
   args.delete(:undefined)
   args.delete("")
   args << default
   return args[0]
 end
end
#
# prefix.rb
#

module Puppet::Parser::Functions
  newfunction(:prefix, :type => :rvalue, :doc => <<-EOS
This function applies a prefix to all elements in an array.

*Examples:*

    prefix(['a','b','c'], 'p')

Will return: ['pa','pb','pc']
    EOS
  ) do |arguments|

    # Technically we support two arguments but only first is mandatory ...
    raise(Puppet::ParseError, "prefix(): Wrong number of arguments " +
      "given (#{arguments.size} for 1)") if arguments.size < 1

    array = arguments[0]

    unless array.is_a?(Array)
      raise Puppet::ParseError, "prefix(): expected first argument to be an Array, got #{array.inspect}"
    end

    prefix = arguments[1] if arguments[1]

    if prefix
      unless prefix.is_a?(String)
        raise Puppet::ParseError, "prefix(): expected second argument to be a String, got #{prefix.inspect}"
      end
    end

    # Turn everything into string same as join would do ...
    result = array.collect do |i|
      i = i.to_s
      prefix ? prefix + i : i
    end

    return result
  end
end

# vim: set ts=2 sw=2 et :
#
# private.rb
#

module Puppet::Parser::Functions
  newfunction(:private, :doc => <<-'EOS'
    Sets the current class or definition as private.
    Calling the class or definition from outside the current module will fail.
    EOS
  ) do |args|

    raise(Puppet::ParseError, "private(): Wrong number of arguments "+
      "given (#{args.size}}) for 0 or 1)") if args.size > 1

    scope = self
    if scope.lookupvar('module_name') != scope.lookupvar('caller_module_name')
      message = nil
      if args[0] and args[0].is_a? String
        message = args[0]
      else
        manifest_name = scope.source.name
        manifest_type = scope.source.type
        message = (manifest_type.to_s == 'hostclass') ? 'Class' : 'Definition'
        message += " #{manifest_name} is private"
      end
      raise(Puppet::ParseError, message)
    end
  end
end
#
# range.rb
#

# TODO(Krzysztof Wilczynski): We probably need to approach numeric values differently ...

module Puppet::Parser::Functions
  newfunction(:range, :type => :rvalue, :doc => <<-EOS
When given range in the form of (start, stop) it will extrapolate a range as
an array.

*Examples:*

    range("0", "9")

Will return: [0,1,2,3,4,5,6,7,8,9]

    range("00", "09")

Will return: [0,1,2,3,4,5,6,7,8,9] (Zero padded strings are converted to
integers automatically)

    range("a", "c")

Will return: ["a","b","c"]

    range("host01", "host10")

Will return: ["host01", "host02", ..., "host09", "host10"]

Passing a third argument will cause the generated range to step by that
interval, e.g.

    range("0", "9", "2")

Will return: [0,2,4,6,8]
    EOS
  ) do |arguments|

    # We support more than one argument but at least one is mandatory ...
    raise(Puppet::ParseError, "range(): Wrong number of " +
      "arguments given (#{arguments.size} for 1)") if arguments.size < 1

    if arguments.size > 1
      start = arguments[0]
      stop  = arguments[1]
      step  = arguments[2].nil? ? 1 : arguments[2].to_i.abs

      type = '..' # We select simplest type for Range available in Ruby ...

    elsif arguments.size > 0
      value = arguments[0]

      if m = value.match(/^(\w+)(\.\.\.?|\-)(\w+)$/)
        start = m[1]
        stop  = m[3]

        type = m[2]

      elsif value.match(/^.+$/)
        raise(Puppet::ParseError, 'range(): Unable to compute range ' +
          'from the value given')
      else
        raise(Puppet::ParseError, 'range(): Unknown format of range given')
      end
    end

      # Check whether we have integer value if so then make it so ...
      if start.match(/^\d+$/)
        start = start.to_i
        stop  = stop.to_i
      else
        start = start.to_s
        stop  = stop.to_s
      end

      range = case type
        when /^(\.\.|\-)$/ then (start .. stop)
        when /^(\.\.\.)$/  then (start ... stop) # Exclusive of last element ...
      end

      result = range.step(step).collect { |i| i } # Get them all ... Pokemon ...

    return result
  end
end

# vim: set ts=2 sw=2 et :
#
# reject.rb
#

module Puppet::Parser::Functions
  newfunction(:reject, :type => :rvalue, :doc => <<-EOS) do |args|
This function searches through an array and rejects all elements that match
the provided regular expression.

*Examples:*

    reject(['aaa','bbb','ccc','aaaddd'], 'aaa')

Would return:

    ['bbb','ccc']
EOS

    if (args.size != 2)
      raise Puppet::ParseError,
        "reject(): Wrong number of arguments given #{args.size} for 2"
    end

    ary = args[0]
    pattern = Regexp.new(args[1])

    ary.reject { |e| e =~ pattern }
  end
end

# vim: set ts=2 sw=2 et :
#
# reverse.rb
#

module Puppet::Parser::Functions
  newfunction(:reverse, :type => :rvalue, :doc => <<-EOS
Reverses the order of a string or array.
    EOS
  ) do |arguments|

    raise(Puppet::ParseError, "reverse(): Wrong number of arguments " +
      "given (#{arguments.size} for 1)") if arguments.size < 1

    value = arguments[0]

    unless value.is_a?(Array) || value.is_a?(String)
      raise(Puppet::ParseError, 'reverse(): Requires either ' +
        'array or string to work with')
    end

    result = value.reverse

    return result
  end
end

# vim: set ts=2 sw=2 et :
#
#  rstrip.rb
#

module Puppet::Parser::Functions
  newfunction(:rstrip, :type => :rvalue, :doc => <<-EOS
Strips leading spaces to the right of the string.
    EOS
  ) do |arguments|

    raise(Puppet::ParseError, "rstrip(): Wrong number of arguments " +
      "given (#{arguments.size} for 1)") if arguments.size < 1

    value = arguments[0]

    unless value.is_a?(Array) || value.is_a?(String)
      raise(Puppet::ParseError, 'rstrip(): Requires either ' +
        'array or string to work with')
    end

    if value.is_a?(Array)
      result = value.collect { |i| i.is_a?(String) ? i.rstrip : i }
    else
      result = value.rstrip
    end

    return result
  end
end

# vim: set ts=2 sw=2 et :
#
# shuffle.rb
#

module Puppet::Parser::Functions
  newfunction(:shuffle, :type => :rvalue, :doc => <<-EOS
Randomizes the order of a string or array elements.
    EOS
  ) do |arguments|

    raise(Puppet::ParseError, "shuffle(): Wrong number of arguments " +
      "given (#{arguments.size} for 1)") if arguments.size < 1

    value = arguments[0]

    unless value.is_a?(Array) || value.is_a?(String)
      raise(Puppet::ParseError, 'shuffle(): Requires either ' +
        'array or string to work with')
    end

    result = value.clone

    string = value.is_a?(String) ? true : false

    # Check whether it makes sense to shuffle ...
    return result if result.size <= 1

    # We turn any string value into an array to be able to shuffle ...
    result = string ? result.split('') : result

    elements = result.size

    # Simple implementation of Fisher–Yates in-place shuffle ...
    elements.times do |i|
      j = rand(elements - i) + i
      result[j], result[i] = result[i], result[j]
    end

    result = string ? result.join : result

    return result
  end
end

# vim: set ts=2 sw=2 et :
#
# size.rb
#

# TODO(Krzysztof Wilczynski): Support for hashes would be nice too ...

module Puppet::Parser::Functions
  newfunction(:size, :type => :rvalue, :doc => <<-EOS
Returns the number of elements in a string or array.
    EOS
  ) do |arguments|

    raise(Puppet::ParseError, "size(): Wrong number of arguments " +
      "given (#{arguments.size} for 1)") if arguments.size < 1

    item = arguments[0]

    if item.is_a?(String)

      begin
        #
        # Check whether your item is a numeric value or not ...
        # This will take care about positive and/or negative numbers
        # for both integer and floating-point values ...
        #
        # Please note that Puppet has no notion of hexadecimal
        # nor octal numbers for its DSL at this point in time ...
        #
        Float(item)

        raise(Puppet::ParseError, 'size(): Requires either ' +
          'string or array to work with')

      rescue ArgumentError
        result = item.size
      end

    elsif item.is_a?(Array)
      result = item.size
    else
      raise(Puppet::ParseError, 'size(): Unknown type given')
    end

    return result
  end
end

# vim: set ts=2 sw=2 et :
#
# sort.rb
#

module Puppet::Parser::Functions
  newfunction(:sort, :type => :rvalue, :doc => <<-EOS
Sorts strings and arrays lexically.
    EOS
  ) do |arguments|

    if (arguments.size != 1) then
      raise(Puppet::ParseError, "sort(): Wrong number of arguments "+
        "given #{arguments.size} for 1")
    end

    value = arguments[0]

    if value.is_a?(Array) then
      value.sort
    elsif value.is_a?(String) then
      value.split("").sort.join("")
    end

  end
end

# vim: set ts=2 sw=2 et :
#
# squeeze.rb
#

module Puppet::Parser::Functions
  newfunction(:squeeze, :type => :rvalue, :doc => <<-EOS
Returns a new string where runs of the same character that occur in this set are replaced by a single character.
    EOS
  ) do |arguments|

    if ((arguments.size != 2) and (arguments.size != 1)) then
      raise(Puppet::ParseError, "squeeze(): Wrong number of arguments "+
        "given #{arguments.size} for 2 or 1")
    end

    item = arguments[0]
    squeezeval = arguments[1]

    if item.is_a?(Array) then
      if squeezeval then
        item.collect { |i| i.squeeze(squeezeval) }
      else
        item.collect { |i| i.squeeze }
      end
    else
      if squeezeval then
        item.squeeze(squeezeval)
      else
        item.squeeze
      end
    end

  end
end

# vim: set ts=2 sw=2 et :
#
# str2bool.rb
#

module Puppet::Parser::Functions
  newfunction(:str2bool, :type => :rvalue, :doc => <<-EOS
This converts a string to a boolean. This attempt to convert strings that
contain things like: y, 1, t, true to 'true' and strings that contain things
like: 0, f, n, false, no to 'false'.
    EOS
  ) do |arguments|

    raise(Puppet::ParseError, "str2bool(): Wrong number of arguments " +
      "given (#{arguments.size} for 1)") if arguments.size < 1

    string = arguments[0]

    # If string is already Boolean, return it
    if !!string == string
      return string
    end

    unless string.is_a?(String)
      raise(Puppet::ParseError, 'str2bool(): Requires either ' +
        'string to work with')
    end

    # We consider all the yes, no, y, n and so on too ...
    result = case string
      #
      # This is how undef looks like in Puppet ...
      # We yield false in this case.
      #
      when /^$/, '' then false # Empty string will be false ...
      when /^(1|t|y|true|yes)$/  then true
      when /^(0|f|n|false|no)$/  then false
      when /^(undef|undefined)$/ then false # This is not likely to happen ...
      else
        raise(Puppet::ParseError, 'str2bool(): Unknown type of boolean given')
    end

    return result
  end
end

# vim: set ts=2 sw=2 et :
#
# str2saltedsha512.rb
#

module Puppet::Parser::Functions
  newfunction(:str2saltedsha512, :type => :rvalue, :doc => <<-EOS
This converts a string to a salted-SHA512 password hash (which is used for
OS X versions >= 10.7). Given any simple string, you will get a hex version
of a salted-SHA512 password hash that can be inserted into your Puppet
manifests as a valid password attribute.
    EOS
  ) do |arguments|
    require 'digest/sha2'

    raise(Puppet::ParseError, "str2saltedsha512(): Wrong number of arguments " +
      "passed (#{arguments.size} but we require 1)") if arguments.size != 1

    password = arguments[0]

    unless password.is_a?(String)
      raise(Puppet::ParseError, 'str2saltedsha512(): Requires a ' +
        "String argument, you passed: #{password.class}")
    end

    seedint    = rand(2**31 - 1)
    seedstring = Array(seedint).pack("L")
    saltedpass = Digest::SHA512.digest(seedstring + password)
    (seedstring + saltedpass).unpack('H*')[0]
  end
end

# vim: set ts=2 sw=2 et :
#
# strftime.rb
#

module Puppet::Parser::Functions
  newfunction(:strftime, :type => :rvalue, :doc => <<-EOS
This function returns formatted time.

*Examples:*

To return the time since epoch:

    strftime("%s")

To return the date:

    strftime("%Y-%m-%d")

*Format meaning:*

    %a - The abbreviated weekday name (``Sun'')
    %A - The  full  weekday  name (``Sunday'')
    %b - The abbreviated month name (``Jan'')
    %B - The  full  month  name (``January'')
    %c - The preferred local date and time representation
    %C - Century (20 in 2009)
    %d - Day of the month (01..31)
    %D - Date (%m/%d/%y)
    %e - Day of the month, blank-padded ( 1..31)
    %F - Equivalent to %Y-%m-%d (the ISO 8601 date format)
    %h - Equivalent to %b
    %H - Hour of the day, 24-hour clock (00..23)
    %I - Hour of the day, 12-hour clock (01..12)
    %j - Day of the year (001..366)
    %k - hour, 24-hour clock, blank-padded ( 0..23)
    %l - hour, 12-hour clock, blank-padded ( 0..12)
    %L - Millisecond of the second (000..999)
    %m - Month of the year (01..12)
    %M - Minute of the hour (00..59)
    %n - Newline (\n)
    %N - Fractional seconds digits, default is 9 digits (nanosecond)
            %3N  millisecond (3 digits)
            %6N  microsecond (6 digits)
            %9N  nanosecond (9 digits)
    %p - Meridian indicator (``AM''  or  ``PM'')
    %P - Meridian indicator (``am''  or  ``pm'')
    %r - time, 12-hour (same as %I:%M:%S %p)
    %R - time, 24-hour (%H:%M)
    %s - Number of seconds since 1970-01-01 00:00:00 UTC.
    %S - Second of the minute (00..60)
    %t - Tab character (\t)
    %T - time, 24-hour (%H:%M:%S)
    %u - Day of the week as a decimal, Monday being 1. (1..7)
    %U - Week  number  of the current year,
            starting with the first Sunday as the first
            day of the first week (00..53)
    %v - VMS date (%e-%b-%Y)
    %V - Week number of year according to ISO 8601 (01..53)
    %W - Week  number  of the current year,
            starting with the first Monday as the first
            day of the first week (00..53)
    %w - Day of the week (Sunday is 0, 0..6)
    %x - Preferred representation for the date alone, no time
    %X - Preferred representation for the time alone, no date
    %y - Year without a century (00..99)
    %Y - Year with century
    %z - Time zone as  hour offset from UTC (e.g. +0900)
    %Z - Time zone name
    %% - Literal ``%'' character
    EOS
  ) do |arguments|

    # Technically we support two arguments but only first is mandatory ...
    raise(Puppet::ParseError, "strftime(): Wrong number of arguments " +
      "given (#{arguments.size} for 1)") if arguments.size < 1

    format = arguments[0]

    raise(Puppet::ParseError, 'strftime(): You must provide ' +
      'format for evaluation') if format.empty?

    # The Time Zone argument is optional ...
    time_zone = arguments[1] if arguments[1]

    time = Time.new

    # There is probably a better way to handle Time Zone ...
    if time_zone and not time_zone.empty?
      original_zone = ENV['TZ']

      local_time = time.clone
      local_time = local_time.utc

      ENV['TZ'] = time_zone

      time = local_time.localtime

      ENV['TZ'] = original_zone
    end

    result = time.strftime(format)

    return result
  end
end

# vim: set ts=2 sw=2 et :
#
#  strip.rb
#

module Puppet::Parser::Functions
  newfunction(:strip, :type => :rvalue, :doc => <<-EOS
This function removes leading and trailing whitespace from a string or from
every string inside an array.

*Examples:*

    strip("    aaa   ")

Would result in: "aaa"
    EOS
  ) do |arguments|

    raise(Puppet::ParseError, "strip(): Wrong number of arguments " +
      "given (#{arguments.size} for 1)") if arguments.size < 1

    value = arguments[0]

    unless value.is_a?(Array) || value.is_a?(String)
      raise(Puppet::ParseError, 'strip(): Requires either ' +
        'array or string to work with')
    end

    if value.is_a?(Array)
      result = value.collect { |i| i.is_a?(String) ? i.strip : i }
    else
      result = value.strip
    end

    return result
  end
end

# vim: set ts=2 sw=2 et :
#
# suffix.rb
#

module Puppet::Parser::Functions
  newfunction(:suffix, :type => :rvalue, :doc => <<-EOS
This function applies a suffix to all elements in an array.

*Examples:*

    suffix(['a','b','c'], 'p')

Will return: ['ap','bp','cp']
    EOS
  ) do |arguments|

    # Technically we support two arguments but only first is mandatory ...
    raise(Puppet::ParseError, "suffix(): Wrong number of arguments " +
      "given (#{arguments.size} for 1)") if arguments.size < 1

    array = arguments[0]

    unless array.is_a?(Array)
      raise Puppet::ParseError, "suffix(): expected first argument to be an Array, got #{array.inspect}"
    end

    suffix = arguments[1] if arguments[1]

    if suffix
      unless suffix.is_a? String
        raise Puppet::ParseError, "suffix(): expected second argument to be a String, got #{suffix.inspect}"
      end
    end

    # Turn everything into string same as join would do ...
    result = array.collect do |i|
      i = i.to_s
      suffix ? i + suffix : i
    end

    return result
  end
end

# vim: set ts=2 sw=2 et :
#
#  swapcase.rb
#

module Puppet::Parser::Functions
  newfunction(:swapcase, :type => :rvalue, :doc => <<-EOS
This function will swap the existing case of a string.

*Examples:*

    swapcase("aBcD")

Would result in: "AbCd"
    EOS
  ) do |arguments|

    raise(Puppet::ParseError, "swapcase(): Wrong number of arguments " +
      "given (#{arguments.size} for 1)") if arguments.size < 1

    value = arguments[0]

    unless value.is_a?(Array) || value.is_a?(String)
      raise(Puppet::ParseError, 'swapcase(): Requires either ' +
        'array or string to work with')
    end

    if value.is_a?(Array)
      # Numbers in Puppet are often string-encoded which is troublesome ...
      result = value.collect { |i| i.is_a?(String) ? i.swapcase : i }
    else
      result = value.swapcase
    end

    return result
  end
end

# vim: set ts=2 sw=2 et :
#
# time.rb
#

module Puppet::Parser::Functions
  newfunction(:time, :type => :rvalue, :doc => <<-EOS
This function will return the current time since epoch as an integer.

*Examples:*

    time()

Will return something like: 1311972653
    EOS
  ) do |arguments|

    # The Time Zone argument is optional ...
    time_zone = arguments[0] if arguments[0]

    if (arguments.size != 0) and (arguments.size != 1) then
      raise(Puppet::ParseError, "time(): Wrong number of arguments "+
        "given #{arguments.size} for 0 or 1")
    end

    time = Time.new

    # There is probably a better way to handle Time Zone ...
    if time_zone and not time_zone.empty?
      original_zone = ENV['TZ']

      local_time = time.clone
      local_time = local_time.utc

      ENV['TZ'] = time_zone

      time = local_time.localtime

      ENV['TZ'] = original_zone
    end

    # Calling Time#to_i on a receiver changes it.  Trust me I am the Doctor.
    result = time.strftime('%s')
    result = result.to_i

    return result
  end
end

# vim: set ts=2 sw=2 et :
module Puppet::Parser::Functions
  newfunction(:to_bytes, :type => :rvalue, :doc => <<-EOS
    Converts the argument into bytes, for example 4 kB becomes 4096.
    Takes a single string value as an argument.
    These conversions reflect a layperson's understanding of
    1 MB = 1024 KB, when in fact 1 MB = 1000 KB, and 1 MiB = 1024 KiB.
    EOS
  ) do |arguments|

    raise(Puppet::ParseError, "to_bytes(): Wrong number of arguments " +
          "given (#{arguments.size} for 1)") if arguments.size != 1

    arg = arguments[0]

    return arg if arg.is_a? Numeric

    value,prefix = */([0-9.e+-]*)\s*([^bB]?)/.match(arg)[1,2]

    value = value.to_f
    case prefix
    when '' then return value.to_i
    when 'k' then return (value*(1<<10)).to_i
    when 'M' then return (value*(1<<20)).to_i
    when 'G' then return (value*(1<<30)).to_i
    when 'T' then return (value*(1<<40)).to_i
    when 'P' then return (value*(1<<50)).to_i
    when 'E' then return (value*(1<<60)).to_i
    else raise Puppet::ParseError, "to_bytes(): Unknown prefix #{prefix}"
    end
  end
end
#
# type.rb
#

module Puppet::Parser::Functions
  newfunction(:type, :type => :rvalue, :doc => <<-EOS
Returns the type when passed a variable. Type can be one of:

* string
* array
* hash
* float
* integer
* boolean
    EOS
  ) do |arguments|

    raise(Puppet::ParseError, "type(): Wrong number of arguments " +
      "given (#{arguments.size} for 1)") if arguments.size < 1

    value = arguments[0]

    klass = value.class

    if not [TrueClass, FalseClass, Array, Bignum, Fixnum, Float, Hash, String].include?(klass)
      raise(Puppet::ParseError, 'type(): Unknown type')
    end

    klass = klass.to_s # Ugly ...

    # We note that Integer is the parent to Bignum and Fixnum ...
    result = case klass
      when /^(?:Big|Fix)num$/ then 'integer'
      when /^(?:True|False)Class$/ then 'boolean'
      else klass
    end

    if result == "String" then
      if value == value.to_i.to_s then
        result = "Integer"
      elsif value == value.to_f.to_s then
        result = "Float"
      end
    end

    return result.downcase
  end
end

# vim: set ts=2 sw=2 et :
#
# union.rb
#

module Puppet::Parser::Functions
  newfunction(:union, :type => :rvalue, :doc => <<-EOS
This function returns a union of two arrays.

*Examples:*

    union(["a","b","c"],["b","c","d"])

Would return: ["a","b","c","d"]
    EOS
  ) do |arguments|

    # Two arguments are required
    raise(Puppet::ParseError, "union(): Wrong number of arguments " +
      "given (#{arguments.size} for 2)") if arguments.size != 2

    first = arguments[0]
    second = arguments[1]

    unless first.is_a?(Array) && second.is_a?(Array)
      raise(Puppet::ParseError, 'union(): Requires 2 arrays')
    end

    result = first | second

    return result
  end
end

# vim: set ts=2 sw=2 et :
#
# unique.rb
#

module Puppet::Parser::Functions
  newfunction(:unique, :type => :rvalue, :doc => <<-EOS
This function will remove duplicates from strings and arrays.

*Examples:*

    unique("aabbcc")

Will return:

    abc

You can also use this with arrays:

    unique(["a","a","b","b","c","c"])

This returns:

    ["a","b","c"]
    EOS
  ) do |arguments|

    raise(Puppet::ParseError, "unique(): Wrong number of arguments " +
      "given (#{arguments.size} for 1)") if arguments.size < 1

    value = arguments[0]

    unless value.is_a?(Array) || value.is_a?(String)
      raise(Puppet::ParseError, 'unique(): Requires either ' +
        'array or string to work with')
    end

    result = value.clone

    string = value.is_a?(String) ? true : false

    # We turn any string value into an array to be able to shuffle ...
    result = string ? result.split('') : result
    result = result.uniq # Remove duplicates ...
    result = string ? result.join : result

    return result
  end
end

# vim: set ts=2 sw=2 et :
#
# upcase.rb
#

module Puppet::Parser::Functions
  newfunction(:upcase, :type => :rvalue, :doc => <<-EOS
Converts a string or an array of strings to uppercase.

*Examples:*

    upcase("abcd")

Will return:

    ASDF
    EOS
  ) do |arguments|

    raise(Puppet::ParseError, "upcase(): Wrong number of arguments " +
      "given (#{arguments.size} for 1)") if arguments.size < 1

    value = arguments[0]

    unless value.is_a?(Array) || value.is_a?(String)
      raise(Puppet::ParseError, 'upcase(): Requires either ' +
        'array or string to work with')
    end

    if value.is_a?(Array)
      # Numbers in Puppet are often string-encoded which is troublesome ...
      result = value.collect { |i| i.is_a?(String) ? i.upcase : i }
    else
      result = value.upcase
    end

    return result
  end
end

# vim: set ts=2 sw=2 et :
#
#  uriescape.rb
#
require 'uri'

module Puppet::Parser::Functions
  newfunction(:uriescape, :type => :rvalue, :doc => <<-EOS
    Urlencodes a string or array of strings.
    Requires either a single string or an array as an input.
    EOS
  ) do |arguments|

    raise(Puppet::ParseError, "uriescape(): Wrong number of arguments " +
      "given (#{arguments.size} for 1)") if arguments.size < 1

    value = arguments[0]

    unless value.is_a?(Array) || value.is_a?(String)
      raise(Puppet::ParseError, 'uriescape(): Requires either ' +
        'array or string to work with')
    end

    if value.is_a?(Array)
      # Numbers in Puppet are often string-encoded which is troublesome ...
      result = value.collect { |i| i.is_a?(String) ? URI.escape(i,unsafe) : i }
    else
      result = URI.escape(value)
    end

    return result
  end
end

# vim: set ts=2 sw=2 et :
module Puppet::Parser::Functions
  newfunction(:validate_absolute_path, :doc => <<-'ENDHEREDOC') do |args|
    Validate the string represents an absolute path in the filesystem.  This function works
    for windows and unix style paths.

    The following values will pass:

        $my_path = "C:/Program Files (x86)/Puppet Labs/Puppet"
        validate_absolute_path($my_path)
        $my_path2 = "/var/lib/puppet"
        validate_absolute_path($my_path2)


    The following values will fail, causing compilation to abort:

        validate_absolute_path(true)
        validate_absolute_path([ 'var/lib/puppet', '/var/foo' ])
        validate_absolute_path([ '/var/lib/puppet', 'var/foo' ])
        $undefined = undef
        validate_absolute_path($undefined)

    ENDHEREDOC

    require 'puppet/util'

    unless args.length > 0 then
      raise Puppet::ParseError, ("validate_absolute_path(): wrong number of arguments (#{args.length}; must be > 0)")
    end

    args.each do |arg|
      # This logic was borrowed from
      # [lib/puppet/file_serving/base.rb](https://github.com/puppetlabs/puppet/blob/master/lib/puppet/file_serving/base.rb)

      # Puppet 2.7 and beyond will have Puppet::Util.absolute_path?  Fall back to a back-ported implementation otherwise.
      if Puppet::Util.respond_to?(:absolute_path?) then
        unless Puppet::Util.absolute_path?(arg, :posix) or Puppet::Util.absolute_path?(arg, :windows)
          raise Puppet::ParseError, ("#{arg.inspect} is not an absolute path.")
        end
      else
        # This code back-ported from 2.7.x's lib/puppet/util.rb Puppet::Util.absolute_path?
        # Determine in a platform-specific way whether a path is absolute. This
        # defaults to the local platform if none is specified.
        # Escape once for the string literal, and once for the regex.
        slash = '[\\\\/]'
        name = '[^\\\\/]+'
        regexes = {
          :windows => %r!^(([A-Z]:#{slash})|(#{slash}#{slash}#{name}#{slash}#{name})|(#{slash}#{slash}\?#{slash}#{name}))!i,
          :posix   => %r!^/!,
        }

        rval = (!!(arg =~ regexes[:posix])) || (!!(arg =~ regexes[:windows]))
        rval or raise Puppet::ParseError, ("#{arg.inspect} is not an absolute path.")
      end
    end
  end
end
module Puppet::Parser::Functions

  newfunction(:validate_array, :doc => <<-'ENDHEREDOC') do |args|
    Validate that all passed values are array data structures. Abort catalog
    compilation if any value fails this check.

    The following values will pass:

        $my_array = [ 'one', 'two' ]
        validate_array($my_array)

    The following values will fail, causing compilation to abort:

        validate_array(true)
        validate_array('some_string')
        $undefined = undef
        validate_array($undefined)

    ENDHEREDOC

    unless args.length > 0 then
      raise Puppet::ParseError, ("validate_array(): wrong number of arguments (#{args.length}; must be > 0)")
    end

    args.each do |arg|
      unless arg.is_a?(Array)
        raise Puppet::ParseError, ("#{arg.inspect} is not an Array.  It looks to be a #{arg.class}")
      end
    end

  end

end
require 'tempfile'

module Puppet::Parser::Functions
  newfunction(:validate_augeas, :doc => <<-'ENDHEREDOC') do |args|
    Perform validation of a string using an Augeas lens
    The first argument of this function should be a string to
    test, and the second argument should be the name of the Augeas lens to use.
    If Augeas fails to parse the string with the lens, the compilation will
    abort with a parse error.

    A third argument can be specified, listing paths which should
    not be found in the file. The `$file` variable points to the location
    of the temporary file being tested in the Augeas tree.

    For example, if you want to make sure your passwd content never contains
    a user `foo`, you could write:

        validate_augeas($passwdcontent, 'Passwd.lns', ['$file/foo'])

    Or if you wanted to ensure that no users used the '/bin/barsh' shell,
    you could use:

        validate_augeas($passwdcontent, 'Passwd.lns', ['$file/*[shell="/bin/barsh"]']

    If a fourth argument is specified, this will be the error message raised and
    seen by the user.

    A helpful error message can be returned like this:

        validate_augeas($sudoerscontent, 'Sudoers.lns', [], 'Failed to validate sudoers content with Augeas')

    ENDHEREDOC
    unless Puppet.features.augeas?
      raise Puppet::ParseError, ("validate_augeas(): this function requires the augeas feature. See http://projects.puppetlabs.com/projects/puppet/wiki/Puppet_Augeas#Pre-requisites for how to activate it.")
    end

    if (args.length < 2) or (args.length > 4) then
      raise Puppet::ParseError, ("validate_augeas(): wrong number of arguments (#{args.length}; must be 2, 3, or 4)")
    end

    msg = args[3] || "validate_augeas(): Failed to validate content against #{args[1].inspect}"

    require 'augeas'
    aug = Augeas::open(nil, nil, Augeas::NO_MODL_AUTOLOAD)
    begin
      content = args[0]

      # Test content in a temporary file
      tmpfile = Tempfile.new("validate_augeas")
      begin
        tmpfile.write(content)
      ensure
        tmpfile.close
      end

      # Check for syntax
      lens = args[1]
      aug.transform(
        :lens => lens,
        :name => 'Validate_augeas',
        :incl => tmpfile.path
      )
      aug.load!

      unless aug.match("/augeas/files#{tmpfile.path}//error").empty?
        error = aug.get("/augeas/files#{tmpfile.path}//error/message")
        msg += " with error: #{error}"
        raise Puppet::ParseError, (msg)
      end

      # Launch unit tests
      tests = args[2] || []
      aug.defvar('file', "/files#{tmpfile.path}")
      tests.each do |t|
        msg += " testing path #{t}"
        raise Puppet::ParseError, (msg) unless aug.match(t).empty?
      end
    ensure
      aug.close
      tmpfile.unlink
    end
  end
end
module Puppet::Parser::Functions

  newfunction(:validate_bool, :doc => <<-'ENDHEREDOC') do |args|
    Validate that all passed values are either true or false. Abort catalog
    compilation if any value fails this check.

    The following values will pass:

        $iamtrue = true
        validate_bool(true)
        validate_bool(true, true, false, $iamtrue)

    The following values will fail, causing compilation to abort:

        $some_array = [ true ]
        validate_bool("false")
        validate_bool("true")
        validate_bool($some_array)

    ENDHEREDOC

    unless args.length > 0 then
      raise Puppet::ParseError, ("validate_bool(): wrong number of arguments (#{args.length}; must be > 0)")
    end

    args.each do |arg|
      unless function_is_bool([arg])
        raise Puppet::ParseError, ("#{arg.inspect} is not a boolean.  It looks to be a #{arg.class}")
      end
    end

  end

end
require 'puppet/util/execution'
require 'tempfile'

module Puppet::Parser::Functions
  newfunction(:validate_cmd, :doc => <<-'ENDHEREDOC') do |args|
    Perform validation of a string with an external command.
    The first argument of this function should be a string to
    test, and the second argument should be a path to a test command
    taking a file as last argument. If the command, launched against
    a tempfile containing the passed string, returns a non-null value,
    compilation will abort with a parse error.

    If a third argument is specified, this will be the error message raised and
    seen by the user.

    A helpful error message can be returned like this:

    Example:

        validate_cmd($sudoerscontent, '/usr/sbin/visudo -c -f', 'Visudo failed to validate sudoers content')

    ENDHEREDOC
    if (args.length < 2) or (args.length > 3) then
      raise Puppet::ParseError, ("validate_cmd(): wrong number of arguments (#{args.length}; must be 2 or 3)")
    end

    msg = args[2] || "validate_cmd(): failed to validate content with command #{args[1].inspect}"

    content = args[0]
    checkscript = args[1]

    # Test content in a temporary file
    tmpfile = Tempfile.new("validate_cmd")
    begin
      tmpfile.write(content)
      tmpfile.close
      if Puppet::Util::Execution.respond_to?('execute')
        Puppet::Util::Execution.execute("#{checkscript} #{tmpfile.path}")
      else
        Puppet::Util.execute("#{checkscript} #{tmpfile.path}")
      end
    rescue Puppet::ExecutionFailure => detail
      msg += "\n#{detail}"
      raise Puppet::ParseError, msg
    rescue Exception => detail
      msg += "\n#{detail.class.name} #{detail}"
      raise Puppet::ParseError, msg
    ensure
      tmpfile.unlink
    end
  end
end
module Puppet::Parser::Functions

  newfunction(:validate_hash, :doc => <<-'ENDHEREDOC') do |args|
    Validate that all passed values are hash data structures. Abort catalog
    compilation if any value fails this check.

    The following values will pass:

        $my_hash = { 'one' => 'two' }
        validate_hash($my_hash)

    The following values will fail, causing compilation to abort:

        validate_hash(true)
        validate_hash('some_string')
        $undefined = undef
        validate_hash($undefined)

    ENDHEREDOC

    unless args.length > 0 then
      raise Puppet::ParseError, ("validate_hash(): wrong number of arguments (#{args.length}; must be > 0)")
    end

    args.each do |arg|
      unless arg.is_a?(Hash)
        raise Puppet::ParseError, ("#{arg.inspect} is not a Hash.  It looks to be a #{arg.class}")
      end
    end

  end

end
module Puppet::Parser::Functions

  newfunction(:validate_ipv4_address, :doc => <<-ENDHEREDOC
    Validate that all values passed are valid IPv4 addresses.
    Fail compilation if any value fails this check.

    The following values will pass:

    $my_ip = "1.2.3.4"
    validate_ipv4_address($my_ip)
    validate_bool("8.8.8.8", "172.16.0.1", $my_ip)

    The following values will fail, causing compilation to abort:

    $some_array = [ 1, true, false, "garbage string", "3ffe:505:2" ]
    validate_ipv4_address($some_array)

    ENDHEREDOC
  ) do |args|

    require "ipaddr"
    rescuable_exceptions = [ ArgumentError ]

    if defined?(IPAddr::InvalidAddressError)
      rescuable_exceptions << IPAddr::InvalidAddressError
    end

    unless args.length > 0 then
      raise Puppet::ParseError, ("validate_ipv4_address(): wrong number of arguments (#{args.length}; must be > 0)")
    end

    args.each do |arg|
      unless arg.is_a?(String)
        raise Puppet::ParseError, "#{arg.inspect} is not a string."
      end

      begin
        unless IPAddr.new(arg).ipv4?
          raise Puppet::ParseError, "#{arg.inspect} is not a valid IPv4 address."
        end
      rescue *rescuable_exceptions
        raise Puppet::ParseError, "#{arg.inspect} is not a valid IPv4 address."
      end
    end

  end

end
module Puppet::Parser::Functions

  newfunction(:validate_ipv6_address, :doc => <<-ENDHEREDOC
    Validate that all values passed are valid IPv6 addresses.
    Fail compilation if any value fails this check.

    The following values will pass:

    $my_ip = "3ffe:505:2"
    validate_ipv6_address(1)
    validate_ipv6_address($my_ip)
    validate_bool("fe80::baf6:b1ff:fe19:7507", $my_ip)

    The following values will fail, causing compilation to abort:

    $some_array = [ true, false, "garbage string", "1.2.3.4" ]
    validate_ipv6_address($some_array)

    ENDHEREDOC
  ) do |args|

    require "ipaddr"
    rescuable_exceptions = [ ArgumentError ]

    if defined?(IPAddr::InvalidAddressError)
      rescuable_exceptions << IPAddr::InvalidAddressError
    end

    unless args.length > 0 then
      raise Puppet::ParseError, ("validate_ipv6_address(): wrong number of arguments (#{args.length}; must be > 0)")
    end

    args.each do |arg|
      unless arg.is_a?(String)
        raise Puppet::ParseError, "#{arg.inspect} is not a string."
      end

      begin
        unless IPAddr.new(arg).ipv6?
          raise Puppet::ParseError, "#{arg.inspect} is not a valid IPv6 address."
        end
      rescue *rescuable_exceptions
        raise Puppet::ParseError, "#{arg.inspect} is not a valid IPv6 address."
      end
    end

  end

end
module Puppet::Parser::Functions
  newfunction(:validate_re, :doc => <<-'ENDHEREDOC') do |args|
    Perform simple validation of a string against one or more regular
    expressions. The first argument of this function should be a string to
    test, and the second argument should be a stringified regular expression
    (without the // delimiters) or an array of regular expressions.  If none
    of the regular expressions match the string passed in, compilation will
    abort with a parse error.

    If a third argument is specified, this will be the error message raised and
    seen by the user.

    The following strings will validate against the regular expressions:

        validate_re('one', '^one$')
        validate_re('one', [ '^one', '^two' ])

    The following strings will fail to validate, causing compilation to abort:

        validate_re('one', [ '^two', '^three' ])

    A helpful error message can be returned like this:

        validate_re($::puppetversion, '^2.7', 'The $puppetversion fact value does not match 2.7')

    ENDHEREDOC
    if (args.length < 2) or (args.length > 3) then
      raise Puppet::ParseError, ("validate_re(): wrong number of arguments (#{args.length}; must be 2 or 3)")
    end

    msg = args[2] || "validate_re(): #{args[0].inspect} does not match #{args[1].inspect}"

    # We're using a flattened array here because we can't call String#any? in
    # Ruby 1.9 like we can in Ruby 1.8
    raise Puppet::ParseError, (msg) unless [args[1]].flatten.any? do |re_str|
      args[0] =~ Regexp.compile(re_str)
    end

  end
end
module Puppet::Parser::Functions

  newfunction(:validate_slength, :doc => <<-'ENDHEREDOC') do |args|
    Validate that the first argument is a string (or an array of strings), and
    less/equal to than the length of the second argument. An optional third
    parameter can be given a the minimum length. It fails if the first
    argument is not a string or array of strings, and if arg 2 and arg 3 are
    not convertable to a number.

    The following values will pass:

      validate_slength("discombobulate",17)
      validate_slength(["discombobulate","moo"],17)
      validate_slength(["discombobulate","moo"],17,3)

    The following valueis will not:

      validate_slength("discombobulate",1)
      validate_slength(["discombobulate","thermometer"],5)
      validate_slength(["discombobulate","moo"],17,10)

    ENDHEREDOC

    raise Puppet::ParseError, "validate_slength(): Wrong number of arguments (#{args.length}; must be 2 or 3)" unless args.length == 2 or args.length == 3

    input, max_length, min_length = *args

    begin
      max_length = Integer(max_length)
      raise ArgumentError if max_length <= 0
    rescue ArgumentError, TypeError
      raise Puppet::ParseError, "validate_slength(): Expected second argument to be a positive Numeric, got #{max_length}:#{max_length.class}"
    end

    if min_length
      begin
        min_length = Integer(min_length)
        raise ArgumentError if min_length < 0
    rescue ArgumentError, TypeError
        raise Puppet::ParseError, "validate_slength(): Expected third argument to be unset or a positive Numeric, got #{min_length}:#{min_length.class}"
      end
    else
      min_length = 0
    end

    if min_length > max_length
      raise Puppet::ParseError, "validate_slength(): Expected second argument to be larger than third argument"
    end

    validator = lambda do |str|
      unless str.length <= max_length and str.length >= min_length
        raise Puppet::ParseError, "validate_slength(): Expected length of #{input.inspect} to be between #{min_length} and #{max_length}, was #{input.length}"
      end
    end

    case input
    when String
      validator.call(input)
    when Array
      input.each_with_index do |arg, pos|
        if arg.is_a? String
          validator.call(arg)
        else
          raise Puppet::ParseError, "validate_slength(): Expected element at array position #{pos} to be a String, got #{arg.class}"
        end
      end
    else
      raise Puppet::ParseError, "validate_slength(): Expected first argument to be a String or Array, got #{input.class}"
    end
  end
end
module Puppet::Parser::Functions

  newfunction(:validate_string, :doc => <<-'ENDHEREDOC') do |args|
    Validate that all passed values are string data structures. Abort catalog
    compilation if any value fails this check.

    The following values will pass:

        $my_string = "one two"
        validate_string($my_string, 'three')

    The following values will fail, causing compilation to abort:

        validate_string(true)
        validate_string([ 'some', 'array' ])
        
    Note: validate_string(undef) will not fail in this version of the
    functions API (incl. current and future parser). Instead, use:
    
        if $var == undef {
          fail('...')
        }
    
    ENDHEREDOC

    unless args.length > 0 then
      raise Puppet::ParseError, ("validate_string(): wrong number of arguments (#{args.length}; must be > 0)")
    end

    args.each do |arg|
      unless arg.is_a?(String)
        raise Puppet::ParseError, ("#{arg.inspect} is not a string.  It looks to be a #{arg.class}")
      end
    end

  end

end
#
# values.rb
#

module Puppet::Parser::Functions
  newfunction(:values, :type => :rvalue, :doc => <<-EOS
When given a hash this function will return the values of that hash.

*Examples:*

    $hash = {
      'a' => 1,
      'b' => 2,
      'c' => 3,
    }
    values($hash)

This example would return:

    [1,2,3]
    EOS
  ) do |arguments|

    raise(Puppet::ParseError, "values(): Wrong number of arguments " +
      "given (#{arguments.size} for 1)") if arguments.size < 1

    hash = arguments[0]

    unless hash.is_a?(Hash)
      raise(Puppet::ParseError, 'values(): Requires hash to work with')
    end

    result = hash.values

    return result
  end
end

# vim: set ts=2 sw=2 et :
#
# values_at.rb
#

module Puppet::Parser::Functions
  newfunction(:values_at, :type => :rvalue, :doc => <<-EOS
Finds value inside an array based on location.

The first argument is the array you want to analyze, and the second element can
be a combination of:

* A single numeric index
* A range in the form of 'start-stop' (eg. 4-9)
* An array combining the above

*Examples*:

    values_at(['a','b','c'], 2)

Would return ['c'].

    values_at(['a','b','c'], ["0-1"])

Would return ['a','b'].

    values_at(['a','b','c','d','e'], [0, "2-3"])

Would return ['a','c','d'].
    EOS
  ) do |arguments|

    raise(Puppet::ParseError, "values_at(): Wrong number of " +
      "arguments given (#{arguments.size} for 2)") if arguments.size < 2

    array = arguments.shift

    unless array.is_a?(Array)
      raise(Puppet::ParseError, 'values_at(): Requires array to work with')
    end

    indices = [arguments.shift].flatten() # Get them all ... Pokemon ...

    if not indices or indices.empty?
      raise(Puppet::ParseError, 'values_at(): You must provide ' +
        'at least one positive index to collect')
    end

    result       = []
    indices_list = []

    indices.each do |i|
      i = i.to_s
      if m = i.match(/^(\d+)(\.\.\.?|\-)(\d+)$/)
        start = m[1].to_i
        stop  = m[3].to_i

        type = m[2]

        if start > stop
          raise(Puppet::ParseError, 'values_at(): Stop index in ' +
            'given indices range is smaller than the start index')
        elsif stop > array.size - 1 # First element is at index 0 is it not?
          raise(Puppet::ParseError, 'values_at(): Stop index in ' +
            'given indices range exceeds array size')
        end

        range = case type
          when /^(\.\.|\-)$/ then (start .. stop)
          when /^(\.\.\.)$/  then (start ... stop) # Exclusive of last element ...
        end

        range.each { |i| indices_list << i.to_i }
      else
        # Only positive numbers allowed in this case ...
        if not i.match(/^\d+$/)
          raise(Puppet::ParseError, 'values_at(): Unknown format ' +
            'of given index')
        end

        # In Puppet numbers are often string-encoded ...
        i = i.to_i

        if i > array.size - 1 # Same story.  First element is at index 0 ...
          raise(Puppet::ParseError, 'values_at(): Given index ' +
            'exceeds array size')
        end

        indices_list << i
      end
    end

    # We remove nil values as they make no sense in Puppet DSL ...
    result = indices_list.collect { |i| array[i] }.compact

    return result
  end
end

# vim: set ts=2 sw=2 et :
#
# zip.rb
#

module Puppet::Parser::Functions
  newfunction(:zip, :type => :rvalue, :doc => <<-EOS
Takes one element from first array and merges corresponding elements from second array. This generates a sequence of n-element arrays, where n is one more than the count of arguments.

*Example:*

    zip(['1','2','3'],['4','5','6'])

Would result in:

    ["1", "4"], ["2", "5"], ["3", "6"]
    EOS
  ) do |arguments|

    # Technically we support three arguments but only first is mandatory ...
    raise(Puppet::ParseError, "zip(): Wrong number of arguments " +
      "given (#{arguments.size} for 2)") if arguments.size < 2

    a = arguments[0]
    b = arguments[1]

    unless a.is_a?(Array) and b.is_a?(Array)
      raise(Puppet::ParseError, 'zip(): Requires array to work with')
    end

    flatten = function_str2bool([arguments[2]]) if arguments[2]

    result = a.zip(b)
    result = flatten ? result.flatten : result

    return result
  end
end

# vim: set ts=2 sw=2 et :
Puppet::Type.type(:file_line).provide(:ruby) do
  def exists?
    lines.find do |line|
      line.chomp == resource[:line].chomp
    end
  end

  def create
    if resource[:match]
      handle_create_with_match
    elsif resource[:after]
      handle_create_with_after
    else
      append_line
    end
  end

  def destroy
    local_lines = lines
    File.open(resource[:path],'w') do |fh|
      fh.write(local_lines.reject{|l| l.chomp == resource[:line] }.join(''))
    end
  end

  private
  def lines
    # If this type is ever used with very large files, we should
    #  write this in a different way, using a temp
    #  file; for now assuming that this type is only used on
    #  small-ish config files that can fit into memory without
    #  too much trouble.
    @lines ||= File.readlines(resource[:path])
  end

  def handle_create_with_match()
    regex = resource[:match] ? Regexp.new(resource[:match]) : nil
    match_count = count_matches(regex)
    if match_count > 1 && resource[:multiple].to_s != 'true'
     raise Puppet::Error, "More than one line in file '#{resource[:path]}' matches pattern '#{resource[:match]}'"
    end
    File.open(resource[:path], 'w') do |fh|
      lines.each do |l|
        fh.puts(regex.match(l) ? resource[:line] : l)
      end

      if (match_count == 0)
        fh.puts(resource[:line])
      end
    end
  end

  def handle_create_with_after
    regex = Regexp.new(resource[:after])
    count = count_matches(regex)
    case count
    when 1 # find the line to put our line after
      File.open(resource[:path], 'w') do |fh|
        lines.each do |l|
          fh.puts(l)
          if regex.match(l) then
            fh.puts(resource[:line])
          end
        end
      end
    when 0 # append the line to the end of the file
      append_line
    else
      raise Puppet::Error, "#{count} lines match pattern '#{resource[:after]}' in file '#{resource[:path]}'.  One or no line must match the pattern."
    end
  end

  def count_matches(regex)
    lines.select{|l| l.match(regex)}.size
  end

  ##
  # append the line to the file.
  #
  # @api private
  def append_line
    File.open(resource[:path], 'a') do |fh|
      fh.puts resource[:line]
    end
  end
end
Puppet::Type.newtype(:anchor) do
  desc <<-'ENDOFDESC'
  A simple resource type intended to be used as an anchor in a composite class.

  In Puppet 2.6, when a class declares another class, the resources in the
  interior class are not contained by the exterior class. This interacts badly
  with the pattern of composing complex modules from smaller classes, as it
  makes it impossible for end users to specify order relationships between the
  exterior class and other modules.

  The anchor type lets you work around this. By sandwiching any interior
  classes between two no-op resources that _are_ contained by the exterior
  class, you can ensure that all resources in the module are contained.

      class ntp {
        # These classes will have the correct order relationship with each
        # other. However, without anchors, they won't have any order
        # relationship to Class['ntp'].
        class { 'ntp::package': }
        -> class { 'ntp::config': }
        -> class { 'ntp::service': }

        # These two resources "anchor" the composed classes within the ntp
        # class.
        anchor { 'ntp::begin': } -> Class['ntp::package']
        Class['ntp::service']    -> anchor { 'ntp::end': }
      }

  This allows the end user of the ntp module to establish require and before
  relationships with Class['ntp']:

      class { 'ntp': } -> class { 'mcollective': }
      class { 'mcollective': } -> class { 'ntp': }

  ENDOFDESC

  newparam :name do
    desc "The name of the anchor resource."
  end

  def refresh
    # We don't do anything with them, but we need this to
    #   show that we are "refresh aware" and not break the
    #   chain of propagation.
  end
end
Puppet::Type.newtype(:file_line) do

  desc <<-EOT
    Ensures that a given line is contained within a file.  The implementation
    matches the full line, including whitespace at the beginning and end.  If
    the line is not contained in the given file, Puppet will add the line to
    ensure the desired state.  Multiple resources may be declared to manage
    multiple lines in the same file.

    Example:

        file_line { 'sudo_rule':
          path => '/etc/sudoers',
          line => '%sudo ALL=(ALL) ALL',
        }
        file_line { 'sudo_rule_nopw':
          path => '/etc/sudoers',
          line => '%sudonopw ALL=(ALL) NOPASSWD: ALL',
        }

    In this example, Puppet will ensure both of the specified lines are
    contained in the file /etc/sudoers.

    **Autorequires:** If Puppet is managing the file that will contain the line
    being managed, the file_line resource will autorequire that file.

  EOT

  ensurable do
    defaultvalues
    defaultto :present
  end

  newparam(:name, :namevar => true) do
    desc 'An arbitrary name used as the identity of the resource.'
  end

  newparam(:match) do
    desc 'An optional regular expression to run against existing lines in the file;\n' +
        'if a match is found, we replace that line rather than adding a new line.'
  end

  newparam(:multiple) do
    desc 'An optional value to determine if match can change multiple lines.'
    newvalues(true, false)
  end

  newparam(:after) do
    desc 'An optional value used to specify the line after which we will add any new lines. (Existing lines are added in place)'
  end

  newparam(:line) do
    desc 'The line to be appended to the file located by the path parameter.'
  end

  newparam(:path) do
    desc 'The file Puppet will ensure contains the line specified by the line parameter.'
    validate do |value|
      unless (Puppet.features.posix? and value =~ /^\//) or (Puppet.features.microsoft_windows? and (value =~ /^.:\// or value =~ /^\/\/[^\/]+\/[^\/]+/))
        raise(Puppet::Error, "File paths must be fully qualified, not '#{value}'")
      end
    end
  end

  # Autorequire the file resource if it's being managed
  autorequire(:file) do
    self[:path]
  end

  validate do
    unless self[:line] and self[:path]
      raise(Puppet::Error, "Both line and path are required attributes")
    end

    if (self[:match])
      unless Regexp.new(self[:match]).match(self[:line])
        raise(Puppet::Error, "When providing a 'match' parameter, the value must be a regex that matches against the value of your 'line' parameter")
      end
    end

  end
end
# Class: stdlib
#
# This module manages stdlib. Most of stdlib's features are automatically
# loaded by Puppet, but this class should be declared in order to use the
# standardized run stages.
#
# Parameters: none
#
# Actions:
#
#   Declares all other classes in the stdlib module. Currently, this consists
#   of stdlib::stages.
#
# Requires: nothing
#
class stdlib {

  class { 'stdlib::stages': }

}
# Class: stdlib::stages
#
# This class manages a standard set of run stages for Puppet. It is managed by
# the stdlib class, and should not be declared independently.
#
# The high level stages are (in order):
#
#  * setup
#  * main
#  * runtime
#  * setup_infra
#  * deploy_infra
#  * setup_app
#  * deploy_app
#  * deploy
#
# Parameters: none
#
# Actions:
#
#   Declares various run-stages for deploying infrastructure,
#   language runtimes, and application layers.
#
# Requires: nothing
#
# Sample Usage:
#
#  node default {
#    include stdlib
#    class { java: stage => 'runtime' }
#  }
#
class stdlib::stages {

  stage { 'setup':  before => Stage['main'] }
  stage { 'runtime': require => Stage['main'] }
  -> stage { 'setup_infra': }
  -> stage { 'deploy_infra': }
  -> stage { 'setup_app': }
  -> stage { 'deploy_app': }
  -> stage { 'deploy': }

}
{
  "name": "puppetlabs-stdlib",
  "version": "4.4.0",
  "author": "puppetlabs",
  "summary": "Puppet Module Standard Library",
  "license": "Apache 2.0",
  "source": "git://github.com/puppetlabs/puppetlabs-stdlib",
  "project_page": "https://github.com/puppetlabs/puppetlabs-stdlib",
  "issues_url": "https://tickets.puppetlabs.com/browse/MODULES",
  "operatingsystem_support": [
    {
      "operatingsystem": "RedHat",
      "operatingsystemrelease": [
        "4",
        "5",
        "6",
        "7"
      ]
    },
    {
      "operatingsystem": "CentOS",
      "operatingsystemrelease": [
        "4",
        "5",
        "6",
        "7"
      ]
    },
    {
      "operatingsystem": "OracleLinux",
      "operatingsystemrelease": [
        "4",
        "5",
        "6",
        "7"
      ]
    },
    {
      "operatingsystem": "Scientific",
      "operatingsystemrelease": [
        "4",
        "5",
        "6",
        "7"
      ]
    },
    {
      "operatingsystem": "SLES",
      "operatingsystemrelease": [
        "11 SP1"
      ]
    },
    {
      "operatingsystem": "Debian",
      "operatingsystemrelease": [
        "6",
        "7"
      ]
    },
    {
      "operatingsystem": "Ubuntu",
      "operatingsystemrelease": [
        "10.04",
        "12.04",
        "14.04"
      ]
    },
    {
      "operatingsystem": "Solaris",
      "operatingsystemrelease": [
        "10",
        "11"
      ]
    },
    {
      "operatingsystem": "Windows",
      "operatingsystemrelease": [
        "Server 2003",
        "Server 2003 R2",
        "Server 2008",
        "Server 2008 R2",
        "Server 2012",
        "Server 2012 R2",
        "7",
        "8"
      ]
    },
    {
      "operatingsystem": "AIX",
      "operatingsystemrelease": [
        "5.3",
        "6.1",
        "7.1"
      ]
    }
  ],
  "requirements": [
    {
      "name": "pe",
      "version_requirement": "3.x"
    },
    {
      "name": "puppet",
      "version_requirement": ">=2.7.20 <4.0.0"
    }
  ],
  "description": "Standard Library for Puppet Modules",
  "dependencies": [
  
  ]
}
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'abs function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'should accept a string' do
      pp = <<-EOS
      $input  = '-34.56'
      $output = abs($input)
      notify { "$output": }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: 34.56/)
      end
    end

    it 'should accept a float' do
      pp = <<-EOS
      $input  = -34.56
      $output = abs($input)
      notify { "$output": }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: 34.56/)
      end
    end
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'any2array function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'should create an empty array' do
      pp = <<-EOS
      $input = ''
      $output = any2array($input)
      validate_array($output)
      notify { "Output: ${output}": }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: Output: /)
      end
    end

    it 'should leave arrays modified' do
      pp = <<-EOS
      $input = ['test', 'array']
      $output = any2array($input)
      validate_array($output)
      notify { "Output: ${output}": }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: Output: (\[|)test(,\s|)array(\]|)/)
      end
    end

    it 'should turn a hash into an array' do
      pp = <<-EOS
      $input = {'test' => 'array'}
      $output = any2array($input)

      validate_array($output)
      # Check each element of the array is a plain string.
      validate_string($output[0])
      validate_string($output[1])
      notify { "Output: ${output}": }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: Output: (\[|)test(,\s|)array(\]|)/)
      end
    end
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'base64 function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'should encode then decode a string' do
      pp = <<-EOS
      $encodestring = base64('encode', 'thestring')
      $decodestring = base64('decode', $encodestring)
      notify { $decodestring: }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/thestring/)
      end
    end
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'bool2num function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    ['false', 'f', '0', 'n', 'no'].each do |bool|
      it "should convert a given boolean, #{bool}, to 0" do
        pp = <<-EOS
        $input = "#{bool}"
        $output = bool2num($input)
        notify { "$output": }
        EOS

        apply_manifest(pp, :catch_failures => true) do |r|
          expect(r.stdout).to match(/Notice: 0/)
        end
      end
    end

    ['true', 't', '1', 'y', 'yes'].each do |bool|
      it "should convert a given boolean, #{bool}, to 1" do
        pp = <<-EOS
        $input = "#{bool}"
        $output = bool2num($input)
        notify { "$output": }
        EOS

        apply_manifest(pp, :catch_failures => true) do |r|
          expect(r.stdout).to match(/Notice: 1/)
        end
      end
    end
  end
end
#!/usr/bin/env ruby
# vim: set sw=2 sts=2 et tw=80 :
require 'rspec'

#XXX Super ugly hack to keep from starting beaker nodes
module Kernel
  # make an alias of the original require
  alias_method :original_require, :require
  # rewrite require
  def require name
    original_require name if name != 'spec_helper_acceptance'
  end
end
UNSUPPORTED_PLATFORMS = []
def fact(*args) [] end
#XXX End hax

# Get a list of functions for test coverage
function_list = Dir[File.join(File.dirname(__FILE__),"..","..","lib","puppet","parser","functions","*.rb")].collect do |function_rb|
  File.basename(function_rb,".rb")
end

## Configure rspec to parse tests
options = RSpec::Core::ConfigurationOptions.new(['spec/acceptance'])
configuration = RSpec::configuration
world = RSpec::world
options.parse_options
options.configure(configuration)
configuration.load_spec_files

## Collect up tests and example groups into a hash
def get_tests(children)
  children.inject({}) do |memo,c|
    memo[c.description] = Hash.new
    memo[c.description]["groups"] = get_tests(c.children) unless c.children.empty?
    memo[c.description]["tests"] = c.examples.collect { |e|
      e.description unless e.pending?
    }.compact unless c.examples.empty?
    memo[c.description]["pending_tests"] = c.examples.collect { |e|
      e.description if e.pending?
    }.compact unless c.examples.empty?
    memo
  end
end

def count_test_types_in(type,group)
  return 0 if group.nil?
  group.inject(0) do |m,(k,v)|
    m += v.length if k == type
    m += count_tests_in(v) if v.is_a?(Hash)
    m
  end
end
def count_tests_in(group)
  count_test_types_in('tests',group)
end
def count_pending_tests_in(group)
  count_test_types_in('pending_tests',group)
end

# Convert tests hash to csv format
def to_csv(function_list,tests)
  function_list.collect do |function_name|
    if v = tests["#{function_name} function"]
      positive_tests = count_tests_in(v["groups"]["success"])
      negative_tests = count_tests_in(v["groups"]["failure"])
      pending_tests  =
        count_pending_tests_in(v["groups"]["failure"]) +
        count_pending_tests_in(v["groups"]["failure"])
    else
      positive_tests = 0
      negative_tests = 0
      pending_tests  = 0
    end
    sprintf("%-25s, %-9d, %-9d, %-9d", function_name,positive_tests,negative_tests,pending_tests)
  end.compact
end

tests = get_tests(world.example_groups)
csv = to_csv(function_list,tests)
percentage_tested = "#{tests.count*100/function_list.count}%"
printf("%-25s,  %-9s, %-9s, %-9s\n","#{percentage_tested} have tests.","Positive","Negative","Pending")
puts csv
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'capitalize function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'should capitalize the first letter of a string' do
      pp = <<-EOS
      $input = 'this is a string'
      $output = capitalize($input)
      notify { $output: }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: This is a string/)
      end
    end

    it 'should capitalize the first letter of an array of strings' do
      pp = <<-EOS
      $input = ['this', 'is', 'a', 'string']
      $output = capitalize($input)
      notify { $output: }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: This/)
        expect(r.stdout).to match(/Notice: Is/)
        expect(r.stdout).to match(/Notice: A/)
        expect(r.stdout).to match(/Notice: String/)
      end
    end
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'chomp function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'should eat the newline' do
      pp = <<-EOS
      $input = "test\n"
      if size($input) != 5 {
        fail("Size of ${input} is not 5.")
      }
      $output = chomp($input)
      if size($output) != 4 {
        fail("Size of ${input} is not 4.")
      }
      EOS

      apply_manifest(pp, :catch_failures => true)
    end
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'chop function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'should eat the last character' do
      pp = <<-EOS
      $input = "test"
      if size($input) != 4 {
        fail("Size of ${input} is not 4.")
      }
      $output = chop($input)
      if size($output) != 3 {
        fail("Size of ${input} is not 3.")
      }
      EOS

      apply_manifest(pp, :catch_failures => true)
    end

    it 'should eat the last two characters of \r\n' do
      pp = <<-'EOS'
      $input = "test\r\n"
      if size($input) != 6 {
        fail("Size of ${input} is not 6.")
      }
      $output = chop($input)
      if size($output) != 4 {
        fail("Size of ${input} is not 4.")
      }
      EOS

      apply_manifest(pp, :catch_failures => true)
    end

    it 'should not fail on empty strings' do
      pp = <<-EOS
      $input = ""
      $output = chop($input)
      EOS

      apply_manifest(pp, :catch_failures => true)
    end
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'concat function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'should concat one array to another' do
      pp = <<-EOS
      $output = concat(['1','2','3'],['4','5','6'])
      validate_array($output)
      if size($output) != 6 {
        fail("${output} should have 6 elements.")
      }
      EOS

      apply_manifest(pp, :catch_failures => true)
    end
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'count function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'should count elements in an array' do
      pp = <<-EOS
      $input = [1,2,3,4]
      $output = count($input)
      notify { "$output": }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: 4/)
      end
    end

    it 'should count elements in an array that match a second argument' do
      pp = <<-EOS
      $input = [1,1,1,2]
      $output = count($input, 1)
      notify { "$output": }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: 3/)
      end
    end
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'deep_merge function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'should deep merge two hashes' do
      pp = <<-EOS
      $hash1 = {'one' => 1, 'two' => 2, 'three' => { 'four' => 4 } }
      $hash2 = {'two' => 'dos', 'three' => { 'five' => 5 } }
      $merged_hash = deep_merge($hash1, $hash2)

      if $merged_hash != { 'one' => 1, 'two' => 'dos', 'three' => { 'four' => 4, 'five' => 5 } } {
        fail("Hash was incorrectly merged.")
      }
      EOS

      apply_manifest(pp, :catch_failures => true)
    end
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'defined_with_params function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'should successfully notify' do
      pp = <<-EOS
      user { 'dan':
        ensure => present,
      }

      if defined_with_params(User[dan], {'ensure' => 'present' }) {
        notify { 'User defined with ensure=>present': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: User defined with ensure=>present/)
      end
    end
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'delete_at function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'should delete elements of the array' do
      pp = <<-EOS
      $output = delete_at(['a','b','c','b'], 1)
      if $output == ['a','c','b'] {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'delete function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'should delete elements of the array' do
      pp = <<-EOS
      $output = delete(['a','b','c','b'], 'b')
      if $output == ['a','c'] {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'delete_undef_values function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'should delete elements of the array' do
      pp = <<-EOS
      $output = delete_undef_values({a=>'A', b=>'', c=>undef, d => false})
      if $output == { a => 'A', b => '', d => false } {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'delete_values function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'should delete elements of the hash' do
      pp = <<-EOS
      $a = { 'a' => 'A', 'b' => 'B', 'B' => 'C', 'd' => 'B' }
      $b = { 'a' => 'A', 'B' => 'C' }
      $o = delete_values($a, 'B')
      if $o == $b {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
  end
  describe 'failure' do
    it 'handles non-hash arguments'
    it 'handles improper argument counts'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'difference function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'returns non-duplicates in the first array' do
      pp = <<-EOS
      $a = ['a','b','c']
      $b = ['b','c','d']
      $c = ['a']
      $o = difference($a, $b)
      if $o == $c {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
  end
  describe 'failure' do
    it 'handles non-array arguments'
    it 'handles improper argument counts'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'dirname function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    context 'absolute path' do
      it 'returns the dirname' do
        pp = <<-EOS
        $a = '/path/to/a/file.txt'
        $b = '/path/to/a'
        $o = dirname($a)
        if $o == $b {
          notify { 'output correct': }
        }
        EOS

        apply_manifest(pp, :catch_failures => true) do |r|
          expect(r.stdout).to match(/Notice: output correct/)
        end
      end
    end
    context 'relative path' do
      it 'returns the dirname' do
        pp = <<-EOS
        $a = 'path/to/a/file.txt'
        $b = 'path/to/a'
        $o = dirname($a)
        if $o == $b {
          notify { 'output correct': }
        }
        EOS

        apply_manifest(pp, :catch_failures => true) do |r|
          expect(r.stdout).to match(/Notice: output correct/)
        end
      end
    end
  end
  describe 'failure' do
    it 'handles improper argument counts'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'downcase function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'returns the downcase' do
      pp = <<-EOS
      $a = 'AOEU'
      $b = 'aoeu'
      $o = downcase($a)
      if $o == $b {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
    it 'doesn\'t affect lowercase words' do
      pp = <<-EOS
      $a = 'aoeu aoeu'
      $b = 'aoeu aoeu'
      $o = downcase($a)
      if $o == $b {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
  end
  describe 'failure' do
    it 'handles improper argument counts'
    it 'handles non-strings'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'empty function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'recognizes empty strings' do
      pp = <<-EOS
      $a = ''
      $b = true
      $o = empty($a)
      if $o == $b {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
    it 'recognizes non-empty strings' do
      pp = <<-EOS
      $a = 'aoeu'
      $b = false
      $o = empty($a)
      if $o == $b {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
  end
  describe 'failure' do
    it 'handles improper argument counts'
    it 'handles non-strings'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'ensure_packages function', :unless => fact('osfamily') =~ /windows/i do
  describe 'success' do
    it 'ensure_packages a package' do
      apply_manifest('package { "rake": ensure => absent, provider => "gem", }')
      pp = <<-EOS
      $a = "rake"
      ensure_packages($a,{'provider' => 'gem'})
      EOS

      apply_manifest(pp, :expect_changes => true)
    end
    it 'ensures a package already declared'
    it 'takes defaults arguments'
  end
  describe 'failure' do
    it 'handles no arguments'
    it 'handles non strings'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'ensure_resource function', :unless => fact('osfamily') =~ /windows/i do
  describe 'success' do
    it 'ensure_resource a package' do
      apply_manifest('package { "rake": ensure => absent, provider => "gem", }')
      pp = <<-EOS
      $a = "rake"
      ensure_resource('package', $a, {'provider' => 'gem'})
      EOS

      apply_manifest(pp, :expect_changes => true)
    end
    it 'ensures a resource already declared'
    it 'takes defaults arguments'
  end
  describe 'failure' do
    it 'handles no arguments'
    it 'handles non strings'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'flatten function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'flattens arrays' do
      pp = <<-EOS
      $a = ["a","b",["c",["d","e"],"f","g"]]
      $b = ["a","b","c","d","e","f","g"]
      $o = flatten($a)
      if $o == $b {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
    it 'does not affect flat arrays' do
      pp = <<-EOS
      $a = ["a","b","c","d","e","f","g"]
      $b = ["a","b","c","d","e","f","g"]
      $o = flatten($a)
      if $o == $b {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
  end
  describe 'failure' do
    it 'handles improper argument counts'
    it 'handles non-strings'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'floor function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'floors floats' do
      pp = <<-EOS
      $a = 12.8
      $b = 12
      $o = floor($a)
      if $o == $b {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
    it 'floors integers' do
      pp = <<-EOS
      $a = 7
      $b = 7
      $o = floor($a)
      if $o == $b {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
  end
  describe 'failure' do
    it 'handles improper argument counts'
    it 'handles non-numbers'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'fqdn_rotate function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    let(:facts_d) do
      if fact('is_pe', '--puppet') == "true"
        if fact('osfamily') =~ /windows/i
          if fact('kernelmajversion').to_f < 6.0
            'C:/Documents and Settings/All Users/Application Data/PuppetLabs/facter/facts.d'
          else
            'C:/ProgramData/PuppetLabs/facter/facts.d'
          end
        else
          '/etc/puppetlabs/facter/facts.d'
        end
      else
        '/etc/facter/facts.d'
      end
    end
    after :each do
      shell("if [ -f '#{facts_d}/fqdn.txt' ] ; then rm '#{facts_d}/fqdn.txt' ; fi")
    end
    before :all do
      #No need to create on windows, PE creates by default
      if fact('osfamily') !~ /windows/i
        shell("mkdir -p '#{facts_d}'")
      end
    end
    it 'fqdn_rotates floats' do
      shell("echo fqdn=fakehost.localdomain > '#{facts_d}/fqdn.txt'")
      pp = <<-EOS
      $a = ['a','b','c','d']
      $o = fqdn_rotate($a)
      notice(inline_template('fqdn_rotate is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/fqdn_rotate is \["c", "d", "a", "b"\]/)
      end
    end
  end
  describe 'failure' do
    it 'handles improper argument counts'
    it 'handles non-numbers'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'get_module_path function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'get_module_paths dne' do
      pp = <<-EOS
      $a = $::is_pe ? {
        'true'  => '/etc/puppetlabs/puppet/modules/dne',
        'false' => '/etc/puppet/modules/dne',
      }
      $o = get_module_path('dne')
      if $o == $a {
        notify { 'output correct': }
      } else {
        notify { "failed; module path is '$o'": }
      }
      EOS

      apply_manifest(pp, :expect_failures => true)
    end
  end
  describe 'failure' do
    it 'handles improper argument counts'
    it 'handles non-numbers'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'getparam function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'getparam a notify' do
      pp = <<-EOS
      notify { 'rspec':
        message => 'custom rspec message',
      }
      $o = getparam(Notify['rspec'], 'message')
      notice(inline_template('getparam is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/getparam is "custom rspec message"/)
      end
    end
  end
  describe 'failure' do
    it 'handles no arguments'
    it 'handles non strings'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'getvar function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'getvars from classes' do
      pp = <<-EOS
      class a::data { $foo = 'aoeu' }
      include a::data
      $b = 'aoeu'
      $o = getvar("a::data::foo")
      if $o == $b {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
  end
  describe 'failure' do
    it 'handles improper argument counts'
    it 'handles non-numbers'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'grep function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'greps arrays' do
      pp = <<-EOS
      $a = ['aaabbb','bbbccc','dddeee']
      $b = 'bbb'
      $c = ['aaabbb','bbbccc']
      $o = grep($a,$b)
      if $o == $c {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
  end
  describe 'failure' do
    it 'handles improper argument counts'
    it 'handles non-arrays'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'has_interface_with function', :unless => ((UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem'))) or (fact('osfamily') == 'windows') or (fact('osfamily') == 'AIX')) do
  describe 'success' do
    it 'has_interface_with existing ipaddress' do
      pp = <<-EOS
      $a = $::ipaddress
      $o = has_interface_with('ipaddress', $a)
      notice(inline_template('has_interface_with is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/has_interface_with is true/)
      end
    end
    it 'has_interface_with absent ipaddress' do
      pp = <<-EOS
      $a = '128.0.0.1'
      $o = has_interface_with('ipaddress', $a)
      notice(inline_template('has_interface_with is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/has_interface_with is false/)
      end
    end
    it 'has_interface_with existing interface' do
      pp = <<-EOS
      if $osfamily == 'Solaris' or $osfamily == 'Darwin' {
        $a = 'lo0'
      }elsif $osfamily == 'windows' {
        $a = $::kernelmajversion ? {
          /6\.(2|3|4)/ => 'Ethernet0',
          /6\.(0|1)/ => 'Local_Area_Connection',
          /5\.(1|2)/  => undef, #Broken current in facter
        }
      }else {
        $a = 'lo'
      }
      $o = has_interface_with($a)
      notice(inline_template('has_interface_with is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/has_interface_with is true/)
      end
    end
  end
  describe 'failure' do
    it 'handles no arguments'
    it 'handles non strings'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'has_ip_address function', :unless => ((UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem'))) or (fact('osfamily') == 'windows') or (fact('osfamily') == 'AIX')) do
  describe 'success' do
    it 'has_ip_address existing ipaddress' do
      pp = <<-EOS
      $a = '127.0.0.1'
      $o = has_ip_address($a)
      notice(inline_template('has_ip_address is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/has_ip_address is true/)
      end
    end
    it 'has_ip_address absent ipaddress' do
      pp = <<-EOS
      $a = '128.0.0.1'
      $o = has_ip_address($a)
      notice(inline_template('has_ip_address is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/has_ip_address is false/)
      end
    end
  end
  describe 'failure' do
    it 'handles no arguments'
    it 'handles non strings'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'has_ip_network function', :unless => ((UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem'))) or (fact('osfamily') == 'windows') or (fact('osfamily') == 'AIX')) do
  describe 'success' do
    it 'has_ip_network existing ipaddress' do
      pp = <<-EOS
      $a = '127.0.0.0'
      $o = has_ip_network($a)
      notice(inline_template('has_ip_network is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/has_ip_network is true/)
      end
    end
    it 'has_ip_network absent ipaddress' do
      pp = <<-EOS
      $a = '128.0.0.0'
      $o = has_ip_network($a)
      notice(inline_template('has_ip_network is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/has_ip_network is false/)
      end
    end
  end
  describe 'failure' do
    it 'handles no arguments'
    it 'handles non strings'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'has_key function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'has_keys in hashes' do
      pp = <<-EOS
      $a = { 'aaa' => 'bbb','bbb' => 'ccc','ddd' => 'eee' }
      $b = 'bbb'
      $c = true
      $o = has_key($a,$b)
      if $o == $c {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
    it 'has_keys not in hashes' do
      pp = <<-EOS
      $a = { 'aaa' => 'bbb','bbb' => 'ccc','ddd' => 'eee' }
      $b = 'ccc'
      $c = false
      $o = has_key($a,$b)
      if $o == $c {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
  end
  describe 'failure' do
    it 'handles improper argument counts'
    it 'handles non-hashes'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'hash function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'hashs arrays' do
      pp = <<-EOS
      $a = ['aaa','bbb','bbb','ccc','ddd','eee']
      $b = { 'aaa' => 'bbb', 'bbb' => 'ccc', 'ddd' => 'eee' }
      $o = hash($a)
      if $o == $b {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
    it 'handles odd-length arrays'
  end
  describe 'failure' do
    it 'handles improper argument counts'
    it 'handles non-arrays'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'intersection function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'intersections arrays' do
      pp = <<-EOS
      $a = ['aaa','bbb','ccc']
      $b = ['bbb','ccc','ddd','eee']
      $c = ['bbb','ccc']
      $o = intersection($a,$b)
      if $o == $c {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
    it 'intersections empty arrays'
  end
  describe 'failure' do
    it 'handles improper argument counts'
    it 'handles non-arrays'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'is_array function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'is_arrays arrays' do
      pp = <<-EOS
      $a = ['aaa','bbb','ccc']
      $b = true
      $o = is_array($a)
      if $o == $b {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
    it 'is_arrays empty arrays' do
      pp = <<-EOS
      $a = []
      $b = true
      $o = is_array($a)
      if $o == $b {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
    it 'is_arrays strings' do
      pp = <<-EOS
      $a = "aoeu"
      $b = false
      $o = is_array($a)
      if $o == $b {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
    it 'is_arrays hashes' do
      pp = <<-EOS
      $a = {'aaa'=>'bbb'}
      $b = false
      $o = is_array($a)
      if $o == $b {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
  end
  describe 'failure' do
    it 'handles improper argument counts'
    it 'handles non-arrays'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'is_bool function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'is_bools arrays' do
      pp = <<-EOS
      $a = ['aaa','bbb','ccc']
      $b = false
      $o = is_bool($a)
      if $o == $b {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
    it 'is_bools true' do
      pp = <<-EOS
      $a = true
      $b = true
      $o = is_bool($a)
      if $o == $b {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
    it 'is_bools false' do
      pp = <<-EOS
      $a = false
      $b = true
      $o = is_bool($a)
      if $o == $b {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
    it 'is_bools strings' do
      pp = <<-EOS
      $a = "true"
      $b = false
      $o = is_bool($a)
      if $o == $b {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
    it 'is_bools hashes' do
      pp = <<-EOS
      $a = {'aaa'=>'bbb'}
      $b = false
      $o = is_bool($a)
      if $o == $b {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
  end
  describe 'failure' do
    it 'handles improper argument counts'
    it 'handles non-arrays'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'is_domain_name function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'is_domain_names arrays' do
      pp = <<-EOS
      $a = ['aaa.com','bbb','ccc']
      $o = is_domain_name($a)
      notice(inline_template('is_domain_name is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/is_domain_name is false/)
      end
    end
    it 'is_domain_names true' do
      pp = <<-EOS
      $a = true
      $o = is_domain_name($a)
      notice(inline_template('is_domain_name is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/is_domain_name is false/)
      end
    end
    it 'is_domain_names false' do
      pp = <<-EOS
      $a = false
      $o = is_domain_name($a)
      notice(inline_template('is_domain_name is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/is_domain_name is false/)
      end
    end
    it 'is_domain_names strings with hyphens' do
      pp = <<-EOS
      $a = "3foo-bar.2bar-fuzz.com"
      $b = true
      $o = is_domain_name($a)
      if $o == $b {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
    it 'is_domain_names strings beginning with hyphens' do
      pp = <<-EOS
      $a = "-bar.2bar-fuzz.com"
      $b = false
      $o = is_domain_name($a)
      if $o == $b {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
    it 'is_domain_names hashes' do
      pp = <<-EOS
      $a = {'aaa'=>'www.com'}
      $o = is_domain_name($a)
      notice(inline_template('is_domain_name is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/is_domain_name is false/)
      end
    end
  end
  describe 'failure' do
    it 'handles improper argument counts'
    it 'handles non-arrays'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'is_float function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'is_floats arrays' do
      pp = <<-EOS
      $a = ['aaa.com','bbb','ccc']
      $o = is_float($a)
      notice(inline_template('is_float is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/is_float is false/)
      end
    end
    it 'is_floats true' do
      pp = <<-EOS
      $a = true
      $o = is_float($a)
      notice(inline_template('is_float is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/is_float is false/)
      end
    end
    it 'is_floats strings' do
      pp = <<-EOS
      $a = "3.5"
      $b = true
      $o = is_float($a)
      if $o == $b {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
    it 'is_floats floats' do
      pp = <<-EOS
      $a = 3.5
      $b = true
      $o = is_float($a)
      if $o == $b {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
    it 'is_floats integers' do
      pp = <<-EOS
      $a = 3
      $b = false
      $o = is_float($a)
      if $o == $b {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
    it 'is_floats hashes' do
      pp = <<-EOS
      $a = {'aaa'=>'www.com'}
      $o = is_float($a)
      notice(inline_template('is_float is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/is_float is false/)
      end
    end
  end
  describe 'failure' do
    it 'handles improper argument counts'
    it 'handles non-arrays'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'is_function_available function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'is_function_availables arrays' do
      pp = <<-EOS
      $a = ['fail','include','require']
      $o = is_function_available($a)
      notice(inline_template('is_function_available is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/is_function_available is false/)
      end
    end
    it 'is_function_availables true' do
      pp = <<-EOS
      $a = true
      $o = is_function_available($a)
      notice(inline_template('is_function_available is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/is_function_available is false/)
      end
    end
    it 'is_function_availables strings' do
      pp = <<-EOS
      $a = "fail"
      $b = true
      $o = is_function_available($a)
      if $o == $b {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
    it 'is_function_availables function_availables' do
      pp = <<-EOS
      $a = "is_function_available"
      $o = is_function_available($a)
      notice(inline_template('is_function_available is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/is_function_available is true/)
      end
    end
  end
  describe 'failure' do
    it 'handles improper argument counts'
    it 'handles non-arrays'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'is_hash function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'is_hashs arrays' do
      pp = <<-EOS
      $a = ['aaa','bbb','ccc']
      $o = is_hash($a)
      notice(inline_template('is_hash is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/is_hash is false/)
      end
    end
    it 'is_hashs empty hashs' do
      pp = <<-EOS
      $a = {}
      $b = true
      $o = is_hash($a)
      if $o == $b {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
    it 'is_hashs strings' do
      pp = <<-EOS
      $a = "aoeu"
      $b = false
      $o = is_hash($a)
      if $o == $b {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
    it 'is_hashs hashes' do
      pp = <<-EOS
      $a = {'aaa'=>'bbb'}
      $b = true
      $o = is_hash($a)
      if $o == $b {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
  end
  describe 'failure' do
    it 'handles improper argument counts'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'is_integer function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'is_integers arrays' do
      pp = <<-EOS
      $a = ['aaa.com','bbb','ccc']
      $b = false
      $o = is_integer($a)
      if $o == $b {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
    it 'is_integers true' do
      pp = <<-EOS
      $a = true
      $b = false
      $o = is_integer($a)
      if $o == $b {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
    it 'is_integers strings' do
      pp = <<-EOS
      $a = "3"
      $b = true
      $o = is_integer($a)
      if $o == $b {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
    it 'is_integers floats' do
      pp = <<-EOS
      $a = 3.5
      $b = false
      $o = is_integer($a)
      if $o == $b {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
    it 'is_integers integers' do
      pp = <<-EOS
      $a = 3
      $b = true
      $o = is_integer($a)
      if $o == $b {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
    it 'is_integers hashes' do
      pp = <<-EOS
      $a = {'aaa'=>'www.com'}
      $b = false
      $o = is_integer($a)
      if $o == $b {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
  end
  describe 'failure' do
    it 'handles improper argument counts'
    it 'handles non-arrays'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'is_ip_address function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'is_ip_addresss ipv4' do
      pp = <<-EOS
      $a = '1.2.3.4'
      $b = true
      $o = is_ip_address($a)
      if $o == $b {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
    it 'is_ip_addresss ipv6' do
      pp = <<-EOS
      $a = "fe80:0000:cd12:d123:e2f8:47ff:fe09:dd74"
      $b = true
      $o = is_ip_address($a)
      if $o == $b {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
    it 'is_ip_addresss ipv6 compressed' do
      pp = <<-EOS
      $a = "fe00::1"
      $b = true
      $o = is_ip_address($a)
      if $o == $b {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
    it 'is_ip_addresss strings' do
      pp = <<-EOS
      $a = "aoeu"
      $b = false
      $o = is_ip_address($a)
      if $o == $b {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
    it 'is_ip_addresss ipv4 out of range' do
      pp = <<-EOS
      $a = '1.2.3.400'
      $b = false
      $o = is_ip_address($a)
      if $o == $b {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
  end
  describe 'failure' do
    it 'handles improper argument counts'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'is_mac_address function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'is_mac_addresss a mac' do
      pp = <<-EOS
      $a = '00:a0:1f:12:7f:a0'
      $b = true
      $o = is_mac_address($a)
      if $o == $b {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
    it 'is_mac_addresss a mac out of range' do
      pp = <<-EOS
      $a = '00:a0:1f:12:7f:g0'
      $b = false
      $o = is_mac_address($a)
      if $o == $b {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
  end
  describe 'failure' do
    it 'handles improper argument counts'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'is_numeric function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'is_numerics arrays' do
      pp = <<-EOS
      $a = ['aaa.com','bbb','ccc']
      $b = false
      $o = is_numeric($a)
      if $o == $b {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
    it 'is_numerics true' do
      pp = <<-EOS
      $a = true
      $b = false
      $o = is_numeric($a)
      if $o == $b {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
    it 'is_numerics strings' do
      pp = <<-EOS
      $a = "3"
      $b = true
      $o = is_numeric($a)
      if $o == $b {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
    it 'is_numerics floats' do
      pp = <<-EOS
      $a = 3.5
      $b = true
      $o = is_numeric($a)
      if $o == $b {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
    it 'is_numerics integers' do
      pp = <<-EOS
      $a = 3
      $b = true
      $o = is_numeric($a)
      if $o == $b {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
    it 'is_numerics hashes' do
      pp = <<-EOS
      $a = {'aaa'=>'www.com'}
      $b = false
      $o = is_numeric($a)
      if $o == $b {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
  end
  describe 'failure' do
    it 'handles improper argument counts'
    it 'handles non-arrays'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'is_string function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'is_strings arrays' do
      pp = <<-EOS
      $a = ['aaa.com','bbb','ccc']
      $b = false
      $o = is_string($a)
      if $o == $b {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
    it 'is_strings true' do
      pp = <<-EOS
      $a = true
      $b = false
      $o = is_string($a)
      if $o == $b {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
    it 'is_strings strings' do
      pp = <<-EOS
      $a = "aoeu"
      $o = is_string($a)
      notice(inline_template('is_string is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/is_string is true/)
      end
    end
    it 'is_strings number strings' do
      pp = <<-EOS
      $a = "3"
      $o = is_string($a)
      notice(inline_template('is_string is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/is_string is false/)
      end
    end
    it 'is_strings floats' do
      pp = <<-EOS
      $a = 3.5
      $b = false
      $o = is_string($a)
      if $o == $b {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
    it 'is_strings integers' do
      pp = <<-EOS
      $a = 3
      $b = false
      $o = is_string($a)
      if $o == $b {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
    it 'is_strings hashes' do
      pp = <<-EOS
      $a = {'aaa'=>'www.com'}
      $b = false
      $o = is_string($a)
      if $o == $b {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
  end
  describe 'failure' do
    it 'handles improper argument counts'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'join_keys_to_values function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'join_keys_to_valuess hashes' do
      pp = <<-EOS
      $a = {'aaa'=>'bbb','ccc'=>'ddd'}
      $b = ':'
      $o = join_keys_to_values($a,$b)
      notice(inline_template('join_keys_to_values is <%= @o.sort.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/join_keys_to_values is \["aaa:bbb", "ccc:ddd"\]/)
      end
    end
    it 'handles non hashes'
    it 'handles empty hashes'
  end
  describe 'failure' do
    it 'handles improper argument counts'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'join function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'joins arrays' do
      pp = <<-EOS
      $a = ['aaa','bbb','ccc']
      $b = ':'
      $c = 'aaa:bbb:ccc'
      $o = join($a,$b)
      if $o == $c {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
    it 'handles non arrays'
  end
  describe 'failure' do
    it 'handles improper argument counts'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'keys function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'keyss hashes' do
      pp = <<-EOS
      $a = {'aaa'=>'bbb','ccc'=>'ddd'}
      $o = keys($a)
      notice(inline_template('keys is <%= @o.sort.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/keys is \["aaa", "ccc"\]/)
      end
    end
    it 'handles non hashes'
    it 'handles empty hashes'
  end
  describe 'failure' do
    it 'handles improper argument counts'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

tmpdir = default.tmpdir('stdlib')

describe 'loadyaml function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'loadyamls array of values' do
      shell("echo '---
      aaa: 1
      bbb: 2
      ccc: 3
      ddd: 4' > #{tmpdir}/testyaml.yaml")
      pp = <<-EOS
      $o = loadyaml('#{tmpdir}/testyaml.yaml')
      notice(inline_template('loadyaml[aaa] is <%= @o["aaa"].inspect %>'))
      notice(inline_template('loadyaml[bbb] is <%= @o["bbb"].inspect %>'))
      notice(inline_template('loadyaml[ccc] is <%= @o["ccc"].inspect %>'))
      notice(inline_template('loadyaml[ddd] is <%= @o["ddd"].inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/loadyaml\[aaa\] is 1/)
        expect(r.stdout).to match(/loadyaml\[bbb\] is 2/)
        expect(r.stdout).to match(/loadyaml\[ccc\] is 3/)
        expect(r.stdout).to match(/loadyaml\[ddd\] is 4/)
      end
    end
  end
  describe 'failure' do
    it 'fails with no arguments'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'lstrip function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'lstrips arrays' do
      pp = <<-EOS
      $a = ["  the   ","   public   ","   art","galleries   "]
      # Anagram: Large picture halls, I bet
      $o = lstrip($a)
      notice(inline_template('lstrip is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/lstrip is \["the   ", "public   ", "art", "galleries   "\]/)
      end
    end
    it 'lstrips strings' do
      pp = <<-EOS
      $a = "   blowzy night-frumps vex'd jack q   "
      $o = lstrip($a)
      notice(inline_template('lstrip is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/lstrip is "blowzy night-frumps vex'd jack q   "/)
      end
    end
  end
  describe 'failure' do
    it 'handles no arguments'
    it 'handles non strings or arrays'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'max function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'maxs arrays' do
      pp = <<-EOS
      $o = max("the","public","art","galleries")
      notice(inline_template('max is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/max is "the"/)
      end
    end
  end
  describe 'failure' do
    it 'handles no arguments'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'member function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  shared_examples 'item found' do
    it 'should output correctly' do
      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
  end
  describe 'success' do
    it 'members arrays' do
      pp = <<-EOS
      $a = ['aaa','bbb','ccc']
      $b = 'ccc'
      $c = true
      $o = member($a,$b)
      if $o == $c {
        notify { 'output correct': }
      }
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/Notice: output correct/)
      end
    end
    describe 'members array of integers' do
      it_should_behave_like 'item found' do
        let(:pp) { <<-EOS
      if member( [1,2,3,4], 4 ){
        notify { 'output correct': }
      }
        EOS
        }
      end
    end
    describe 'members of mixed array' do
      it_should_behave_like 'item found' do
        let(:pp) { <<-EOS
      if member( ['a','4',3], 'a' ){
        notify { 'output correct': }
}
        EOS
        }
      end
    end
    it 'members arrays without members'
  end

  describe 'failure' do
    it 'handles improper argument counts'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'merge function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'should merge two hashes' do
      pp = <<-EOS
      $a = {'one' => 1, 'two' => 2, 'three' => { 'four' => 4 } }
      $b = {'two' => 'dos', 'three' => { 'five' => 5 } }
      $o = merge($a, $b)
      notice(inline_template('merge[one]   is <%= @o["one"].inspect %>'))
      notice(inline_template('merge[two]   is <%= @o["two"].inspect %>'))
      notice(inline_template('merge[three] is <%= @o["three"].inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/merge\[one\]   is ("1"|1)/)
        expect(r.stdout).to match(/merge\[two\]   is "dos"/)
        expect(r.stdout).to match(/merge\[three\] is {"five"=>("5"|5)}/)
      end
    end
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'min function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'mins arrays' do
      pp = <<-EOS
      $o = min("the","public","art","galleries")
      notice(inline_template('min is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/min is "art"/)
      end
    end
  end
  describe 'failure' do
    it 'handles no arguments'
  end
end
HOSTS:
  centos-59-x64:
    roles:
      - master
    platform: el-5-x86_64
    box : centos-59-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-59-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: git
HOSTS:
  'centos-6-vcloud':
    roles:
      - master
    platform: el-6-x86_64
    hypervisor: vcloud
    template: centos-6-x86_64
CONFIG:
  type: foss
  ssh:
    keys: "~/.ssh/id_rsa-acceptance"
  datastore: instance0
  folder: Delivery/Quality Assurance/Enterprise/Dynamic
  resourcepool: delivery/Quality Assurance/Enterprise/Dynamic
  pooling_api: http://vcloud.delivery.puppetlabs.net/
HOSTS:
  centos-64-x64:
    roles:
      - master
      - database
      - dashboard
    platform: el-6-x86_64
    box : centos-64-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: pe
HOSTS:
  centos-64-x64:
    roles:
      - master
    platform: el-6-x86_64
    box : centos-64-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: foss
HOSTS:
  centos-65-x64:
    roles:
      - master
    platform: el-6-x86_64
    box : centos-65-x64-vbox436-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-65-x64-virtualbox-nocm.box
    hypervisor : vagrant
CONFIG:
  type: foss
HOSTS:
  centos-65-x64:
    roles:
      - master
    platform: el-6-x86_64
    box : centos-65-x64-vbox436-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-65-x64-virtualbox-nocm.box
    hypervisor : vagrant
CONFIG:
  type: foss
HOSTS:
  fedora-18-x64:
    roles:
      - master
    platform: fedora-18-x86_64
    box : fedora-18-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/fedora-18-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: foss
HOSTS:
  sles-11-x64.local:
    roles:
      - master
    platform: sles-11-x64
    box : sles-11sp1-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/sles-11sp1-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
    type: foss
HOSTS:
  ubuntu-server-10044-x64:
    roles:
      - master
    platform: ubuntu-10.04-amd64
    box : ubuntu-server-10044-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/ubuntu-server-10044-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: foss
HOSTS:
  ubuntu-server-12042-x64:
    roles:
      - master
    platform: ubuntu-12.04-amd64
    box : ubuntu-server-12042-x64-vbox4210-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/ubuntu-server-12042-x64-vbox4210-nocm.box
    hypervisor : vagrant
CONFIG:
  type: foss
HOSTS:
  ubuntu-server-1404-x64:
    roles:
      - master
    platform: ubuntu-14.04-amd64
    box : puppetlabs/ubuntu-14.04-64-nocm
    box_url : https://vagrantcloud.com/puppetlabs/ubuntu-14.04-64-nocm
    hypervisor : vagrant
CONFIG:
  log_level   : debug
  type: git
HOSTS:
  ubuntu1204:
    roles:
      - master
      - database
      - dashboard
    platform: ubuntu-12.04-amd64
    template: ubuntu-1204-x86_64
    hypervisor: vcloud
  win2003_i386:
    roles:
      - agent
      - default
    platform: windows-2003-i386
    template: win-2003-i386
    hypervisor: vcloud
CONFIG:
  nfs_server: none
  ssh:
    keys: "~/.ssh/id_rsa-acceptance"
  consoleport: 443
  datastore: instance0
  folder: Delivery/Quality Assurance/Enterprise/Dynamic
  resourcepool: delivery/Quality Assurance/Enterprise/Dynamic
  pooling_api: http://vcloud.delivery.puppetlabs.net/
  pe_dir: http://neptune.puppetlabs.lan/3.2/ci-ready/
HOSTS:
  ubuntu1204:
    roles:
      - master
      - database
      - dashboard
    platform: ubuntu-12.04-amd64
    template: ubuntu-1204-x86_64
    hypervisor: vcloud
  win2003_x86_64:
    roles:
      - agent
      - default
    platform: windows-2003-x86_64
    template: win-2003-x86_64
    hypervisor: vcloud
CONFIG:
  nfs_server: none
  ssh:
    keys: "~/.ssh/id_rsa-acceptance"
  consoleport: 443
  datastore: instance0
  folder: Delivery/Quality Assurance/Enterprise/Dynamic
  resourcepool: delivery/Quality Assurance/Enterprise/Dynamic
  pooling_api: http://vcloud.delivery.puppetlabs.net/
  pe_dir: http://neptune.puppetlabs.lan/3.2/ci-ready/
HOSTS:
  ubuntu1204:
    roles:
      - master
      - database
      - dashboard
    platform: ubuntu-12.04-amd64
    template: ubuntu-1204-x86_64
    hypervisor: vcloud
  win2008_x86_64:
    roles:
      - agent
      - default
    platform: windows-2008-x86_64
    template: win-2008-x86_64
    hypervisor: vcloud
CONFIG:
  nfs_server: none
  ssh:
    keys: "~/.ssh/id_rsa-acceptance"
  consoleport: 443
  datastore: instance0
  folder: Delivery/Quality Assurance/Enterprise/Dynamic
  resourcepool: delivery/Quality Assurance/Enterprise/Dynamic
  pooling_api: http://vcloud.delivery.puppetlabs.net/
  pe_dir: http://neptune.puppetlabs.lan/3.2/ci-ready/
HOSTS:
  ubuntu1204:
    roles:
      - master
      - database
      - dashboard
    platform: ubuntu-12.04-amd64
    template: ubuntu-1204-x86_64
    hypervisor: vcloud
  win2008r2:
    roles:
      - agent
      - default
    platform: windows-2008r2-x86_64
    template: win-2008r2-x86_64
    hypervisor: vcloud
CONFIG:
  nfs_server: none
  ssh:
    keys: "~/.ssh/id_rsa-acceptance"
  consoleport: 443
  datastore: instance0
  folder: Delivery/Quality Assurance/Enterprise/Dynamic
  resourcepool: delivery/Quality Assurance/Enterprise/Dynamic
  pooling_api: http://vcloud.delivery.puppetlabs.net/
  pe_dir: http://neptune.puppetlabs.lan/3.2/ci-ready/
HOSTS:
  ubuntu1204:
    roles:
      - master
      - database
      - dashboard
    platform: ubuntu-12.04-amd64
    template: ubuntu-1204-x86_64
    hypervisor: vcloud
  win2012:
    roles:
      - agent
      - default
    platform: windows-2012-x86_64
    template: win-2012-x86_64
    hypervisor: vcloud
CONFIG:
  nfs_server: none
  ssh:
    keys: "~/.ssh/id_rsa-acceptance"
  consoleport: 443
  datastore: instance0
  folder: Delivery/Quality Assurance/Enterprise/Dynamic
  resourcepool: delivery/Quality Assurance/Enterprise/Dynamic
  pooling_api: http://vcloud.delivery.puppetlabs.net/
  pe_dir: http://neptune.puppetlabs.lan/3.2/ci-ready/
HOSTS:
  ubuntu1204:
    roles:
      - master
      - database
      - dashboard
    platform: ubuntu-12.04-amd64
    template: ubuntu-1204-x86_64
    hypervisor: vcloud
  win2012r2:
    roles:
      - agent
      - default
    platform: windows-2012r2-x86_64
    template: win-2012r2-x86_64
    hypervisor: vcloud
CONFIG:
  nfs_server: none
  ssh:
    keys: "~/.ssh/id_rsa-acceptance"
  consoleport: 443
  datastore: instance0
  folder: Delivery/Quality Assurance/Enterprise/Dynamic
  resourcepool: delivery/Quality Assurance/Enterprise/Dynamic
  pooling_api: http://vcloud.delivery.puppetlabs.net/
  pe_dir: http://neptune.puppetlabs.lan/3.2/ci-ready/
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'num2bool function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'bools positive numbers and numeric strings as true' do
      pp = <<-EOS
      $a = 1
      $b = "1"
      $c = "50"
      $ao = num2bool($a)
      $bo = num2bool($b)
      $co = num2bool($c)
      notice(inline_template('a is <%= @ao.inspect %>'))
      notice(inline_template('b is <%= @bo.inspect %>'))
      notice(inline_template('c is <%= @co.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/a is true/)
        expect(r.stdout).to match(/b is true/)
        expect(r.stdout).to match(/c is true/)
      end
    end
    it 'bools negative numbers as false' do
      pp = <<-EOS
      $a = 0
      $b = -0.1
      $c = ["-50","1"]
      $ao = num2bool($a)
      $bo = num2bool($b)
      $co = num2bool($c)
      notice(inline_template('a is <%= @ao.inspect %>'))
      notice(inline_template('b is <%= @bo.inspect %>'))
      notice(inline_template('c is <%= @co.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/a is false/)
        expect(r.stdout).to match(/b is false/)
        expect(r.stdout).to match(/c is false/)
      end
    end
  end
  describe 'failure' do
    it 'fails on words' do
      pp = <<-EOS
      $a = "a"
      $ao = num2bool($a)
      notice(inline_template('a is <%= @ao.inspect %>'))
      EOS
      expect(apply_manifest(pp, :expect_failures => true).stderr).to match(/not look like a number/)
    end

    it 'fails on numberwords' do
      pp = <<-EOS
      $b = "1b"
      $bo = num2bool($b)
      notice(inline_template('b is <%= @bo.inspect %>'))
      EOS
      expect(apply_manifest(pp, :expect_failures => true).stderr).to match(/not look like a number/)

    end

    it 'fails on non-numeric/strings' do
      pending "The function will call .to_s.to_i on anything not a Numeric or
      String, and results in 0. Is this intended?"
      pp = <<-EOS
      $c = {"c" => "-50"}
      $co = num2bool($c)
      notice(inline_template('c is <%= @co.inspect %>'))
      EOS
      expect(apply_manifest(ppc :expect_failures => true).stderr).to match(/Unable to parse/)
    end
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'parsejson function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'parses valid json' do
      pp = <<-EOS
      $a = '{"hunter": "washere", "tests": "passing"}'
      $ao = parsejson($a)
      $tests = $ao['tests']
      notice(inline_template('tests are <%= @tests.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/tests are "passing"/)
      end
    end
  end
  describe 'failure' do
    it 'raises error on incorrect json' do
      pp = <<-EOS
      $a = '{"hunter": "washere", "tests": "passing",}'
      $ao = parsejson($a)
      notice(inline_template('a is <%= @ao.inspect %>'))
      EOS

      apply_manifest(pp, :expect_failures => true) do |r|
        expect(r.stderr).to match(/expected next name/)
      end
    end

    it 'raises error on incorrect number of arguments'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'parseyaml function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'parses valid yaml' do
      pp = <<-EOS
      $a = "---\nhunter: washere\ntests: passing\n"
      $o = parseyaml($a)
      $tests = $o['tests']
      notice(inline_template('tests are <%= @tests.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/tests are "passing"/)
      end
    end
  end
  describe 'failure' do
    it 'raises error on incorrect yaml' do
      pp = <<-EOS
      $a = "---\nhunter: washere\ntests: passing\n:"
      $o = parseyaml($a)
      $tests = $o['tests']
      notice(inline_template('tests are <%= @tests.inspect %>'))
      EOS

      apply_manifest(pp, :expect_failures => true) do |r|
        expect(r.stderr).to match(/(syntax error|did not find expected key)/)
      end
    end

    it 'raises error on incorrect number of arguments'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'pick_default function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'pick_defaults a default value' do
      pp = <<-EOS
      $a = undef
      $o = pick_default($a, 'default')
      notice(inline_template('picked is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/picked is "default"/)
      end
    end
    it 'pick_defaults with no value' do
      pp = <<-EOS
      $a = undef
      $b = undef
      $o = pick_default($a,$b)
      notice(inline_template('picked is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/picked is ""/)
      end
    end
    it 'pick_defaults the first set value' do
      pp = <<-EOS
      $a = "something"
      $b = "long"
      $o = pick_default($a, $b, 'default')
      notice(inline_template('picked is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/picked is "something"/)
      end
    end
  end
  describe 'failure' do
    it 'raises error with no values' do
      pp = <<-EOS
      $o = pick_default()
      notice(inline_template('picked is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :expect_failures => true) do |r|
        expect(r.stderr).to match(/Must receive at least one argument/)
      end
    end
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'pick function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'picks a default value' do
      pp = <<-EOS
      $a = undef
      $o = pick($a, 'default')
      notice(inline_template('picked is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/picked is "default"/)
      end
    end
    it 'picks the first set value' do
      pp = <<-EOS
      $a = "something"
      $b = "long"
      $o = pick($a, $b, 'default')
      notice(inline_template('picked is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/picked is "something"/)
      end
    end
  end
  describe 'failure' do
    it 'raises error with all undef values' do
      pp = <<-EOS
      $a = undef
      $b = undef
      $o = pick($a, $b)
      notice(inline_template('picked is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :expect_failures => true) do |r|
        expect(r.stderr).to match(/must receive at least one non empty value/)
      end
    end
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'prefix function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'prefixes array of values' do
      pp = <<-EOS
      $o = prefix(['a','b','c'],'p')
      notice(inline_template('prefix is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/prefix is \["pa", "pb", "pc"\]/)
      end
    end
    it 'prefixs with empty array' do
      pp = <<-EOS
      $o = prefix([],'p')
      notice(inline_template('prefix is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/prefix is \[\]/)
      end
    end
    it 'prefixs array of values with undef' do
      pp = <<-EOS
      $o = prefix(['a','b','c'], undef)
      notice(inline_template('prefix is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/prefix is \["a", "b", "c"\]/)
      end
    end
  end
  describe 'failure' do
    it 'fails with no arguments'
    it 'fails when first argument is not array'
    it 'fails when second argument is not string'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'range function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'ranges letters' do
      pp = <<-EOS
      $o = range('a','d')
      notice(inline_template('range is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/range is \["a", "b", "c", "d"\]/)
      end
    end
    it 'ranges letters with a step' do
      pp = <<-EOS
      $o = range('a','d', '2')
      notice(inline_template('range is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/range is \["a", "c"\]/)
      end
    end
    it 'ranges letters with a negative step'
    it 'ranges numbers'
    it 'ranges numbers with a step'
    it 'ranges numbers with a negative step'
    it 'ranges numeric strings'
    it 'ranges zero padded numbers'
  end
  describe 'failure' do
    it 'fails with no arguments'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'reject function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'rejects array of values' do
      pp = <<-EOS
      $o = reject(['aaa','bbb','ccc','aaaddd'], 'aaa')
      notice(inline_template('reject is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/reject is \["bbb", "ccc"\]/)
      end
    end
    it 'rejects with empty array' do
      pp = <<-EOS
      $o = reject([],'aaa')
      notice(inline_template('reject is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/reject is \[\]/)
      end
    end
    it 'rejects array of values with undef' do
      pp = <<-EOS
      $o = reject(['aaa','bbb','ccc','aaaddd'], undef)
      notice(inline_template('reject is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/reject is \[\]/)
      end
    end
  end
  describe 'failure' do
    it 'fails with no arguments'
    it 'fails when first argument is not array'
    it 'fails when second argument is not string'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'reverse function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'reverses strings' do
      pp = <<-EOS
      $a = "the public art galleries"
      # Anagram: Large picture halls, I bet
      $o = reverse($a)
      notice(inline_template('reverse is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/reverse is "seirellag tra cilbup eht"/)
      end
    end
  end
  describe 'failure' do
    it 'handles no arguments'
    it 'handles non strings or arrays'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'rstrip function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'rstrips arrays' do
      pp = <<-EOS
      $a = ["  the   ","   public   ","   art","galleries   "]
      # Anagram: Large picture halls, I bet
      $o = rstrip($a)
      notice(inline_template('rstrip is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/rstrip is \["  the", "   public", "   art", "galleries"\]/)
      end
    end
    it 'rstrips strings' do
      pp = <<-EOS
      $a = "   blowzy night-frumps vex'd jack q   "
      $o = rstrip($a)
      notice(inline_template('rstrip is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/rstrip is "   blowzy night-frumps vex'd jack q"/)
      end
    end
  end
  describe 'failure' do
    it 'handles no arguments'
    it 'handles non strings or arrays'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'shuffle function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'shuffles arrays' do
      pp = <<-EOS
      $a = ["1", "2", "3", "4", "5", "6", "7", "8", "the","public","art","galleries"]
      # Anagram: Large picture halls, I bet
      $o = shuffle($a)
      notice(inline_template('shuffle is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to_not match(/shuffle is \["1", "2", "3", "4", "5", "6", "7", "8", "the", "public", "art", "galleries"\]/)
      end
    end
    it 'shuffles strings' do
      pp = <<-EOS
      $a = "blowzy night-frumps vex'd jack q"
      $o = shuffle($a)
      notice(inline_template('shuffle is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to_not match(/shuffle is "blowzy night-frumps vex'd jack q"/)
      end
    end
  end
  describe 'failure' do
    it 'handles no arguments'
    it 'handles non strings or arrays'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'size function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'single string size' do
      pp = <<-EOS
      $a = 'discombobulate'
      $o = size($a)
      notice(inline_template('size is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/size is 14/)
      end
    end
    it 'with empty string' do
      pp = <<-EOS
      $a = ''
      $o = size($a)
      notice(inline_template('size is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/size is 0/)
      end
    end
    it 'with undef' do
      pp = <<-EOS
      $a = undef
      $o = size($a)
      notice(inline_template('size is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/size is 0/)
      end
    end
    it 'strings in array' do
      pp = <<-EOS
      $a = ['discombobulate', 'moo']
      $o = size($a)
      notice(inline_template('size is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/size is 2/)
      end
    end
  end
  describe 'failure' do
    it 'handles no arguments'
    it 'handles non strings or arrays'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'sort function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'sorts arrays' do
      pp = <<-EOS
      $a = ["the","public","art","galleries"]
      # Anagram: Large picture halls, I bet
      $o = sort($a)
      notice(inline_template('sort is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/sort is \["art", "galleries", "public", "the"\]/)
      end
    end
    it 'sorts strings' do
      pp = <<-EOS
      $a = "blowzy night-frumps vex'd jack q"
      $o = sort($a)
      notice(inline_template('sort is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/sort is "    '-abcdefghijklmnopqrstuvwxyz"/)
      end
    end
  end
  describe 'failure' do
    it 'handles no arguments'
    it 'handles non strings or arrays'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'squeeze function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'squeezes arrays' do
      pp = <<-EOS
      # Real words!
      $a = ["wallless", "laparohysterosalpingooophorectomy", "brrr", "goddessship"]
      $o = squeeze($a)
      notice(inline_template('squeeze is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/squeeze is \["wales", "laparohysterosalpingophorectomy", "br", "godeship"\]/)
      end
    end
    it 'squeezez arrays with an argument'
    it 'squeezes strings' do
      pp = <<-EOS
      $a = "wallless laparohysterosalpingooophorectomy brrr goddessship"
      $o = squeeze($a)
      notice(inline_template('squeeze is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/squeeze is "wales laparohysterosalpingophorectomy br godeship"/)
      end
    end

    it 'squeezes strings with an argument' do
      pp = <<-EOS
      $a = "countessship duchessship governessship hostessship"
      $o = squeeze($a, 's')
      notice(inline_template('squeeze is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/squeeze is "counteship ducheship governeship hosteship"/)
      end
    end
  end
  describe 'failure' do
    it 'handles no arguments'
    it 'handles non strings or arrays'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'str2bool function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'works with "y"' do
      pp = <<-EOS
      $o = str2bool('y')
      notice(inline_template('str2bool is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/str2bool is true/)
      end
    end
    it 'works with "Y"'
    it 'works with "yes"'
    it 'works with "1"'
    it 'works with "true"'
    it 'works with "n"'
    it 'works with "N"'
    it 'works with "no"'
    it 'works with "0"'
    it 'works with "false"'
    it 'works with undef'
  end
  describe 'failure' do
    it 'handles no arguments'
    it 'handles non arrays or strings'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'str2saltedsha512 function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'works with "y"' do
      pp = <<-EOS
      $o = str2saltedsha512('password')
      notice(inline_template('str2saltedsha512 is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/str2saltedsha512 is "[a-f0-9]{136}"/)
      end
    end
  end
  describe 'failure' do
    it 'handles no arguments'
    it 'handles more than one argument'
    it 'handles non strings'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'strftime function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'gives the Century' do
      pp = <<-EOS
      $o = strftime('%C')
      notice(inline_template('strftime is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/strftime is "20"/)
      end
    end
    it 'takes a timezone argument'
  end
  describe 'failure' do
    it 'handles no arguments'
    it 'handles invalid format strings'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'strip function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'strips arrays' do
      pp = <<-EOS
      $a = ["  the   ","   public   ","   art","galleries   "]
      # Anagram: Large picture halls, I bet
      $o = strip($a)
      notice(inline_template('strip is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/strip is \["the", "public", "art", "galleries"\]/)
      end
    end
    it 'strips strings' do
      pp = <<-EOS
      $a = "   blowzy night-frumps vex'd jack q   "
      $o = strip($a)
      notice(inline_template('strip is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/strip is "blowzy night-frumps vex'd jack q"/)
      end
    end
  end
  describe 'failure' do
    it 'handles no arguments'
    it 'handles non strings or arrays'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'suffix function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'suffixes array of values' do
      pp = <<-EOS
      $o = suffix(['a','b','c'],'p')
      notice(inline_template('suffix is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/suffix is \["ap", "bp", "cp"\]/)
      end
    end
    it 'suffixs with empty array' do
      pp = <<-EOS
      $o = suffix([],'p')
      notice(inline_template('suffix is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/suffix is \[\]/)
      end
    end
    it 'suffixs array of values with undef' do
      pp = <<-EOS
      $o = suffix(['a','b','c'], undef)
      notice(inline_template('suffix is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/suffix is \["a", "b", "c"\]/)
      end
    end
  end
  describe 'failure' do
    it 'fails with no arguments'
    it 'fails when first argument is not array'
    it 'fails when second argument is not string'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'swapcase function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'works with strings' do
      pp = <<-EOS
      $o = swapcase('aBcD')
      notice(inline_template('swapcase is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/swapcase is "AbCd"/)
      end
    end
    it 'works with arrays'
  end
  describe 'failure' do
    it 'handles no arguments'
    it 'handles non arrays or strings'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'time function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'gives the time' do
      pp = <<-EOS
      $o = time()
      notice(inline_template('time is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        m = r.stdout.match(/time is (\d+)\D/)

        # When I wrote this test
        expect(Integer(m[1])).to be > 1398894170
      end
    end
    it 'takes a timezone argument' do
      pp = <<-EOS
      $o = time('UTC')
      notice(inline_template('time is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        m = r.stdout.match(/time is (\d+)\D/)

        expect(Integer(m[1])).to be > 1398894170
      end
    end
  end
  describe 'failure' do
    it 'handles more arguments'
    it 'handles invalid timezones'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'to_bytes function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'converts kB to B' do
      pp = <<-EOS
      $o = to_bytes('4 kB')
      notice(inline_template('to_bytes is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        m = r.stdout.match(/to_bytes is (\d+)\D/)
        expect(m[1]).to eq("4096")
      end
    end
    it 'works without the B in unit'
    it 'works without a space before unit'
    it 'works without a unit'
    it 'converts fractions'
  end
  describe 'failure' do
    it 'handles no arguments'
    it 'handles non integer arguments'
    it 'handles unknown units like uB'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'type function', :unless => (UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) || is_future_parser_enabled?) do
  describe 'success' do
    it 'types arrays' do
      pp = <<-EOS
      $a = ["the","public","art","galleries"]
      # Anagram: Large picture halls, I bet
      $o = type($a)
      notice(inline_template('type is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/type is "array"/)
      end
    end
    it 'types strings' do
      pp = <<-EOS
      $a = "blowzy night-frumps vex'd jack q"
      $o = type($a)
      notice(inline_template('type is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/type is "string"/)
      end
    end
    it 'types hashes'
    it 'types integers'
    it 'types floats'
    it 'types booleans'
  end
  describe 'failure' do
    it 'handles no arguments'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'union function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'unions arrays' do
      pp = <<-EOS
      $a = ["the","public"]
      $b = ["art","galleries"]
      # Anagram: Large picture halls, I bet
      $o = union($a,$b)
      notice(inline_template('union is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/union is \["the", "public", "art", "galleries"\]/)
      end
    end
  end
  describe 'failure' do
    it 'handles no arguments'
    it 'handles non arrays'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'unique function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'uniques arrays' do
      pp = <<-EOS
      $a = ["wallless", "wallless", "brrr", "goddessship"]
      $o = unique($a)
      notice(inline_template('unique is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/unique is \["wallless", "brrr", "goddessship"\]/)
      end
    end
    it 'uniques strings' do
      pp = <<-EOS
      $a = "wallless laparohysterosalpingooophorectomy brrr goddessship"
      $o = unique($a)
      notice(inline_template('unique is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/unique is "wales prohytingcmbd"/)
      end
    end
  end
  describe 'failure' do
    it 'handles no arguments'
    it 'handles non strings or arrays'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'unsupported distributions and OSes', :if => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  it 'should fail' do
    pp = <<-EOS
    class { 'mysql::server': }
    EOS
    expect(apply_manifest(pp, :expect_failures => true).stderr).to match(/unsupported osfamily/i)
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'upcase function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'upcases arrays' do
      pp = <<-EOS
      $a = ["wallless", "laparohysterosalpingooophorectomy", "brrr", "goddessship"]
      $o = upcase($a)
      notice(inline_template('upcase is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/upcase is \["WALLLESS", "LAPAROHYSTEROSALPINGOOOPHORECTOMY", "BRRR", "GODDESSSHIP"\]/)
      end
    end
    it 'upcases strings' do
      pp = <<-EOS
      $a = "wallless laparohysterosalpingooophorectomy brrr goddessship"
      $o = upcase($a)
      notice(inline_template('upcase is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/upcase is "WALLLESS LAPAROHYSTEROSALPINGOOOPHORECTOMY BRRR GODDESSSHIP"/)
      end
    end
  end
  describe 'failure' do
    it 'handles no arguments'
    it 'handles non strings or arrays'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'uriescape function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'uriescape strings' do
      pp = <<-EOS
      $a = ":/?#[]@!$&'()*+,;= \\\"{}"
      $o = uriescape($a)
      notice(inline_template('uriescape is <%= @o.inspect %>'))
      EOS

      apply_manifest(pp, :catch_failures => true) do |r|
        expect(r.stdout).to match(/uriescape is ":\/\?%23\[\]@!\$&'\(\)\*\+,;=%20%22%7B%7D"/)
      end
    end
    it 'does nothing if a string is already safe'
  end
  describe 'failure' do
    it 'handles no arguments'
    it 'handles non strings or arrays'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'validate_absolute_path function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    %w{
      C:/
      C:\\\\
      C:\\\\WINDOWS\\\\System32
      C:/windows/system32
      X:/foo/bar
      X:\\\\foo\\\\bar
      /var/tmp
      /var/lib/puppet
      /var/opt/../lib/puppet
    }.each do |path|
      it "validates a single argument #{path}" do
        pp = <<-EOS
        $one = '#{path}'
        validate_absolute_path($one)
        EOS

        apply_manifest(pp, :catch_failures => true)
      end
    end
  end
  describe 'failure' do
    it 'handles improper number of arguments'
    it 'handles relative paths'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'validate_array function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'validates a single argument' do
      pp = <<-EOS
      $one = ['a', 'b']
      validate_array($one)
      EOS

      apply_manifest(pp, :catch_failures => true)
    end
    it 'validates an multiple arguments' do
      pp = <<-EOS
      $one = ['a', 'b']
      $two = [['c'], 'd']
      validate_array($one,$two)
      EOS

      apply_manifest(pp, :catch_failures => true)
    end
    it 'validates a non-array' do
      {
        %{validate_array({'a' => 'hash' })} => "Hash",
        %{validate_array('string')}         => "String",
        %{validate_array(false)}            => "FalseClass",
        %{validate_array(undef)}            => "String"
      }.each do |pp,type|
        expect(apply_manifest(pp, :expect_failures => true).stderr).to match(/a #{type}/)
      end
    end
  end
  describe 'failure' do
    it 'handles improper number of arguments'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'validate_augeas function', :unless => ((UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem'))) or (fact('osfamily') == 'windows')) do
  describe 'prep' do
    it 'installs augeas for tests'
  end
  describe 'success' do
    context 'valid inputs with no 3rd argument' do
      {
        'root:x:0:0:root:/root:/bin/bash\n'                        => 'Passwd.lns',
        'proc /proc   proc    nodev,noexec,nosuid     0       0\n' => 'Fstab.lns'
      }.each do |line,lens|
        it "validates a single argument for #{lens}" do
          pp = <<-EOS
          $line = "#{line}"
          $lens = "#{lens}"
          validate_augeas($line, $lens)
          EOS

          apply_manifest(pp, :catch_failures => true)
        end
      end
    end
    context 'valid inputs with 3rd and 4th arguments' do
      it "validates a restricted value" do
        line        = 'root:x:0:0:root:/root:/bin/barsh\n'
        lens        = 'Passwd.lns'
        restriction = '$file/*[shell="/bin/barsh"]'
        pp = <<-EOS
        $line        = "#{line}"
        $lens        = "#{lens}"
        $restriction = ['#{restriction}']
        validate_augeas($line, $lens, $restriction, "my custom failure message")
        EOS

        expect(apply_manifest(pp, :expect_failures => true).stderr).to match(/my custom failure message/)
      end
    end
    context 'invalid inputs' do
      {
        'root:x:0:0:root' => 'Passwd.lns',
        '127.0.1.1'       => 'Hosts.lns'
      }.each do |line,lens|
        it "validates a single argument for #{lens}" do
          pp = <<-EOS
          $line = "#{line}"
          $lens = "#{lens}"
          validate_augeas($line, $lens)
          EOS

          apply_manifest(pp, :expect_failures => true)
        end
      end
    end
    context 'garbage inputs' do
      it 'raises an error on invalid inputs'
    end
  end
  describe 'failure' do
    it 'handles improper number of arguments'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'validate_bool function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'validates a single argument' do
      pp = <<-EOS
      $one = true
      validate_bool($one)
      EOS

      apply_manifest(pp, :catch_failures => true)
    end
    it 'validates an multiple arguments' do
      pp = <<-EOS
      $one = true
      $two = false
      validate_bool($one,$two)
      EOS

      apply_manifest(pp, :catch_failures => true)
    end
    it 'validates a non-bool' do
      {
        %{validate_bool('true')}  => "String",
        %{validate_bool('false')} => "String",
        %{validate_bool([true])}  => "Array",
        %{validate_bool(undef)}   => "String",
      }.each do |pp,type|
        expect(apply_manifest(pp, :expect_failures => true).stderr).to match(/a #{type}/)
      end
    end
  end
  describe 'failure' do
    it 'handles improper number of arguments'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'validate_cmd function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'validates a true command' do
      pp = <<-EOS
      $one = 'foo'
      if $::osfamily == 'windows' {
        $two = 'echo' #shell built-in
      } else {
        $two = '/bin/echo'
      }
      validate_cmd($one,$two)
      EOS

      apply_manifest(pp, :catch_failures => true)
    end
    it 'validates a fail command' do
      pp = <<-EOS
      $one = 'foo'
      if $::osfamily == 'windows' {
        $two = 'C:/aoeu'
      } else {
        $two = '/bin/aoeu'
      }
      validate_cmd($one,$two)
      EOS

      apply_manifest(pp, :expect_failures => true)
    end
    it 'validates a fail command with a custom error message' do
      pp = <<-EOS
      $one = 'foo'
      if $::osfamily == 'windows' {
        $two = 'C:/aoeu'
      } else {
        $two = '/bin/aoeu'
      }
      validate_cmd($one,$two,"aoeu is dvorak")
      EOS

      apply_manifest(pp, :expect_failures => true) do |output|
        expect(output.stderr).to match(/aoeu is dvorak/)
      end
    end
  end
  describe 'failure' do
    it 'handles improper number of arguments'
    it 'handles improper argument types'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'validate_hash function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'validates a single argument' do
      pp = <<-EOS
      $one = { 'a' => 1 }
      validate_hash($one)
      EOS

      apply_manifest(pp, :catch_failures => true)
    end
    it 'validates an multiple arguments' do
      pp = <<-EOS
      $one = { 'a' => 1 }
      $two = { 'b' => 2 }
      validate_hash($one,$two)
      EOS

      apply_manifest(pp, :catch_failures => true)
    end
    it 'validates a non-hash' do
      {
        %{validate_hash('{ "not" => "hash" }')} => "String",
        %{validate_hash('string')}              => "String",
        %{validate_hash(["array"])}             => "Array",
        %{validate_hash(undef)}                 => "String",
      }.each do |pp,type|
        expect(apply_manifest(pp, :expect_failures => true).stderr).to match(/a #{type}/)
      end
    end
  end
  describe 'failure' do
    it 'handles improper number of arguments'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'validate_ipv4_address function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'validates a single argument' do
      pp = <<-EOS
      $one = '1.2.3.4'
      validate_ipv4_address($one)
      EOS

      apply_manifest(pp, :catch_failures => true)
    end
    it 'validates an multiple arguments' do
      pp = <<-EOS
      $one = '1.2.3.4'
      $two = '5.6.7.8'
      validate_ipv4_address($one,$two)
      EOS

      apply_manifest(pp, :catch_failures => true)
    end
  end
  describe 'failure' do
    it 'handles improper number of arguments'
    it 'handles ipv6 addresses'
    it 'handles non-ipv4 strings'
    it 'handles numbers'
    it 'handles no arguments'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'validate_ipv6_address function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'validates a single argument' do
      pp = <<-EOS
      $one = '3ffe:0505:0002::'
      validate_ipv6_address($one)
      EOS

      apply_manifest(pp, :catch_failures => true)
    end
    it 'validates an multiple arguments' do
      pp = <<-EOS
      $one = '3ffe:0505:0002::'
      $two = '3ffe:0505:0001::'
      validate_ipv6_address($one,$two)
      EOS

      apply_manifest(pp, :catch_failures => true)
    end
  end
  describe 'failure' do
    it 'handles improper number of arguments'
    it 'handles ipv6 addresses'
    it 'handles non-ipv6 strings'
    it 'handles numbers'
    it 'handles no arguments'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'validate_re function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'validates a string' do
      pp = <<-EOS
      $one = 'one'
      $two = '^one$'
      validate_re($one,$two)
      EOS

      apply_manifest(pp, :catch_failures => true)
    end
    it 'validates an array' do
      pp = <<-EOS
      $one = 'one'
      $two = ['^one$', '^two']
      validate_re($one,$two)
      EOS

      apply_manifest(pp, :catch_failures => true)
    end
    it 'validates a failed array' do
      pp = <<-EOS
      $one = 'one'
      $two = ['^two$', '^three']
      validate_re($one,$two)
      EOS

      apply_manifest(pp, :expect_failures => true)
    end
    it 'validates a failed array with a custom error message' do
      pp = <<-EOS
      $one = '3.4.3'
      $two = '^2.7'
      validate_re($one,$two,"The $puppetversion fact does not match 2.7")
      EOS

      expect(apply_manifest(pp, :expect_failures => true).stderr).to match(/does not match/)
    end
  end
  describe 'failure' do
    it 'handles improper number of arguments'
    it 'handles improper argument types'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'validate_slength function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'validates a single string max' do
      pp = <<-EOS
      $one = 'discombobulate'
      $two = 17
      validate_slength($one,$two)
      EOS

      apply_manifest(pp, :catch_failures => true)
    end
    it 'validates multiple string maxes' do
      pp = <<-EOS
      $one = ['discombobulate', 'moo']
      $two = 17
      validate_slength($one,$two)
      EOS

      apply_manifest(pp, :catch_failures => true)
    end
    it 'validates min/max of  strings in array' do
      pp = <<-EOS
      $one = ['discombobulate', 'moo']
      $two = 17
      $three = 3
      validate_slength($one,$two,$three)
      EOS

      apply_manifest(pp, :catch_failures => true)
    end
    it 'validates a single string max of incorrect length' do
      pp = <<-EOS
      $one = 'discombobulate'
      $two = 1
      validate_slength($one,$two)
      EOS

      apply_manifest(pp, :expect_failures => true)
    end
    it 'validates multiple string maxes of incorrect length' do
      pp = <<-EOS
      $one = ['discombobulate', 'moo']
      $two = 3
      validate_slength($one,$two)
      EOS

      apply_manifest(pp, :expect_failures => true)
    end
    it 'validates multiple strings min/maxes of incorrect length' do
      pp = <<-EOS
      $one = ['discombobulate', 'moo']
      $two = 17
      $three = 10
      validate_slength($one,$two,$three)
      EOS

      apply_manifest(pp, :expect_failures => true)
    end
  end
  describe 'failure' do
    it 'handles improper number of arguments'
    it 'handles improper first argument type'
    it 'handles non-strings in array of first argument'
    it 'handles improper second argument type'
    it 'handles improper third argument type'
    it 'handles negative ranges'
    it 'handles improper ranges'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'validate_string function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'validates a single argument' do
      pp = <<-EOS
      $one = 'string'
      validate_string($one)
      EOS

      apply_manifest(pp, :catch_failures => true)
    end
    it 'validates an multiple arguments' do
      pp = <<-EOS
      $one = 'string'
      $two = 'also string'
      validate_string($one,$two)
      EOS

      apply_manifest(pp, :catch_failures => true)
    end
    it 'validates a non-string' do
      {
        %{validate_string({ 'a' => 'hash' })} => "Hash",
        %{validate_string(['array'])}         => "Array",
        %{validate_string(false)}             => "FalseClass",
      }.each do |pp,type|
        expect(apply_manifest(pp, :expect_failures => true).stderr).to match(/a #{type}/)
      end
    end
  end
  describe 'failure' do
    it 'handles improper number of arguments'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'values_at function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'returns a specific value' do
      pp = <<-EOS
      $one = ['a','b','c','d','e']
      $two = 1
      $output = values_at($one,$two)
      notice(inline_template('<%= @output.inspect %>'))
      EOS

      expect(apply_manifest(pp, :catch_failures => true).stdout).to match(/\["b"\]/)
    end
    it 'returns a specific negative index value' do
      pending("negative numbers don't work")
      pp = <<-EOS
      $one = ['a','b','c','d','e']
      $two = -1
      $output = values_at($one,$two)
      notice(inline_template('<%= @output.inspect %>'))
      EOS

      expect(apply_manifest(pp, :catch_failures => true).stdout).to match(/\["e"\]/)
    end
    it 'returns a range of values' do
      pp = <<-EOS
      $one = ['a','b','c','d','e']
      $two = "1-3"
      $output = values_at($one,$two)
      notice(inline_template('<%= @output.inspect %>'))
      EOS

      expect(apply_manifest(pp, :catch_failures => true).stdout).to match(/\["b", "c", "d"\]/)
    end
    it 'returns a negative specific value and range of values' do
      pp = <<-EOS
      $one = ['a','b','c','d','e']
      $two = ["1-3",0]
      $output = values_at($one,$two)
      notice(inline_template('<%= @output.inspect %>'))
      EOS

      expect(apply_manifest(pp, :catch_failures => true).stdout).to match(/\["b", "c", "d", "a"\]/)
    end
  end
  describe 'failure' do
    it 'handles improper number of arguments' do
      pp = <<-EOS
      $one = ['a','b','c','d','e']
      $output = values_at($one)
      notice(inline_template('<%= @output.inspect %>'))
      EOS

      expect(apply_manifest(pp, :expect_failures => true).stderr).to match(/Wrong number of arguments/)
    end
    it 'handles non-indicies arguments' do
      pp = <<-EOS
      $one = ['a','b','c','d','e']
      $two = []
      $output = values_at($one,$two)
      notice(inline_template('<%= @output.inspect %>'))
      EOS

      expect(apply_manifest(pp, :expect_failures => true).stderr).to match(/at least one positive index/)
    end

    it 'detects index ranges smaller than the start range'
    it 'handles index ranges larger than array'
    it 'handles non-integer indicies'
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'

describe 'values function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'returns an array of values' do
      pp = <<-EOS
      $arg = {
        'a' => 1,
        'b' => 2,
        'c' => 3,
      }
      $output = values($arg)
      notice(inline_template('<%= @output.sort.inspect %>'))
      EOS
      if is_future_parser_enabled?
        expect(apply_manifest(pp, :catch_failures => true).stdout).to match(/\[1, 2, 3\]/)
      else
        expect(apply_manifest(pp, :catch_failures => true).stdout).to match(/\["1", "2", "3"\]/)
      end

    end
  end
  describe 'failure' do
    it 'handles non-hash arguments' do
      pp = <<-EOS
      $arg = "foo"
      $output = values($arg)
      notice(inline_template('<%= @output.inspect %>'))
      EOS

      expect(apply_manifest(pp, :expect_failures => true).stderr).to match(/Requires hash/)
    end
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper_acceptance'
require 'puppet'

describe 'zip function', :unless => UNSUPPORTED_PLATFORMS.include?(fact('operatingsystem')) do
  describe 'success' do
    it 'zips two arrays of numbers together' do
      pp = <<-EOS
      $one = [1,2,3,4]
      $two = [5,6,7,8]
      $output = zip($one,$two)
      notice(inline_template('<%= @output.inspect %>'))
      EOS
      if is_future_parser_enabled?
        expect(apply_manifest(pp, :catch_failures => true).stdout).to match(/\[\[1, 5\], \[2, 6\], \[3, 7\], \[4, 8\]\]/)
      else
        expect(apply_manifest(pp, :catch_failures => true).stdout).to match(/\[\["1", "5"\], \["2", "6"\], \["3", "7"\], \["4", "8"\]\]/)
      end
    end
    it 'zips two arrays of numbers & bools together' do
      pp = <<-EOS
      $one = [1,2,"three",4]
      $two = [true,true,false,false]
      $output = zip($one,$two)
      notice(inline_template('<%= @output.inspect %>'))
      EOS
      if is_future_parser_enabled?
        expect(apply_manifest(pp, :catch_failures => true).stdout).to match(/\[\[1, true\], \[2, true\], \["three", false\], \[4, false\]\]/)
      else
        expect(apply_manifest(pp, :catch_failures => true).stdout).to match(/\[\["1", true\], \["2", true\], \["three", false\], \["4", false\]\]/)
      end
    end
    it 'zips two arrays of numbers together and flattens them' do
      # XXX This only tests the argument `true`, even though the following are valid:
      # 1 t y true yes
      # 0 f n false no
      # undef undefined
      pp = <<-EOS
      $one = [1,2,3,4]
      $two = [5,6,7,8]
      $output = zip($one,$two,true)
      notice(inline_template('<%= @output.inspect %>'))
      EOS
      if is_future_parser_enabled?
        expect(apply_manifest(pp, :catch_failures => true).stdout).to match(/\[1, 5, 2, 6, 3, 7, 4, 8\]/)
      else
        expect(apply_manifest(pp, :catch_failures => true).stdout).to match(/\["1", "5", "2", "6", "3", "7", "4", "8"\]/)
      end
    end
    it 'handles unmatched length' do
      # XXX Is this expected behavior?
      pp = <<-EOS
      $one = [1,2]
      $two = [5,6,7,8]
      $output = zip($one,$two)
      notice(inline_template('<%= @output.inspect %>'))
      EOS
      if is_future_parser_enabled?
        expect(apply_manifest(pp, :catch_failures => true).stdout).to match(/\[\[1, 5\], \[2, 6\]\]/)
      else
        expect(apply_manifest(pp, :catch_failures => true).stdout).to match(/\[\["1", "5"\], \["2", "6"\]\]/)
      end
    end
  end
  describe 'failure' do
    it 'handles improper number of arguments' do
      pp = <<-EOS
      $one = [1,2]
      $output = zip($one)
      notice(inline_template('<%= @output.inspect %>'))
      EOS

      expect(apply_manifest(pp, :expect_failures => true).stderr).to match(/Wrong number of arguments/)
    end
    it 'handles improper argument types' do
      pp = <<-EOS
      $one = "a string"
      $two = [5,6,7,8]
      $output = zip($one,$two)
      notice(inline_template('<%= @output.inspect %>'))
      EOS

      expect(apply_manifest(pp, :expect_failures => true).stderr).to match(/Requires array/)
    end
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'
require 'puppet_spec/compiler'

describe "anchorrefresh" do
  include PuppetSpec::Compiler

  let :transaction do
    apply_compiled_manifest(<<-ANCHORCLASS)
      class anchored {
        anchor { 'anchored::begin': }
        ~> anchor { 'anchored::end': }
      }

      class anchorrefresh {
        notify { 'first': }
        ~> class { 'anchored': }
        ~> anchor { 'final': }
      }

      include anchorrefresh
    ANCHORCLASS
  end

  it 'propagates events through the anchored class' do
    resource = transaction.resource_status('Anchor[final]')

    expect(resource.restarted).to eq(true)
  end
end
#! /usr/bin/env ruby -S rspec

require 'spec_helper'

describe "the abs function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("abs")).to eq("function_abs")
  end

  it "should raise a ParseError if there is less than 1 arguments" do
    expect { scope.function_abs([]) }.to( raise_error(Puppet::ParseError))
  end

  it "should convert a negative number into a positive" do
    result = scope.function_abs(["-34"])
    expect(result).to(eq(34))
  end

  it "should do nothing with a positive number" do
    result = scope.function_abs(["5678"])
    expect(result).to(eq(5678))
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the any2array function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("any2array")).to eq("function_any2array")
  end

  it "should return an empty array if there is less than 1 argument" do
    result = scope.function_any2array([])
    expect(result).to(eq([]))
  end

  it "should convert boolean true to [ true ] " do
    result = scope.function_any2array([true])
    expect(result).to(eq([true]))
  end

  it "should convert one object to [object]" do
    result = scope.function_any2array(['one'])
    expect(result).to(eq(['one']))
  end

  it "should convert multiple objects to [objects]" do
    result = scope.function_any2array(['one', 'two'])
    expect(result).to(eq(['one', 'two']))
  end

  it "should return empty array it was called with" do
    result = scope.function_any2array([[]])
    expect(result).to(eq([]))
  end

  it "should return one-member array it was called with" do
    result = scope.function_any2array([['string']])
    expect(result).to(eq(['string']))
  end

  it "should return multi-member array it was called with" do
    result = scope.function_any2array([['one', 'two']])
    expect(result).to(eq(['one', 'two']))
  end

  it "should return members of a hash it was called with" do
    result = scope.function_any2array([{ 'key' => 'value' }])
    expect(result).to(eq(['key', 'value']))
  end

  it "should return an empty array if it was called with an empty hash" do
    result = scope.function_any2array([{ }])
    expect(result).to(eq([]))
  end
end
#! /usr/bin/env ruby -S rspec

require 'spec_helper'

describe "the base64 function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("base64")).to eq("function_base64")
  end

  it "should raise a ParseError if there are other than 2 arguments" do
    expect { scope.function_base64([]) }.to(raise_error(Puppet::ParseError))
    expect { scope.function_base64(["asdf"]) }.to(raise_error(Puppet::ParseError))
    expect { scope.function_base64(["asdf","moo","cow"]) }.to(raise_error(Puppet::ParseError))
  end

  it "should raise a ParseError if argument 1 isn't 'encode' or 'decode'" do
    expect { scope.function_base64(["bees","astring"]) }.to(raise_error(Puppet::ParseError, /first argument must be one of/))
  end

  it "should raise a ParseError if argument 2 isn't a string" do
    expect { scope.function_base64(["encode",["2"]]) }.to(raise_error(Puppet::ParseError, /second argument must be a string/))
  end

  it "should encode a encoded string" do
    result = scope.function_base64(["encode",'thestring'])
    expect(result).to match(/\AdGhlc3RyaW5n\n\Z/)
  end
  it "should decode a base64 encoded string" do
    result = scope.function_base64(["decode",'dGhlc3RyaW5n'])
    expect(result).to eq('thestring')
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the bool2num function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("bool2num")).to eq("function_bool2num")
  end

  it "should raise a ParseError if there is less than 1 arguments" do
    expect { scope.function_bool2num([]) }.to( raise_error(Puppet::ParseError))
  end

  it "should convert true to 1" do
    result = scope.function_bool2num([true])
    expect(result).to(eq(1))
  end

  it "should convert 'true' to 1" do
    result = scope.function_bool2num(['true'])
    result.should(eq(1))
  end

  it "should convert 'false' to 0" do
    result = scope.function_bool2num(['false'])
    expect(result).to(eq(0))
  end

  it "should accept objects which extend String" do
    class AlsoString < String
    end

    value = AlsoString.new('true')
    result = scope.function_bool2num([value])
    result.should(eq(1))
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the capitalize function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("capitalize")).to eq("function_capitalize")
  end

  it "should raise a ParseError if there is less than 1 arguments" do
    expect { scope.function_capitalize([]) }.to( raise_error(Puppet::ParseError))
  end

  it "should capitalize the beginning of a string" do
    result = scope.function_capitalize(["abc"])
    expect(result).to(eq("Abc"))
  end

  it "should accept objects which extend String" do
    class AlsoString < String
    end

    value = AlsoString.new('abc')
    result = scope.function_capitalize([value])
    result.should(eq('Abc'))
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the chomp function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("chomp")).to eq("function_chomp")
  end

  it "should raise a ParseError if there is less than 1 arguments" do
    expect { scope.function_chomp([]) }.to( raise_error(Puppet::ParseError))
  end

  it "should chomp the end of a string" do
    result = scope.function_chomp(["abc\n"])
    expect(result).to(eq("abc"))
  end

  it "should accept objects which extend String" do
    class AlsoString < String
    end

    value = AlsoString.new("abc\n")
    result = scope.function_chomp([value])
    result.should(eq("abc"))
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the chop function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("chop")).to eq("function_chop")
  end

  it "should raise a ParseError if there is less than 1 arguments" do
    expect { scope.function_chop([]) }.to( raise_error(Puppet::ParseError))
  end

  it "should chop the end of a string" do
    result = scope.function_chop(["asdf\n"])
    expect(result).to(eq("asdf"))
  end

  it "should accept objects which extend String" do
    class AlsoString < String
    end

    value = AlsoString.new("abc\n")
    result = scope.function_chop([value])
    result.should(eq('abc'))
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the concat function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should raise a ParseError if the client does not provide two arguments" do
    expect { scope.function_concat([]) }.to(raise_error(Puppet::ParseError))
  end

  it "should raise a ParseError if the first parameter is not an array" do
    expect { scope.function_concat([1, []])}.to(raise_error(Puppet::ParseError))
  end

  it "should be able to concat an array" do
    result = scope.function_concat([['1','2','3'],['4','5','6']])
    expect(result).to(eq(['1','2','3','4','5','6']))
  end

  it "should be able to concat a primitive to an array" do
    result = scope.function_concat([['1','2','3'],'4'])
    expect(result).to(eq(['1','2','3','4']))
  end

  it "should not accidentally flatten nested arrays" do
    result = scope.function_concat([['1','2','3'],[['4','5'],'6']])
    expect(result).to(eq(['1','2','3',['4','5'],'6']))
  end

  it "should leave the original array intact" do
    array_original = ['1','2','3']
    result = scope.function_concat([array_original,['4','5','6']])
    array_original.should(eq(['1','2','3']))
  end
end
#! /usr/bin/env ruby -S rspec

require 'spec_helper'

describe "the count function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("count")).to eq("function_count")
  end

  it "should raise a ArgumentError if there is more than 2 arguments" do
    expect { scope.function_count(['foo', 'bar', 'baz']) }.to( raise_error(ArgumentError))
  end

  it "should be able to count arrays" do
    expect(scope.function_count([["1","2","3"]])).to(eq(3))
  end

  it "should be able to count matching elements in arrays" do
    expect(scope.function_count([["1", "2", "2"], "2"])).to(eq(2))
  end

  it "should not count nil or empty strings" do
    expect(scope.function_count([["foo","bar",nil,""]])).to(eq(2))
  end

  it 'does not count an undefined hash key or an out of bound array index (which are both :undef)' do
    expect(scope.function_count([["foo",:undef,:undef]])).to eq(1)
  end
end
#! /usr/bin/env ruby -S rspec

require 'spec_helper'

describe Puppet::Parser::Functions.function(:deep_merge) do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  describe 'when calling deep_merge from puppet' do
    it "should not compile when no arguments are passed" do
      skip("Fails on 2.6.x, see bug #15912") if Puppet.version =~ /^2\.6\./
      Puppet[:code] = '$x = deep_merge()'
      expect {
        scope.compiler.compile
      }.to raise_error(Puppet::ParseError, /wrong number of arguments/)
    end

    it "should not compile when 1 argument is passed" do
      skip("Fails on 2.6.x, see bug #15912") if Puppet.version =~ /^2\.6\./
      Puppet[:code] = "$my_hash={'one' => 1}\n$x = deep_merge($my_hash)"
      expect {
        scope.compiler.compile
      }.to raise_error(Puppet::ParseError, /wrong number of arguments/)
    end
  end

  describe 'when calling deep_merge on the scope instance' do
    it 'should require all parameters are hashes' do
      expect { new_hash = scope.function_deep_merge([{}, '2'])}.to raise_error(Puppet::ParseError, /unexpected argument type String/)
      expect { new_hash = scope.function_deep_merge([{}, 2])}.to raise_error(Puppet::ParseError, /unexpected argument type Fixnum/)
    end

    it 'should accept empty strings as puppet undef' do
      expect { new_hash = scope.function_deep_merge([{}, ''])}.not_to raise_error
    end

    it 'should be able to deep_merge two hashes' do
      new_hash = scope.function_deep_merge([{'one' => '1', 'two' => '1'}, {'two' => '2', 'three' => '2'}])
      expect(new_hash['one']).to   eq('1')
      expect(new_hash['two']).to   eq('2')
      expect(new_hash['three']).to eq('2')
    end

    it 'should deep_merge multiple hashes' do
      hash = scope.function_deep_merge([{'one' => 1}, {'one' => '2'}, {'one' => '3'}])
      expect(hash['one']).to eq('3')
    end

    it 'should accept empty hashes' do
      expect(scope.function_deep_merge([{},{},{}])).to eq({})
    end

    it 'should deep_merge subhashes' do
      hash = scope.function_deep_merge([{'one' => 1}, {'two' => 2, 'three' => { 'four' => 4 } }])
      expect(hash['one']).to eq(1)
      expect(hash['two']).to eq(2)
      expect(hash['three']).to eq({ 'four' => 4 })
    end

    it 'should append to subhashes' do
      hash = scope.function_deep_merge([{'one' => { 'two' => 2 } }, { 'one' => { 'three' => 3 } }])
      expect(hash['one']).to eq({ 'two' => 2, 'three' => 3 })
    end

    it 'should append to subhashes 2' do
      hash = scope.function_deep_merge([{'one' => 1, 'two' => 2, 'three' => { 'four' => 4 } }, {'two' => 'dos', 'three' => { 'five' => 5 } }])
      expect(hash['one']).to eq(1)
      expect(hash['two']).to eq('dos')
      expect(hash['three']).to eq({ 'four' => 4, 'five' => 5 })
    end

    it 'should append to subhashes 3' do
      hash = scope.function_deep_merge([{ 'key1' => { 'a' => 1, 'b' => 2 }, 'key2' => { 'c' => 3 } }, { 'key1' => { 'b' => 99 } }])
      expect(hash['key1']).to eq({ 'a' => 1, 'b' => 99 })
      expect(hash['key2']).to eq({ 'c' => 3 })
    end

    it 'should not change the original hashes' do
      hash1 = {'one' => { 'two' => 2 } }
      hash2 = { 'one' => { 'three' => 3 } }
      hash = scope.function_deep_merge([hash1, hash2])
      expect(hash1).to eq({'one' => { 'two' => 2 } })
      expect(hash2).to eq({ 'one' => { 'three' => 3 } })
      expect(hash['one']).to eq({ 'two' => 2, 'three' => 3 })
    end

    it 'should not change the original hashes 2' do
      hash1 = {'one' => { 'two' => [1,2] } }
      hash2 = { 'one' => { 'three' => 3 } }
      hash = scope.function_deep_merge([hash1, hash2])
      expect(hash1).to eq({'one' => { 'two' => [1,2] } })
      expect(hash2).to eq({ 'one' => { 'three' => 3 } })
      expect(hash['one']).to eq({ 'two' => [1,2], 'three' => 3 })
    end

    it 'should not change the original hashes 3' do
      hash1 = {'one' => { 'two' => [1,2, {'two' => 2} ] } }
      hash2 = { 'one' => { 'three' => 3 } }
      hash = scope.function_deep_merge([hash1, hash2])
      expect(hash1).to eq({'one' => { 'two' => [1,2, {'two' => 2}] } })
      expect(hash2).to eq({ 'one' => { 'three' => 3 } })
      expect(hash['one']).to eq({ 'two' => [1,2, {'two' => 2} ], 'three' => 3 })
      expect(hash['one']['two']).to eq([1,2, {'two' => 2}])
    end
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

require 'rspec-puppet'
describe 'defined_with_params' do
  describe 'when a resource is not specified' do
    it { is_expected.to run.with_params().and_raise_error(ArgumentError) }
  end
  describe 'when compared against a resource with no attributes' do
    let :pre_condition do
      'user { "dan": }'
    end
    it do
      is_expected.to run.with_params('User[dan]', {}).and_return(true)
      is_expected.to run.with_params('User[bob]', {}).and_return(false)
      is_expected.to run.with_params('User[dan]', {'foo' => 'bar'}).and_return(false)
    end
  end

  describe 'when compared against a resource with attributes' do
    let :pre_condition do
      'user { "dan": ensure => present, shell => "/bin/csh", managehome => false}'
    end
    it do
      is_expected.to run.with_params('User[dan]', {}).and_return(true)
      is_expected.to run.with_params('User[dan]', '').and_return(true)
      is_expected.to run.with_params('User[dan]', {'ensure' => 'present'}
                            ).and_return(true)
      is_expected.to run.with_params('User[dan]',
                             {'ensure' => 'present', 'managehome' => false}
                            ).and_return(true)
      is_expected.to run.with_params('User[dan]',
                             {'ensure' => 'absent', 'managehome' => false}
                            ).and_return(false)
    end
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the delete_at function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("delete_at")).to eq("function_delete_at")
  end

  it "should raise a ParseError if there is less than 1 arguments" do
    expect { scope.function_delete_at([]) }.to( raise_error(Puppet::ParseError))
  end

  it "should delete an item at specified location from an array" do
    result = scope.function_delete_at([['a','b','c'],1])
    expect(result).to(eq(['a','c']))
  end

  it "should not change origin array passed as argument" do
    origin_array = ['a','b','c','d']
    result = scope.function_delete_at([origin_array, 1])
    expect(origin_array).to(eq(['a','b','c','d']))
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the delete function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("delete")).to eq("function_delete")
  end

  it "should raise a ParseError if there are fewer than 2 arguments" do
    expect { scope.function_delete([]) }.to( raise_error(Puppet::ParseError))
  end

  it "should raise a ParseError if there are greater than 2 arguments" do
    expect { scope.function_delete([[], 'foo', 'bar']) }.to( raise_error(Puppet::ParseError))
  end

  it "should raise a TypeError if a number is passed as the first argument" do
    expect { scope.function_delete([1, 'bar']) }.to( raise_error(TypeError))
  end

  it "should delete all instances of an element from an array" do
    result = scope.function_delete([['a','b','c','b'],'b'])
    expect(result).to(eq(['a','c']))
  end

  it "should delete all instances of a substring from a string" do
    result = scope.function_delete(['foobarbabarz','bar'])
    expect(result).to(eq('foobaz'))
  end

  it "should delete a key from a hash" do
    result = scope.function_delete([{ 'a' => 1, 'b' => 2, 'c' => 3 },'b'])
    expect(result).to(eq({ 'a' => 1, 'c' => 3 }))
  end

  it "should not change origin array passed as argument" do
    origin_array = ['a','b','c','d']
    result = scope.function_delete([origin_array, 'b'])
    expect(origin_array).to(eq(['a','b','c','d']))
  end

  it "should not change the origin string passed as argument" do
    origin_string = 'foobarbabarz'
    result = scope.function_delete([origin_string,'bar'])
    expect(origin_string).to(eq('foobarbabarz'))
  end

  it "should not change origin hash passed as argument" do
    origin_hash = { 'a' => 1, 'b' => 2, 'c' => 3 }
    result = scope.function_delete([origin_hash, 'b'])
    expect(origin_hash).to(eq({ 'a' => 1, 'b' => 2, 'c' => 3 }))
  end

end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the delete_undef_values function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("delete_undef_values")).to eq("function_delete_undef_values")
  end

  it "should raise a ParseError if there is less than 1 argument" do
    expect { scope.function_delete_undef_values([]) }.to( raise_error(Puppet::ParseError))
  end

  it "should raise a ParseError if the argument is not Array nor Hash" do
    expect { scope.function_delete_undef_values(['']) }.to( raise_error(Puppet::ParseError))
    expect { scope.function_delete_undef_values([nil]) }.to( raise_error(Puppet::ParseError))
  end

  it "should delete all undef items from Array and only these" do
    result = scope.function_delete_undef_values([['a',:undef,'c','undef']])
    expect(result).to(eq(['a','c','undef']))
  end

  it "should delete all undef items from Hash and only these" do
    result = scope.function_delete_undef_values([{'a'=>'A','b'=>:undef,'c'=>'C','d'=>'undef'}])
    expect(result).to(eq({'a'=>'A','c'=>'C','d'=>'undef'}))
  end

  it "should not change origin array passed as argument" do
    origin_array = ['a',:undef,'c','undef']
    result = scope.function_delete_undef_values([origin_array])
    expect(origin_array).to(eq(['a',:undef,'c','undef']))
  end

  it "should not change origin hash passed as argument" do
    origin_hash = { 'a' => 1, 'b' => :undef, 'c' => 'undef' }
    result = scope.function_delete_undef_values([origin_hash])
    expect(origin_hash).to(eq({ 'a' => 1, 'b' => :undef, 'c' => 'undef' }))
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the delete_values function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("delete_values")).to eq("function_delete_values")
  end

  it "should raise a ParseError if there are fewer than 2 arguments" do
    expect { scope.function_delete_values([]) }.to( raise_error(Puppet::ParseError))
  end

  it "should raise a ParseError if there are greater than 2 arguments" do
    expect { scope.function_delete_values([[], 'foo', 'bar']) }.to( raise_error(Puppet::ParseError))
  end

  it "should raise a TypeError if the argument is not a hash" do
    expect { scope.function_delete_values([1,'bar']) }.to( raise_error(TypeError))
    expect { scope.function_delete_values(['foo','bar']) }.to( raise_error(TypeError))
    expect { scope.function_delete_values([[],'bar']) }.to( raise_error(TypeError))
  end

  it "should delete all instances of a value from a hash" do
    result = scope.function_delete_values([{ 'a'=>'A', 'b'=>'B', 'B'=>'C', 'd'=>'B' },'B'])
    expect(result).to(eq({ 'a'=>'A', 'B'=>'C' }))
  end

  it "should not change origin hash passed as argument" do
    origin_hash = { 'a' => 1, 'b' => 2, 'c' => 3 }
    result = scope.function_delete_values([origin_hash, 2])
    expect(origin_hash).to(eq({ 'a' => 1, 'b' => 2, 'c' => 3 }))
  end

end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the difference function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("difference")).to eq("function_difference")
  end

  it "should raise a ParseError if there are fewer than 2 arguments" do
    expect { scope.function_difference([]) }.to( raise_error(Puppet::ParseError) )
  end

  it "should return the difference between two arrays" do
    result = scope.function_difference([["a","b","c"],["b","c","d"]])
    expect(result).to(eq(["a"]))
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the dirname function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("dirname")).to eq("function_dirname")
  end

  it "should raise a ParseError if there is less than 1 arguments" do
    expect { scope.function_dirname([]) }.to( raise_error(Puppet::ParseError))
  end

  it "should return dirname for an absolute path" do
    result = scope.function_dirname(['/path/to/a/file.ext'])
    expect(result).to(eq('/path/to/a'))
  end

  it "should return dirname for a relative path" do
    result = scope.function_dirname(['path/to/a/file.ext'])
    expect(result).to(eq('path/to/a'))
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the downcase function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("downcase")).to eq("function_downcase")
  end

  it "should raise a ParseError if there is less than 1 arguments" do
    expect { scope.function_downcase([]) }.to( raise_error(Puppet::ParseError))
  end

  it "should downcase a string" do
    result = scope.function_downcase(["ASFD"])
    expect(result).to(eq("asfd"))
  end

  it "should do nothing to a string that is already downcase" do
    result = scope.function_downcase(["asdf asdf"])
    expect(result).to(eq("asdf asdf"))
  end

  it "should accept objects which extend String" do
    class AlsoString < String
    end

    value = AlsoString.new("ASFD")
    result = scope.function_downcase([value])
    result.should(eq('asfd'))
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the empty function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
  it "should exist" do
    expect(Puppet::Parser::Functions.function("empty")).to eq("function_empty")
  end

  it "should raise a ParseError if there is less than 1 arguments" do
    expect { scope.function_empty([]) }.to( raise_error(Puppet::ParseError))
  end

  it "should return a true for an empty string" do
    result = scope.function_empty([''])
    expect(result).to(eq(true))
  end

  it "should return a false for a non-empty string" do
    result = scope.function_empty(['asdf'])
    expect(result).to(eq(false))
  end

  it "should accept objects which extend String" do
    class AlsoString < String
    end

    value = AlsoString.new()
    result = scope.function_empty([value])
    result.should(eq(true))
  end
end
#! /usr/bin/env ruby

require 'spec_helper'
require 'rspec-puppet'
require 'puppet_spec/compiler'

describe 'ensure_packages' do
  include PuppetSpec::Compiler

  before :each do
    Puppet::Parser::Functions.autoloader.loadall
    Puppet::Parser::Functions.function(:ensure_packages)
    Puppet::Parser::Functions.function(:ensure_resource)
    Puppet::Parser::Functions.function(:defined_with_params)
    Puppet::Parser::Functions.function(:create_resources)
  end

  let :node     do Puppet::Node.new('localhost') end
  let :compiler do Puppet::Parser::Compiler.new(node) end
  let :scope    do
    if Puppet.version.to_f >= 3.0
      Puppet::Parser::Scope.new(compiler)
    else
      newscope = Puppet::Parser::Scope.new
      newscope.compiler = compiler
      newscope.source   = Puppet::Resource::Type.new(:node, :localhost)
      newscope
    end
  end

  describe 'argument handling' do
    it 'fails with no arguments' do
      expect {
        scope.function_ensure_packages([])
      }.to raise_error(Puppet::ParseError, /0 for 1 or 2/)
    end

    it 'accepts an array of values' do
      scope.function_ensure_packages([['foo']])
    end

    it 'accepts a single package name as a string' do
      scope.function_ensure_packages(['foo'])
    end
  end

  context 'given a catalog with puppet package => absent' do
    let :catalog do
      compile_to_catalog(<<-EOS
        ensure_packages(['facter'])
        package { puppet: ensure => absent }
      EOS
      )
    end

    it 'has no effect on Package[puppet]' do
      expect(catalog.resource(:package, 'puppet')['ensure']).to eq('absent')
    end
  end

  context 'given a clean catalog' do
    let :catalog do
      compile_to_catalog('ensure_packages(["facter"])')
    end

    it 'declares package resources with ensure => present' do
      expect(catalog.resource(:package, 'facter')['ensure']).to eq('present')
    end
  end

  context 'given a clean catalog and specified defaults' do
    let :catalog do
      compile_to_catalog('ensure_packages(["facter"], {"provider" => "gem"})')
    end

    it 'declares package resources with ensure => present' do
      expect(catalog.resource(:package, 'facter')['ensure']).to eq('present')
      expect(catalog.resource(:package, 'facter')['provider']).to eq('gem')
    end
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'
require 'rspec-puppet'
require 'puppet_spec/compiler'

describe 'ensure_resource' do
  include PuppetSpec::Compiler

  before :all do
    Puppet::Parser::Functions.autoloader.loadall
    Puppet::Parser::Functions.function(:ensure_packages)
  end

  let :node     do Puppet::Node.new('localhost') end
  let :compiler do Puppet::Parser::Compiler.new(node) end
  let :scope    do Puppet::Parser::Scope.new(compiler) end

  describe 'when a type or title is not specified' do
    it { expect { scope.function_ensure_resource([]) }.to raise_error }
    it { expect { scope.function_ensure_resource(['type']) }.to raise_error }
  end

  describe 'when compared against a resource with no attributes' do
    let :catalog do
      compile_to_catalog(<<-EOS
        user { "dan": }
        ensure_resource('user', 'dan', {})
      EOS
      )
    end

    it 'should contain the the ensured resources' do
      expect(catalog.resource(:user, 'dan').to_s).to eq('User[dan]')
    end
  end

  describe 'works when compared against a resource with non-conflicting attributes' do
    [
      "ensure_resource('User', 'dan', {})",
      "ensure_resource('User', 'dan', '')",
      "ensure_resource('User', 'dan', {'ensure' => 'present'})",
      "ensure_resource('User', 'dan', {'ensure' => 'present', 'managehome' => false})"
    ].each do |ensure_resource|
      pp = <<-EOS
        user { "dan": ensure => present, shell => "/bin/csh", managehome => false}
        #{ensure_resource}
      EOS

      it { expect { compile_to_catalog(pp) }.to_not raise_error }
    end
  end

  describe 'fails when compared against a resource with conflicting attributes' do
    pp = <<-EOS
      user { "dan": ensure => present, shell => "/bin/csh", managehome => false}
      ensure_resource('User', 'dan', {'ensure' => 'absent', 'managehome' => false})
    EOS

    it { expect { compile_to_catalog(pp) }.to raise_error }
  end

  describe 'when an array of new resources are passed in' do
    let :catalog do
      compile_to_catalog("ensure_resource('User', ['dan', 'alex'], {})")
    end

    it 'should contain the ensured resources' do
      expect(catalog.resource('User[dan]').to_s).to eq('User[dan]')
      expect(catalog.resource('User[alex]').to_s).to eq('User[alex]')
    end
  end

  describe 'when an array of existing resources is compared against existing resources' do
    pp = <<-EOS
      user { 'dan': ensure => present; 'alex': ensure => present }
      ensure_resource('User', ['dan', 'alex'], {})
    EOS

    let :catalog do
      compile_to_catalog(pp)
    end

    it 'should return the existing resources' do
      expect(catalog.resource('User[dan]').to_s).to eq('User[dan]')
      expect(catalog.resource('User[alex]').to_s).to eq('User[alex]')
    end
  end

  describe 'works when compared against existing resources with attributes' do
    [
      "ensure_resource('User', ['dan', 'alex'], {})",
      "ensure_resource('User', ['dan', 'alex'], '')",
      "ensure_resource('User', ['dan', 'alex'], {'ensure' => 'present'})",
    ].each do |ensure_resource|
      pp = <<-EOS
        user { 'dan': ensure => present; 'alex': ensure => present }
        #{ensure_resource}
      EOS

      it { expect { compile_to_catalog(pp) }.to_not raise_error }
    end
  end

  describe 'fails when compared against existing resources with conflicting attributes' do
    pp = <<-EOS
      user { 'dan': ensure => present; 'alex': ensure => present }
      ensure_resource('User', ['dan', 'alex'], {'ensure' => 'absent'})
    EOS

    it { expect { compile_to_catalog(pp) }.to raise_error }
  end

end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the flatten function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
  it "should exist" do
    expect(Puppet::Parser::Functions.function("flatten")).to eq("function_flatten")
  end

  it "should raise a ParseError if there is less than 1 arguments" do
    expect { scope.function_flatten([]) }.to( raise_error(Puppet::ParseError))
  end

  it "should raise a ParseError if there is more than 1 argument" do
    expect { scope.function_flatten([[], []]) }.to( raise_error(Puppet::ParseError))
  end

  it "should flatten a complex data structure" do
    result = scope.function_flatten([["a","b",["c",["d","e"],"f","g"]]])
    expect(result).to(eq(["a","b","c","d","e","f","g"]))
  end

  it "should do nothing to a structure that is already flat" do
    result = scope.function_flatten([["a","b","c","d"]])
    expect(result).to(eq(["a","b","c","d"]))
  end
end
#! /usr/bin/env ruby -S rspec

require 'spec_helper'

describe "the floor function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("floor")).to eq("function_floor")
  end

  it "should raise a ParseError if there is less than 1 argument" do
    expect { scope.function_floor([]) }.to( raise_error(Puppet::ParseError, /Wrong number of arguments/))
  end

  it "should should raise a ParseError if input isn't numeric (eg. String)" do
    expect { scope.function_floor(["foo"]) }.to( raise_error(Puppet::ParseError, /Wrong argument type/))
  end

  it "should should raise a ParseError if input isn't numeric (eg. Boolean)" do
    expect { scope.function_floor([true]) }.to( raise_error(Puppet::ParseError, /Wrong argument type/))
  end

  it "should return an integer when a numeric type is passed" do
    result = scope.function_floor([12.4])
    expect(result.is_a?(Integer)).to(eq(true))
  end

  it "should return the input when an integer is passed" do
    result = scope.function_floor([7])
    expect(result).to(eq(7))
  end

  it "should return the largest integer less than or equal to the input" do
    result = scope.function_floor([3.8])
    expect(result).to(eq(3))
  end
end

#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the fqdn_rotate function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("fqdn_rotate")).to eq("function_fqdn_rotate")
  end

  it "should raise a ParseError if there is less than 1 arguments" do
    expect { scope.function_fqdn_rotate([]) }.to( raise_error(Puppet::ParseError))
  end

  it "should rotate a string and the result should be the same size" do
    scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.1")
    result = scope.function_fqdn_rotate(["asdf"])
    expect(result.size).to(eq(4))
  end

  it "should rotate a string to give the same results for one host" do
    scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.1").twice
    expect(scope.function_fqdn_rotate(["abcdefg"])).to eql(scope.function_fqdn_rotate(["abcdefg"]))
  end

  it "should rotate a string to give different values on different hosts" do
     scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.1")
     val1 = scope.function_fqdn_rotate(["abcdefghijklmnopqrstuvwxyz01234567890987654321"])
     scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.2")
     val2 = scope.function_fqdn_rotate(["abcdefghijklmnopqrstuvwxyz01234567890987654321"])
     expect(val1).not_to eql(val2)
  end

  it "should accept objects which extend String" do
    class AlsoString < String
    end

    scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.1")
    value = AlsoString.new("asdf")
    result = scope.function_fqdn_rotate([value])
    result.size.should(eq(4))
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe Puppet::Parser::Functions.function(:get_module_path) do
  Internals = PuppetlabsSpec::PuppetInternals
  class StubModule
    attr_reader :path
    def initialize(path)
      @path = path
    end
  end

  def scope(environment = "production")
    Internals.scope(:compiler => Internals.compiler(:node => Internals.node(:environment => environment)))
  end

  it 'should only allow one argument' do
    expect { scope.function_get_module_path([]) }.to raise_error(Puppet::ParseError, /Wrong number of arguments, expects one/)
    expect { scope.function_get_module_path(['1','2','3']) }.to raise_error(Puppet::ParseError, /Wrong number of arguments, expects one/)
  end
  it 'should raise an exception when the module cannot be found' do
    expect { scope.function_get_module_path(['foo']) }.to raise_error(Puppet::ParseError, /Could not find module/)
  end
  describe 'when locating a module' do
    let(:modulepath) { "/tmp/does_not_exist" }
    let(:path_of_module_foo) { StubModule.new("/tmp/does_not_exist/foo") }

    before(:each) { Puppet[:modulepath] = modulepath }

    it 'should be able to find module paths from the modulepath setting' do
      Puppet::Module.expects(:find).with('foo', 'production').returns(path_of_module_foo)
      expect(scope.function_get_module_path(['foo'])).to eq(path_of_module_foo.path)
    end
    it 'should be able to find module paths when the modulepath is a list' do
      Puppet[:modulepath] = modulepath + ":/tmp"
      Puppet::Module.expects(:find).with('foo', 'production').returns(path_of_module_foo)
      expect(scope.function_get_module_path(['foo'])).to eq(path_of_module_foo.path)
    end
    it 'should respect the environment' do
      skip("Disabled on Puppet 2.6.x") if Puppet.version =~ /^2\.6\b/
      Puppet.settings[:environment] = 'danstestenv'
      Puppet::Module.expects(:find).with('foo', 'danstestenv').returns(path_of_module_foo)
      expect(scope('danstestenv').function_get_module_path(['foo'])).to eq(path_of_module_foo.path)
    end
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'
require 'rspec-puppet'
require 'puppet_spec/compiler'

describe 'getparam' do
  include PuppetSpec::Compiler

  before :each do
    Puppet::Parser::Functions.autoloader.loadall
    Puppet::Parser::Functions.function(:getparam)
  end

  let :node     do Puppet::Node.new('localhost') end
  let :compiler do Puppet::Parser::Compiler.new(node) end
  if Puppet.version.to_f >= 3.0
    let :scope    do Puppet::Parser::Scope.new(compiler) end
  else
    let :scope    do
      newscope = Puppet::Parser::Scope.new
      newscope.compiler = compiler
      newscope.source   = Puppet::Resource::Type.new(:node, :localhost)
      newscope
    end
  end

  it "should exist" do
    expect(Puppet::Parser::Functions.function("getparam")).to eq("function_getparam")
  end

  describe 'when a resource is not specified' do
    it { expect { scope.function_getparam([]) }.to raise_error }
    it { expect { scope.function_getparam(['User[dan]']) }.to raise_error }
    it { expect { scope.function_getparam(['User[dan]']) }.to raise_error }
    it { expect { scope.function_getparam(['User[dan]', {}]) }.to raise_error }
    # This seems to be OK because we just check for a string.
    it { expect { scope.function_getparam(['User[dan]', '']) }.to_not raise_error }
  end

  describe 'when compared against a resource with no params' do
    let :catalog do
      compile_to_catalog(<<-EOS
        user { "dan": }
      EOS
      )
    end

    it do
      expect(scope.function_getparam(['User[dan]', 'shell'])).to eq('')
    end
  end

  describe 'when compared against a resource with params' do
    let :catalog do
      compile_to_catalog(<<-EOS
        user { 'dan': ensure => present, shell => '/bin/sh', managehome => false}
        $test = getparam(User[dan], 'shell')
      EOS
      )
    end

    it do
      resource = Puppet::Parser::Resource.new(:user, 'dan', {:scope => scope})
      resource.set_parameter('ensure', 'present')
      resource.set_parameter('shell', '/bin/sh')
      resource.set_parameter('managehome', false)
      compiler.add_resource(scope, resource)

      expect(scope.function_getparam(['User[dan]', 'shell'])).to eq('/bin/sh')
      expect(scope.function_getparam(['User[dan]', ''])).to eq('')
      expect(scope.function_getparam(['User[dan]', 'ensure'])).to eq('present')
      # TODO: Expected this to be false, figure out why we're getting '' back.
      expect(scope.function_getparam(['User[dan]', 'managehome'])).to eq('')
    end
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe Puppet::Parser::Functions.function(:getvar) do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
  describe 'when calling getvar from puppet' do

    it "should not compile when no arguments are passed" do
      skip("Fails on 2.6.x, see bug #15912") if Puppet.version =~ /^2\.6\./
      Puppet[:code] = '$foo = getvar()'
      expect {
        scope.compiler.compile
      }.to raise_error(Puppet::ParseError, /wrong number of arguments/)
    end

    it "should not compile when too many arguments are passed" do
      skip("Fails on 2.6.x, see bug #15912") if Puppet.version =~ /^2\.6\./
      Puppet[:code] = '$foo = getvar("foo::bar", "baz")'
      expect {
        scope.compiler.compile
      }.to raise_error(Puppet::ParseError, /wrong number of arguments/)
    end

    it "should lookup variables in other namespaces" do
      skip("Fails on 2.6.x, see bug #15912") if Puppet.version =~ /^2\.6\./
      Puppet[:code] = <<-'ENDofPUPPETcode'
        class site::data { $foo = 'baz' }
        include site::data
        $foo = getvar("site::data::foo")
        if $foo != 'baz' {
          fail('getvar did not return what we expect')
        }
      ENDofPUPPETcode
      scope.compiler.compile
    end
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the grep function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("grep")).to eq("function_grep")
  end

  it "should raise a ParseError if there is less than 1 arguments" do
    expect { scope.function_grep([]) }.to( raise_error(Puppet::ParseError))
  end

  it "should grep contents from an array" do
    result = scope.function_grep([["aaabbb","bbbccc","dddeee"], "bbb"])
    expect(result).to(eq(["aaabbb","bbbccc"]))
  end
end
#!/usr/bin/env ruby -S rspec
require 'spec_helper'

describe Puppet::Parser::Functions.function(:has_interface_with) do

  let(:scope) do
    PuppetlabsSpec::PuppetInternals.scope
  end

  # The subject of these examples is the method itself.
  subject do
    function_name = Puppet::Parser::Functions.function(:has_interface_with)
    scope.method(function_name)
  end

  # We need to mock out the Facts so we can specify how we expect this function
  # to behave on different platforms.
  context "On Mac OS X Systems" do
    before :each do
      scope.stubs(:lookupvar).with("interfaces").returns('lo0,gif0,stf0,en1,p2p0,fw0,en0,vmnet1,vmnet8,utun0')
    end
    it 'should have loopback (lo0)' do
      expect(subject.call(['lo0'])).to be_truthy
    end
    it 'should not have loopback (lo)' do
      expect(subject.call(['lo'])).to be_falsey
    end
  end
  context "On Linux Systems" do
    before :each do
      scope.stubs(:lookupvar).with("interfaces").returns('eth0,lo')
      scope.stubs(:lookupvar).with("ipaddress").returns('10.0.0.1')
      scope.stubs(:lookupvar).with("ipaddress_lo").returns('127.0.0.1')
      scope.stubs(:lookupvar).with("ipaddress_eth0").returns('10.0.0.1')
      scope.stubs(:lookupvar).with('muppet').returns('kermit')
      scope.stubs(:lookupvar).with('muppet_lo').returns('mspiggy')
      scope.stubs(:lookupvar).with('muppet_eth0').returns('kermit')
    end
    it 'should have loopback (lo)' do
      expect(subject.call(['lo'])).to be_truthy
    end
    it 'should not have loopback (lo0)' do
      expect(subject.call(['lo0'])).to be_falsey
    end
    it 'should have ipaddress with 127.0.0.1' do
      expect(subject.call(['ipaddress', '127.0.0.1'])).to be_truthy
    end
    it 'should have ipaddress with 10.0.0.1' do
      expect(subject.call(['ipaddress', '10.0.0.1'])).to be_truthy
    end
    it 'should not have ipaddress with 10.0.0.2' do
      expect(subject.call(['ipaddress', '10.0.0.2'])).to be_falsey
    end
    it 'should have muppet named kermit' do
      expect(subject.call(['muppet', 'kermit'])).to be_truthy
    end
    it 'should have muppet named mspiggy' do
      expect(subject.call(['muppet', 'mspiggy'])).to be_truthy
    end
    it 'should not have muppet named bigbird' do
      expect(subject.call(['muppet', 'bigbird'])).to be_falsey
    end
  end
end
#!/usr/bin/env ruby -S rspec
require 'spec_helper'

describe Puppet::Parser::Functions.function(:has_ip_address) do

  let(:scope) do
    PuppetlabsSpec::PuppetInternals.scope
  end

  subject do
    function_name = Puppet::Parser::Functions.function(:has_ip_address)
    scope.method(function_name)
  end

  context "On Linux Systems" do
    before :each do
      scope.stubs(:lookupvar).with('interfaces').returns('eth0,lo')
      scope.stubs(:lookupvar).with('ipaddress').returns('10.0.2.15')
      scope.stubs(:lookupvar).with('ipaddress_eth0').returns('10.0.2.15')
      scope.stubs(:lookupvar).with('ipaddress_lo').returns('127.0.0.1')
    end

    it 'should have primary address (10.0.2.15)' do
      expect(subject.call(['10.0.2.15'])).to be_truthy
    end

    it 'should have lookupback address (127.0.0.1)' do
      expect(subject.call(['127.0.0.1'])).to be_truthy
    end

    it 'should not have other address' do
      expect(subject.call(['192.1681.1.1'])).to be_falsey
    end

    it 'should not have "mspiggy" on an interface' do
      expect(subject.call(['mspiggy'])).to be_falsey
    end
  end
end
#!/usr/bin/env ruby -S rspec
require 'spec_helper'

describe Puppet::Parser::Functions.function(:has_ip_network) do

  let(:scope) do
    PuppetlabsSpec::PuppetInternals.scope
  end

  subject do
    function_name = Puppet::Parser::Functions.function(:has_ip_network)
    scope.method(function_name)
  end

  context "On Linux Systems" do
    before :each do
      scope.stubs(:lookupvar).with('interfaces').returns('eth0,lo')
      scope.stubs(:lookupvar).with('network').returns(:undefined)
      scope.stubs(:lookupvar).with('network_eth0').returns('10.0.2.0')
      scope.stubs(:lookupvar).with('network_lo').returns('127.0.0.1')
    end

    it 'should have primary network (10.0.2.0)' do
      expect(subject.call(['10.0.2.0'])).to be_truthy
    end

    it 'should have loopback network (127.0.0.0)' do
      expect(subject.call(['127.0.0.1'])).to be_truthy
    end

    it 'should not have other network' do
      expect(subject.call(['192.168.1.0'])).to be_falsey
    end
  end
end

#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe Puppet::Parser::Functions.function(:has_key) do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  describe 'when calling has_key from puppet' do
    it "should not compile when no arguments are passed" do
      skip("Fails on 2.6.x, see bug #15912") if Puppet.version =~ /^2\.6\./
      Puppet[:code] = '$x = has_key()'
      expect {
        scope.compiler.compile
      }.to raise_error(Puppet::ParseError, /wrong number of arguments/)
    end

    it "should not compile when 1 argument is passed" do
      skip("Fails on 2.6.x, see bug #15912") if Puppet.version =~ /^2\.6\./
      Puppet[:code] = "$x = has_key('foo')"
      expect {
        scope.compiler.compile
      }.to raise_error(Puppet::ParseError, /wrong number of arguments/)
    end

    it "should require the first value to be a Hash" do
      skip("Fails on 2.6.x, see bug #15912") if Puppet.version =~ /^2\.6\./
      Puppet[:code] = "$x = has_key('foo', 'bar')"
      expect {
        scope.compiler.compile
      }.to raise_error(Puppet::ParseError, /expects the first argument to be a hash/)
    end
  end

  describe 'when calling the function has_key from a scope instance' do
    it 'should detect existing keys' do
      expect(scope.function_has_key([{'one' => 1}, 'one'])).to be_truthy
    end

    it 'should detect existing keys' do
      expect(scope.function_has_key([{'one' => 1}, 'two'])).to be_falsey
    end
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the hash function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("hash")).to eq("function_hash")
  end

  it "should raise a ParseError if there is less than 1 arguments" do
    expect { scope.function_hash([]) }.to( raise_error(Puppet::ParseError))
  end

  it "should convert an array to a hash" do
    result = scope.function_hash([['a',1,'b',2,'c',3]])
    expect(result).to(eq({'a'=>1,'b'=>2,'c'=>3}))
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the intersection function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("intersection")).to eq("function_intersection")
  end

  it "should raise a ParseError if there are fewer than 2 arguments" do
    expect { scope.function_intersection([]) }.to( raise_error(Puppet::ParseError) )
  end

  it "should return the intersection of two arrays" do
    result = scope.function_intersection([["a","b","c"],["b","c","d"]])
    expect(result).to(eq(["b","c"]))
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the is_array function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("is_array")).to eq("function_is_array")
  end

  it "should raise a ParseError if there is less than 1 arguments" do
    expect { scope.function_is_array([]) }.to( raise_error(Puppet::ParseError))
  end

  it "should return true if passed an array" do
    result = scope.function_is_array([[1,2,3]])
    expect(result).to(eq(true))
  end

  it "should return false if passed a hash" do
    result = scope.function_is_array([{'a'=>1}])
    expect(result).to(eq(false))
  end

  it "should return false if passed a string" do
    result = scope.function_is_array(["asdf"])
    expect(result).to(eq(false))
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the is_bool function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("is_bool")).to eq("function_is_bool")
  end

  it "should raise a ParseError if there is less than 1 arguments" do
    expect { scope.function_is_bool([]) }.to( raise_error(Puppet::ParseError))
  end

  it "should return true if passed a TrueClass" do
    result = scope.function_is_bool([true])
    expect(result).to(eq(true))
  end

  it "should return true if passed a FalseClass" do
    result = scope.function_is_bool([false])
    expect(result).to(eq(true))
  end

  it "should return false if passed the string 'true'" do
    result = scope.function_is_bool(['true'])
    expect(result).to(eq(false))
  end

  it "should return false if passed the string 'false'" do
    result = scope.function_is_bool(['false'])
    expect(result).to(eq(false))
  end

  it "should return false if passed an array" do
    result = scope.function_is_bool([["a","b"]])
    expect(result).to(eq(false))
  end

  it "should return false if passed a hash" do
    result = scope.function_is_bool([{"a" => "b"}])
    expect(result).to(eq(false))
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the is_domain_name function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("is_domain_name")).to eq("function_is_domain_name")
  end

  it "should raise a ParseError if there is less than 1 arguments" do
    expect { scope.function_is_domain_name([]) }.to( raise_error(Puppet::ParseError))
  end

  it "should return true if a valid short domain name" do
    result = scope.function_is_domain_name(["x.com"])
    expect(result).to(be_truthy)
  end

  it "should return true if the domain is ." do
    result = scope.function_is_domain_name(["."])
    expect(result).to(be_truthy)
  end

  it "should return true if the domain is x.com." do
    result = scope.function_is_domain_name(["x.com."])
    expect(result).to(be_truthy)
  end

  it "should return true if a valid domain name" do
    result = scope.function_is_domain_name(["foo.bar.com"])
    expect(result).to(be_truthy)
  end

  it "should allow domain parts to start with numbers" do
    result = scope.function_is_domain_name(["3foo.2bar.com"])
    expect(result).to(be_truthy)
  end

  it "should allow domain to end with a dot" do
    result = scope.function_is_domain_name(["3foo.2bar.com."])
    expect(result).to(be_truthy)
  end

  it "should allow a single part domain" do
    result = scope.function_is_domain_name(["orange"])
    expect(result).to(be_truthy)
  end

  it "should return false if domain parts start with hyphens" do
    result = scope.function_is_domain_name(["-3foo.2bar.com"])
    expect(result).to(be_falsey)
  end

  it "should return true if domain contains hyphens" do
    result = scope.function_is_domain_name(["3foo-bar.2bar-fuzz.com"])
    expect(result).to(be_truthy)
  end

  it "should return false if domain name contains spaces" do
    result = scope.function_is_domain_name(["not valid"])
    expect(result).to(be_falsey)
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the is_float function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("is_float")).to eq("function_is_float")
  end

  it "should raise a ParseError if there is less than 1 arguments" do
    expect { scope.function_is_float([]) }.to( raise_error(Puppet::ParseError))
  end

  it "should return true if a float" do
    result = scope.function_is_float(["0.12"])
    expect(result).to(eq(true))
  end

  it "should return false if a string" do
    result = scope.function_is_float(["asdf"])
    expect(result).to(eq(false))
  end

  it "should return false if an integer" do
    result = scope.function_is_float(["3"])
    expect(result).to(eq(false))
  end
  it "should return true if a float is created from an arithmetical operation" do
    result = scope.function_is_float([3.2*2])
    expect(result).to(eq(true))
  end
end
#!/usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the is_function_available function" do
  before :all do
    Puppet::Parser::Functions.autoloader.loadall
  end

  before :each do
    @scope = Puppet::Parser::Scope.new
  end

  it "should exist" do
    expect(Puppet::Parser::Functions.function("is_function_available")).to eq("function_is_function_available")
  end

  it "should raise a ParseError if there is less than 1 arguments" do
    expect { @scope.function_is_function_available([]) }.to( raise_error(Puppet::ParseError))
  end

  it "should return false if a nonexistent function is passed" do
    result = @scope.function_is_function_available(['jeff_mccunes_left_sock'])
    expect(result).to(eq(false))
  end

  it "should return true if an available function is passed" do
    result = @scope.function_is_function_available(['require'])
    expect(result).to(eq(true))
  end

end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the is_hash function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("is_hash")).to eq("function_is_hash")
  end

  it "should raise a ParseError if there is less than 1 arguments" do
    expect { scope.function_is_hash([]) }.to( raise_error(Puppet::ParseError))
  end

  it "should return true if passed a hash" do
    result = scope.function_is_hash([{"a"=>1,"b"=>2}])
    expect(result).to(eq(true))
  end

  it "should return false if passed an array" do
    result = scope.function_is_hash([["a","b"]])
    expect(result).to(eq(false))
  end

  it "should return false if passed a string" do
    result = scope.function_is_hash(["asdf"])
    expect(result).to(eq(false))
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the is_integer function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("is_integer")).to eq("function_is_integer")
  end

  it "should raise a ParseError if there is less than 1 arguments" do
    expect { scope.function_is_integer([]) }.to( raise_error(Puppet::ParseError))
  end

  it "should return true if an integer" do
    result = scope.function_is_integer(["3"])
    expect(result).to(eq(true))
  end

  it "should return true if a negative integer" do
    result = scope.function_is_integer(["-7"])
    expect(result).to(eq(true))
  end

  it "should return false if a float" do
    result = scope.function_is_integer(["3.2"])
    expect(result).to(eq(false))
  end

  it "should return false if a string" do
    result = scope.function_is_integer(["asdf"])
    expect(result).to(eq(false))
  end

  it "should return true if an integer is created from an arithmetical operation" do
    result = scope.function_is_integer([3*2])
    expect(result).to(eq(true))
  end

  it "should return false if an array" do
    result = scope.function_is_numeric([["asdf"]])
    expect(result).to(eq(false))
  end

  it "should return false if a hash" do
    result = scope.function_is_numeric([{"asdf" => false}])
    expect(result).to(eq(false))
  end

  it "should return false if a boolean" do
    result = scope.function_is_numeric([true])
    expect(result).to(eq(false))
  end

  it "should return false if a whitespace is in the string" do
    result = scope.function_is_numeric([" -1324"])
    expect(result).to(eq(false))
  end

  it "should return false if it is zero prefixed" do
    result = scope.function_is_numeric(["0001234"])
    expect(result).to(eq(false))
  end

  it "should return false if it is wrapped inside an array" do
    result = scope.function_is_numeric([[1234]])
    expect(result).to(eq(false))
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the is_ip_address function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("is_ip_address")).to eq("function_is_ip_address")
  end

  it "should raise a ParseError if there is less than 1 arguments" do
    expect { scope.function_is_ip_address([]) }.to( raise_error(Puppet::ParseError))
  end

  it "should return true if an IPv4 address" do
    result = scope.function_is_ip_address(["1.2.3.4"])
    expect(result).to(eq(true))
  end

  it "should return true if a full IPv6 address" do
    result = scope.function_is_ip_address(["fe80:0000:cd12:d123:e2f8:47ff:fe09:dd74"])
    expect(result).to(eq(true))
  end

  it "should return true if a compressed IPv6 address" do
    result = scope.function_is_ip_address(["fe00::1"])
    expect(result).to(eq(true))
  end

  it "should return false if not valid" do
    result = scope.function_is_ip_address(["asdf"])
    expect(result).to(eq(false))
  end

  it "should return false if IP octets out of range" do
    result = scope.function_is_ip_address(["1.1.1.300"])
    expect(result).to(eq(false))
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the is_mac_address function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("is_mac_address")).to eq("function_is_mac_address")
  end

  it "should raise a ParseError if there is less than 1 arguments" do
    expect { scope.function_is_mac_address([]) }.to( raise_error(Puppet::ParseError))
  end

  it "should return true if a valid mac address" do
    result = scope.function_is_mac_address(["00:a0:1f:12:7f:a0"])
    expect(result).to(eq(true))
  end

  it "should return false if octets are out of range" do
    result = scope.function_is_mac_address(["00:a0:1f:12:7f:g0"])
    expect(result).to(eq(false))
  end

  it "should return false if not valid" do
    result = scope.function_is_mac_address(["not valid"])
    expect(result).to(eq(false))
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the is_numeric function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("is_numeric")).to eq("function_is_numeric")
  end

  it "should raise a ParseError if there is less than 1 argument" do
    expect { scope.function_is_numeric([]) }.to( raise_error(Puppet::ParseError))
  end

  it "should return true if an integer" do
    result = scope.function_is_numeric(["3"])
    expect(result).to(eq(true))
  end

  it "should return true if a float" do
    result = scope.function_is_numeric(["3.2"])
    expect(result).to(eq(true))
  end

  it "should return true if an integer is created from an arithmetical operation" do
    result = scope.function_is_numeric([3*2])
    expect(result).to(eq(true))
  end

  it "should return true if a float is created from an arithmetical operation" do
    result = scope.function_is_numeric([3.2*2])
    expect(result).to(eq(true))
  end

  it "should return false if a string" do
    result = scope.function_is_numeric(["asdf"])
    expect(result).to(eq(false))
  end

  it "should return false if an array" do
    result = scope.function_is_numeric([["asdf"]])
    expect(result).to(eq(false))
  end

  it "should return false if an array of integers" do
    result = scope.function_is_numeric([[1,2,3,4]])
    expect(result).to(eq(false))
  end

  it "should return false if a hash" do
    result = scope.function_is_numeric([{"asdf" => false}])
    expect(result).to(eq(false))
  end

  it "should return false if a hash with numbers in it" do
    result = scope.function_is_numeric([{1 => 2}])
    expect(result).to(eq(false))
  end

  it "should return false if a boolean" do
    result = scope.function_is_numeric([true])
    expect(result).to(eq(false))
  end

  it "should return true if a negative float with exponent" do
    result = scope.function_is_numeric(["-342.2315e-12"])
    expect(result).to(eq(true))
  end

  it "should return false if a negative integer with whitespaces before/after the dash" do
    result = scope.function_is_numeric([" -  751"])
    expect(result).to(eq(false))
  end

#  it "should return true if a hexadecimal" do
#    result = scope.function_is_numeric(["0x52F8c"])
#    result.should(eq(true))
#  end
#
#  it "should return true if a hexadecimal with uppercase 0X prefix" do
#    result = scope.function_is_numeric(["0X52F8c"])
#    result.should(eq(true))
#  end
#
#  it "should return false if a hexadecimal without a prefix" do
#    result = scope.function_is_numeric(["52F8c"])
#    result.should(eq(false))
#  end
#
#  it "should return true if a octal" do
#    result = scope.function_is_numeric(["0751"])
#    result.should(eq(true))
#  end
#
#  it "should return true if a negative hexadecimal" do
#    result = scope.function_is_numeric(["-0x52F8c"])
#    result.should(eq(true))
#  end
#
#  it "should return true if a negative octal" do
#    result = scope.function_is_numeric(["-0751"])
#    result.should(eq(true))
#  end
#
#  it "should return false if a negative octal with whitespaces before/after the dash" do
#    result = scope.function_is_numeric([" -  0751"])
#    result.should(eq(false))
#  end
#
#  it "should return false if a bad hexadecimal" do
#    result = scope.function_is_numeric(["0x23d7g"])
#    result.should(eq(false))
#  end
#
#  it "should return false if a bad octal" do
#    result = scope.function_is_numeric(["0287"])
#    result.should(eq(false))
#  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the is_string function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("is_string")).to eq("function_is_string")
  end

  it "should raise a ParseError if there is less than 1 arguments" do
    expect { scope.function_is_string([]) }.to( raise_error(Puppet::ParseError))
  end

  it "should return true if a string" do
    result = scope.function_is_string(["asdf"])
    expect(result).to(eq(true))
  end

  it "should return false if an integer" do
    result = scope.function_is_string(["3"])
    expect(result).to(eq(false))
  end

  it "should return false if a float" do
    result = scope.function_is_string(["3.23"])
    expect(result).to(eq(false))
  end

  it "should return false if an array" do
    result = scope.function_is_string([["a","b","c"]])
    expect(result).to(eq(false))
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the join_keys_to_values function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("join_keys_to_values")).to eq("function_join_keys_to_values")
  end

  it "should raise a ParseError if there are fewer than two arguments" do
    expect { scope.function_join_keys_to_values([{}]) }.to raise_error Puppet::ParseError
  end

  it "should raise a ParseError if there are greater than two arguments" do
    expect { scope.function_join_keys_to_values([{}, 'foo', 'bar']) }.to raise_error Puppet::ParseError
  end

  it "should raise a TypeError if the first argument is an array" do
    expect { scope.function_join_keys_to_values([[1,2], ',']) }.to raise_error TypeError
  end

  it "should raise a TypeError if the second argument is an array" do
    expect { scope.function_join_keys_to_values([{}, [1,2]]) }.to raise_error TypeError
  end

  it "should raise a TypeError if the second argument is a number" do
    expect { scope.function_join_keys_to_values([{}, 1]) }.to raise_error TypeError
  end

  it "should return an empty array given an empty hash" do
    result = scope.function_join_keys_to_values([{}, ":"])
    expect(result).to eq([])
  end

  it "should join hash's keys to its values" do
    result = scope.function_join_keys_to_values([{'a'=>1,2=>'foo',:b=>nil}, ":"])
    expect(result).to match_array(['a:1','2:foo','b:'])
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the join function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("join")).to eq("function_join")
  end

  it "should raise a ParseError if there is less than 1 arguments" do
    expect { scope.function_join([]) }.to( raise_error(Puppet::ParseError))
  end

  it "should join an array into a string" do
    result = scope.function_join([["a","b","c"], ":"])
    expect(result).to(eq("a:b:c"))
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the keys function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("keys")).to eq("function_keys")
  end

  it "should raise a ParseError if there is less than 1 arguments" do
    expect { scope.function_keys([]) }.to( raise_error(Puppet::ParseError))
  end

  it "should return an array of keys when given a hash" do
    result = scope.function_keys([{'a'=>1, 'b'=>2}])
    # =~ performs 'array with same elements' (set) matching
    # For more info see RSpec::Matchers::MatchArray
    expect(result).to match_array(['a','b'])
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the loadyaml function" do
  include PuppetlabsSpec::Files

  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("loadyaml")).to eq("function_loadyaml")
  end

  it "should raise a ParseError if there is less than 1 arguments" do
    expect { scope.function_loadyaml([]) }.to raise_error(Puppet::ParseError)
  end

  it "should convert YAML file to a data structure" do
    yaml_file = tmpfilename ('yamlfile')
    File.open(yaml_file, 'w') do |fh|
      fh.write("---\n aaa: 1\n bbb: 2\n ccc: 3\n ddd: 4\n")
    end
    result = scope.function_loadyaml([yaml_file])
    expect(result).to eq({"aaa" => 1, "bbb" => 2, "ccc" => 3, "ddd" => 4 })
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the lstrip function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("lstrip")).to eq("function_lstrip")
  end

  it "should raise a ParseError if there is less than 1 arguments" do
    expect { scope.function_lstrip([]) }.to( raise_error(Puppet::ParseError))
  end

  it "should lstrip a string" do
    result = scope.function_lstrip(["  asdf"])
    expect(result).to(eq('asdf'))
  end

  it "should accept objects which extend String" do
    class AlsoString < String
    end

    value = AlsoString.new("  asdf")
    result = scope.function_lstrip([value])
    result.should(eq("asdf"))
  end
end
#! /usr/bin/env ruby -S rspec

require 'spec_helper'

describe "the max function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("max")).to eq("function_max")
  end

  it "should raise a ParseError if there is less than 1 arguments" do
    expect { scope.function_max([]) }.to( raise_error(Puppet::ParseError))
  end

  it "should be able to compare strings" do
    expect(scope.function_max(["albatross","dog","horse"])).to(eq("horse"))
  end

  it "should be able to compare numbers" do
    expect(scope.function_max([6,8,4])).to(eq(8))
  end

  it "should be able to compare a number with a stringified number" do
    expect(scope.function_max([1,"2"])).to(eq("2"))
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the member function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("member")).to eq("function_member")
  end

  it "should raise a ParseError if there is less than 1 arguments" do
    expect { scope.function_member([]) }.to( raise_error(Puppet::ParseError))
  end

  it "should return true if a member is in an array" do
    result = scope.function_member([["a","b","c"], "a"])
    expect(result).to(eq(true))
  end

  it "should return false if a member is not in an array" do
    result = scope.function_member([["a","b","c"], "d"])
    expect(result).to(eq(false))
  end
end
#! /usr/bin/env ruby -S rspec

require 'spec_helper'

describe Puppet::Parser::Functions.function(:merge) do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  describe 'when calling merge from puppet' do
    it "should not compile when no arguments are passed" do
      skip("Fails on 2.6.x, see bug #15912") if Puppet.version =~ /^2\.6\./
      Puppet[:code] = '$x = merge()'
      expect {
        scope.compiler.compile
      }.to raise_error(Puppet::ParseError, /wrong number of arguments/)
    end

    it "should not compile when 1 argument is passed" do
      skip("Fails on 2.6.x, see bug #15912") if Puppet.version =~ /^2\.6\./
      Puppet[:code] = "$my_hash={'one' => 1}\n$x = merge($my_hash)"
      expect {
        scope.compiler.compile
      }.to raise_error(Puppet::ParseError, /wrong number of arguments/)
    end
  end

  describe 'when calling merge on the scope instance' do
    it 'should require all parameters are hashes' do
      expect { new_hash = scope.function_merge([{}, '2'])}.to raise_error(Puppet::ParseError, /unexpected argument type String/)
      expect { new_hash = scope.function_merge([{}, 2])}.to raise_error(Puppet::ParseError, /unexpected argument type Fixnum/)
    end

    it 'should accept empty strings as puppet undef' do
      expect { new_hash = scope.function_merge([{}, ''])}.not_to raise_error
    end

    it 'should be able to merge two hashes' do
      new_hash = scope.function_merge([{'one' => '1', 'two' => '1'}, {'two' => '2', 'three' => '2'}])
      expect(new_hash['one']).to   eq('1')
      expect(new_hash['two']).to   eq('2')
      expect(new_hash['three']).to eq('2')
    end

    it 'should merge multiple hashes' do
      hash = scope.function_merge([{'one' => 1}, {'one' => '2'}, {'one' => '3'}])
      expect(hash['one']).to eq('3')
    end

    it 'should accept empty hashes' do
      expect(scope.function_merge([{},{},{}])).to eq({})
    end
  end
end
#! /usr/bin/env ruby -S rspec

require 'spec_helper'

describe "the min function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("min")).to eq("function_min")
  end

  it "should raise a ParseError if there is less than 1 arguments" do
    expect { scope.function_min([]) }.to( raise_error(Puppet::ParseError))
  end

  it "should be able to compare strings" do
    expect(scope.function_min(["albatross","dog","horse"])).to(eq("albatross"))
  end

  it "should be able to compare numbers" do
    expect(scope.function_min([6,8,4])).to(eq(4))
  end

  it "should be able to compare a number with a stringified number" do
    expect(scope.function_min([1,"2"])).to(eq(1))
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the num2bool function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("num2bool")).to eq("function_num2bool")
  end

  it "should raise a ParseError if there are no arguments" do
    expect { scope.function_num2bool([]) }.to( raise_error(Puppet::ParseError))
  end

  it "should raise a ParseError if there are more than 1 arguments" do
    expect { scope.function_num2bool(["foo","bar"]) }.to( raise_error(Puppet::ParseError))
  end

  it "should raise a ParseError if passed something non-numeric" do
    expect { scope.function_num2bool(["xyzzy"]) }.to( raise_error(Puppet::ParseError))
  end

  it "should return true if passed string 1" do
    result = scope.function_num2bool(["1"])
    expect(result).to(be_truthy)
  end

  it "should return true if passed string 1.5" do
    result = scope.function_num2bool(["1.5"])
    expect(result).to(be_truthy)
  end

  it "should return true if passed number 1" do
    result = scope.function_num2bool([1])
    expect(result).to(be_truthy)
  end

  it "should return false if passed string 0" do
    result = scope.function_num2bool(["0"])
    expect(result).to(be_falsey)
  end

  it "should return false if passed number 0" do
    result = scope.function_num2bool([0])
    expect(result).to(be_falsey)
  end

  it "should return false if passed string -1" do
    result = scope.function_num2bool(["-1"])
    expect(result).to(be_falsey)
  end

  it "should return false if passed string -1.5" do
    result = scope.function_num2bool(["-1.5"])
    expect(result).to(be_falsey)
  end

  it "should return false if passed number -1" do
    result = scope.function_num2bool([-1])
    expect(result).to(be_falsey)
  end

  it "should return false if passed float -1.5" do
    result = scope.function_num2bool([-1.5])
    expect(result).to(be_falsey)
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the parsejson function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("parsejson")).to eq("function_parsejson")
  end

  it "should raise a ParseError if there is less than 1 arguments" do
    expect { scope.function_parsejson([]) }.to( raise_error(Puppet::ParseError))
  end

  it "should convert JSON to a data structure" do
    json = <<-EOS
["aaa","bbb","ccc"]
EOS
    result = scope.function_parsejson([json])
    expect(result).to(eq(['aaa','bbb','ccc']))
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the parseyaml function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("parseyaml")).to eq("function_parseyaml")
  end

  it "should raise a ParseError if there is less than 1 arguments" do
    expect { scope.function_parseyaml([]) }.to( raise_error(Puppet::ParseError))
  end

  it "should convert YAML to a data structure" do
    yaml = <<-EOS
- aaa
- bbb
- ccc
EOS
    result = scope.function_parseyaml([yaml])
    expect(result).to(eq(['aaa','bbb','ccc']))
  end
end
#!/usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the pick_default function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("pick_default")).to eq("function_pick_default")
  end

  it 'should return the correct value' do
    expect(scope.function_pick_default(['first', 'second'])).to eq('first')
  end

  it 'should return the correct value if the first value is empty' do
    expect(scope.function_pick_default(['', 'second'])).to eq('second')
  end

  it 'should skip empty string values' do
    expect(scope.function_pick_default(['', 'first'])).to eq('first')
  end

  it 'should skip :undef values' do
    expect(scope.function_pick_default([:undef, 'first'])).to eq('first')
  end

  it 'should skip :undefined values' do
    expect(scope.function_pick_default([:undefined, 'first'])).to eq('first')
  end

  it 'should return the empty string if it is the last possibility' do
    expect(scope.function_pick_default([:undef, :undefined, ''])).to eq('')
  end

  it 'should return :undef if it is the last possibility' do
    expect(scope.function_pick_default(['', :undefined, :undef])).to eq(:undef)
  end

  it 'should return :undefined if it is the last possibility' do
    expect(scope.function_pick_default([:undef, '', :undefined])).to eq(:undefined)
  end

  it 'should return the empty string if it is the only possibility' do
    expect(scope.function_pick_default([''])).to eq('')
  end

  it 'should return :undef if it is the only possibility' do
    expect(scope.function_pick_default([:undef])).to eq(:undef)
  end

  it 'should return :undefined if it is the only possibility' do
    expect(scope.function_pick_default([:undefined])).to eq(:undefined)
  end

  it 'should error if no values are passed' do
    expect { scope.function_pick_default([]) }.to raise_error(Puppet::Error, /Must receive at least one argument./)
  end
end
#!/usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the pick function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("pick")).to eq("function_pick")
  end

  it 'should return the correct value' do
    expect(scope.function_pick(['first', 'second'])).to eq('first')
  end

  it 'should return the correct value if the first value is empty' do
    expect(scope.function_pick(['', 'second'])).to eq('second')
  end

  it 'should remove empty string values' do
    expect(scope.function_pick(['', 'first'])).to eq('first')
  end

  it 'should remove :undef values' do
    expect(scope.function_pick([:undef, 'first'])).to eq('first')
  end

  it 'should remove :undefined values' do
    expect(scope.function_pick([:undefined, 'first'])).to eq('first')
  end

  it 'should error if no values are passed' do
    expect { scope.function_pick([]) }.to( raise_error(Puppet::ParseError, "pick(): must receive at least one non empty value"))
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the prefix function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "raises a ParseError if there is less than 1 arguments" do
    expect { scope.function_prefix([]) }.to raise_error(Puppet::ParseError, /number of arguments/)
  end

  it "raises an error if the first argument is not an array" do
    expect {
      scope.function_prefix([Object.new])
    }.to raise_error(Puppet::ParseError, /expected first argument to be an Array/)
  end


  it "raises an error if the second argument is not a string" do
    expect {
      scope.function_prefix([['first', 'second'], 42])
    }.to raise_error(Puppet::ParseError, /expected second argument to be a String/)
  end

  it "returns a prefixed array" do
    result = scope.function_prefix([['a','b','c'], 'p'])
    expect(result).to(eq(['pa','pb','pc']))
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe Puppet::Parser::Functions.function(:private) do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  subject do
    function_name = Puppet::Parser::Functions.function(:private)
    scope.method(function_name)
  end

  context "when called from inside module" do
    it "should not fail" do
      scope.expects(:lookupvar).with('module_name').returns('foo')
      scope.expects(:lookupvar).with('caller_module_name').returns('foo')
      expect {
        subject.call []
      }.not_to raise_error
    end
  end

  context "with an explicit failure message" do
    it "prints the failure message on error" do
      scope.expects(:lookupvar).with('module_name').returns('foo')
      scope.expects(:lookupvar).with('caller_module_name').returns('bar')
      expect {
        subject.call ['failure message!']
      }.to raise_error Puppet::ParseError, /failure message!/
    end
  end

  context "when called from private class" do
    it "should fail with a class error message" do
      scope.expects(:lookupvar).with('module_name').returns('foo')
      scope.expects(:lookupvar).with('caller_module_name').returns('bar')
      scope.source.expects(:name).returns('foo::baz')
      scope.source.expects(:type).returns('hostclass')
      expect {
        subject.call []
      }.to raise_error Puppet::ParseError, /Class foo::baz is private/
    end
  end

  context "when called from private definition" do
    it "should fail with a class error message" do
      scope.expects(:lookupvar).with('module_name').returns('foo')
      scope.expects(:lookupvar).with('caller_module_name').returns('bar')
      scope.source.expects(:name).returns('foo::baz')
      scope.source.expects(:type).returns('definition')
      expect {
        subject.call []
      }.to raise_error Puppet::ParseError, /Definition foo::baz is private/
    end
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the range function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "exists" do
    expect(Puppet::Parser::Functions.function("range")).to eq("function_range")
  end

  it "raises a ParseError if there is less than 1 arguments" do
    expect { scope.function_range([]) }.to raise_error Puppet::ParseError, /Wrong number of arguments.*0 for 1/
  end

  describe 'with a letter range' do
    it "returns a letter range" do
      result = scope.function_range(["a","d"])
      expect(result).to eq ['a','b','c','d']
    end

    it "returns a letter range given a step of 1" do
      result = scope.function_range(["a","d","1"])
      expect(result).to eq ['a','b','c','d']
    end

    it "returns a stepped letter range" do
      result = scope.function_range(["a","d","2"])
      expect(result).to eq ['a','c']
    end

    it "returns a stepped letter range given a negative step" do
      result = scope.function_range(["a","d","-2"])
      expect(result).to eq ['a','c']
    end
  end

  describe 'with a number range' do
    it "returns a number range" do
      result = scope.function_range(["1","4"])
      expect(result).to eq [1,2,3,4]
    end

    it "returns a number range given a step of 1" do
      result = scope.function_range(["1","4","1"])
      expect(result).to eq [1,2,3,4]
    end

    it "returns a stepped number range" do
      result = scope.function_range(["1","4","2"])
      expect(result).to eq [1,3]
    end

    it "returns a stepped number range given a negative step" do
      result = scope.function_range(["1","4","-2"])
      expect(result).to eq [1,3]
    end
  end

  describe 'with a numeric-like string range' do
    it "works with padded hostname like strings" do
      expected = ("host01".."host10").to_a
      expect(scope.function_range(["host01","host10"])).to eq expected
    end

    it "coerces zero padded digits to integers" do
      expected = (0..10).to_a
      expect(scope.function_range(["00", "10"])).to eq expected
    end
  end
end
#!/usr/bin/env ruby

require 'spec_helper'

describe "the reject function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("reject")).to eq("function_reject")
  end

  it "should raise a ParseError if there is less than 1 arguments" do
    expect { scope.function_reject([]) }.to( raise_error(Puppet::ParseError))
  end

  it "should reject contents from an array" do
    result = scope.function_reject([["1111", "aaabbb","bbbccc","dddeee"], "bbb"])
    expect(result).to(eq(["1111", "dddeee"]))
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the reverse function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("reverse")).to eq("function_reverse")
  end

  it "should raise a ParseError if there is less than 1 arguments" do
    expect { scope.function_reverse([]) }.to( raise_error(Puppet::ParseError))
  end

  it "should reverse a string" do
    result = scope.function_reverse(["asdfghijkl"])
    expect(result).to(eq('lkjihgfdsa'))
  end

  it "should accept objects which extend String" do
    class AlsoString < String
    end

    value = AlsoString.new('asdfghjkl')
    result = scope.function_reverse([value])
    result.should(eq('lkjhgfdsa'))
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the rstrip function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("rstrip")).to eq("function_rstrip")
  end

  it "should raise a ParseError if there is less than 1 arguments" do
    expect { scope.function_rstrip([]) }.to( raise_error(Puppet::ParseError))
  end

  it "should rstrip a string" do
    result = scope.function_rstrip(["asdf  "])
    expect(result).to(eq('asdf'))
  end

  it "should rstrip each element in an array" do
    result = scope.function_rstrip([["a ","b ", "c "]])
    expect(result).to(eq(['a','b','c']))
  end

  it "should accept objects which extend String" do
    class AlsoString < String
    end

    value = AlsoString.new('asdf ')
    result = scope.function_rstrip([value])
    result.should(eq('asdf'))
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the shuffle function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("shuffle")).to eq("function_shuffle")
  end

  it "should raise a ParseError if there is less than 1 arguments" do
    expect { scope.function_shuffle([]) }.to( raise_error(Puppet::ParseError))
  end

  it "should shuffle a string and the result should be the same size" do
    result = scope.function_shuffle(["asdf"])
    expect(result.size).to(eq(4))
  end

  it "should shuffle a string but the sorted contents should still be the same" do
    result = scope.function_shuffle(["adfs"])
    expect(result.split("").sort.join("")).to(eq("adfs"))
  end

  it "should accept objects which extend String" do
    class AlsoString < String
    end

    value = AlsoString.new('asdf')
    result = scope.function_shuffle([value])
    result.size.should(eq(4))
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the size function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("size")).to eq("function_size")
  end

  it "should raise a ParseError if there is less than 1 arguments" do
    expect { scope.function_size([]) }.to( raise_error(Puppet::ParseError))
  end

  it "should return the size of a string" do
    result = scope.function_size(["asdf"])
    expect(result).to(eq(4))
  end

  it "should return the size of an array" do
    result = scope.function_size([["a","b","c"]])
    expect(result).to(eq(3))
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the sort function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("sort")).to eq("function_sort")
  end

  it "should raise a ParseError if there is not 1 arguments" do
    expect { scope.function_sort(['','']) }.to( raise_error(Puppet::ParseError))
  end

  it "should sort an array" do
    result = scope.function_sort([["a","c","b"]])
    expect(result).to(eq(['a','b','c']))
  end

  it "should sort a string" do
    result = scope.function_sort(["acb"])
    expect(result).to(eq('abc'))
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the squeeze function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("squeeze")).to eq("function_squeeze")
  end

  it "should raise a ParseError if there is less than 2 arguments" do
    expect { scope.function_squeeze([]) }.to( raise_error(Puppet::ParseError))
  end

  it "should squeeze a string" do
    result = scope.function_squeeze(["aaabbbbcccc"])
    expect(result).to(eq('abc'))
  end

  it "should squeeze all elements in an array" do
    result = scope.function_squeeze([["aaabbbbcccc","dddfff"]])
    expect(result).to(eq(['abc','df']))
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the str2bool function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("str2bool")).to eq("function_str2bool")
  end

  it "should raise a ParseError if there is less than 1 arguments" do
    expect { scope.function_str2bool([]) }.to( raise_error(Puppet::ParseError))
  end

  it "should convert string 'true' to true" do
    result = scope.function_str2bool(["true"])
    expect(result).to(eq(true))
  end

  it "should convert string 'undef' to false" do
    result = scope.function_str2bool(["undef"])
    expect(result).to(eq(false))
  end

  it "should return the boolean it was called with" do
    result = scope.function_str2bool([true])
    expect(result).to(eq(true))
    result = scope.function_str2bool([false])
    expect(result).to(eq(false))
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the str2saltedsha512 function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("str2saltedsha512")).to eq("function_str2saltedsha512")
  end

  it "should raise a ParseError if there is less than 1 argument" do
    expect { scope.function_str2saltedsha512([]) }.to( raise_error(Puppet::ParseError) )
  end

  it "should raise a ParseError if there is more than 1 argument" do
    expect { scope.function_str2saltedsha512(['foo', 'bar', 'baz']) }.to( raise_error(Puppet::ParseError) )
  end

  it "should return a salted-sha512 password hash 136 characters in length" do
    result = scope.function_str2saltedsha512(["password"])
    expect(result.length).to(eq(136))
  end

  it "should raise an error if you pass a non-string password" do
    expect { scope.function_str2saltedsha512([1234]) }.to( raise_error(Puppet::ParseError) )
  end

  it "should generate a valid password" do
    # Allow the function to generate a password based on the string 'password'
    password_hash = scope.function_str2saltedsha512(["password"])

    # Separate the Salt and Password from the Password Hash
    salt     = password_hash[0..7]
    password = password_hash[8..-1]

    # Convert the Salt and Password from Hex to Binary Data
    str_salt     = Array(salt.lines).pack('H*')
    str_password = Array(password.lines).pack('H*')

    # Combine the Binary Salt with 'password' and compare the end result
    saltedpass    = Digest::SHA512.digest(str_salt + 'password')
    result        = (str_salt + saltedpass).unpack('H*')[0]
    expect(result).to eq(password_hash)
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the strftime function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("strftime")).to eq("function_strftime")
  end

  it "should raise a ParseError if there is less than 1 arguments" do
    expect { scope.function_strftime([]) }.to( raise_error(Puppet::ParseError))
  end

  it "using %s should be higher then when I wrote this test" do
    result = scope.function_strftime(["%s"])
    expect(result.to_i).to(be > 1311953157)
  end

  it "using %s should be lower then 1.5 trillion" do
    result = scope.function_strftime(["%s"])
    expect(result.to_i).to(be < 1500000000)
  end

  it "should return a date when given %Y-%m-%d" do
    result = scope.function_strftime(["%Y-%m-%d"])
    expect(result).to match(/^\d{4}-\d{2}-\d{2}$/)
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the strip function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
  it "should exist" do
    expect(Puppet::Parser::Functions.function("strip")).to eq("function_strip")
  end

  it "should raise a ParseError if there is less than 1 arguments" do
    expect { scope.function_strip([]) }.to( raise_error(Puppet::ParseError))
  end

  it "should strip a string" do
    result = scope.function_strip([" ab cd "])
    expect(result).to(eq('ab cd'))
  end

  it "should accept objects which extend String" do
    class AlsoString < String
    end

    value = AlsoString.new(' as df ')
    result = scope.function_strip([value])
    result.should(eq('as df'))
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the suffix function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "raises a ParseError if there is less than 1 arguments" do
    expect { scope.function_suffix([]) }.to raise_error(Puppet::ParseError, /number of arguments/)
  end

  it "raises an error if the first argument is not an array" do
    expect {
      scope.function_suffix([Object.new])
    }.to raise_error(Puppet::ParseError, /expected first argument to be an Array/)
  end

  it "raises an error if the second argument is not a string" do
    expect {
      scope.function_suffix([['first', 'second'], 42])
    }.to raise_error(Puppet::ParseError, /expected second argument to be a String/)
  end

  it "returns a suffixed array" do
    result = scope.function_suffix([['a','b','c'], 'p'])
    expect(result).to(eq(['ap','bp','cp']))
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the swapcase function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("swapcase")).to eq("function_swapcase")
  end

  it "should raise a ParseError if there is less than 1 arguments" do
    expect { scope.function_swapcase([]) }.to( raise_error(Puppet::ParseError))
  end

  it "should swapcase a string" do
    result = scope.function_swapcase(["aaBBccDD"])
    expect(result).to(eq('AAbbCCdd'))
  end

  it "should accept objects which extend String" do
    class AlsoString < String
    end

    value = AlsoString.new("aaBBccDD")
    result = scope.function_swapcase([value])
    result.should(eq("AAbbCCdd"))
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the time function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("time")).to eq("function_time")
  end

  it "should raise a ParseError if there is more than 2 arguments" do
    expect { scope.function_time(['','']) }.to( raise_error(Puppet::ParseError))
  end

  it "should return a number" do
    result = scope.function_time([])
    expect(result).to be_an(Integer)
  end

  it "should be higher then when I wrote this test" do
    result = scope.function_time([])
    expect(result).to(be > 1311953157)
  end

  it "should be lower then 1.5 trillion" do
    result = scope.function_time([])
    expect(result).to(be < 1500000000)
  end
end
#! /usr/bin/env ruby -S rspec

require 'spec_helper'

describe "the to_bytes function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("to_bytes")).to eq("function_to_bytes")
  end

  it "should raise a ParseError if there is less than 1 arguments" do
    expect { scope.function_to_bytes([]) }.to( raise_error(Puppet::ParseError))
  end

  it "should convert kB to B" do
    result = scope.function_to_bytes(["4 kB"])
    expect(result).to(eq(4096))
  end

  it "should convert MB to B" do
    result = scope.function_to_bytes(["4 MB"])
    expect(result).to(eq(4194304))
  end

  it "should convert GB to B" do
    result = scope.function_to_bytes(["4 GB"])
    expect(result).to(eq(4294967296))
  end

  it "should convert TB to B" do
    result = scope.function_to_bytes(["4 TB"])
    expect(result).to(eq(4398046511104))
  end

  it "should convert PB to B" do
    result = scope.function_to_bytes(["4 PB"])
    expect(result).to(eq(4503599627370496))
  end

  it "should convert PB to B" do
    result = scope.function_to_bytes(["4 EB"])
    expect(result).to(eq(4611686018427387904))
  end

  it "should work without B in unit" do
    result = scope.function_to_bytes(["4 k"])
    expect(result).to(eq(4096))
  end

  it "should work without a space before unit" do
    result = scope.function_to_bytes(["4k"])
    expect(result).to(eq(4096))
  end

  it "should work without a unit" do
    result = scope.function_to_bytes(["5678"])
    expect(result).to(eq(5678))
  end

  it "should convert fractions" do
    result = scope.function_to_bytes(["1.5 kB"])
    expect(result).to(eq(1536))
  end

  it "should convert scientific notation" do
    result = scope.function_to_bytes(["1.5e2 B"])
    expect(result).to(eq(150))
  end

  it "should do nothing with a positive number" do
    result = scope.function_to_bytes([5678])
    expect(result).to(eq(5678))
  end

  it "should should raise a ParseError if input isn't a number" do
    expect { scope.function_to_bytes(["foo"]) }.to( raise_error(Puppet::ParseError))
  end

  it "should should raise a ParseError if prefix is unknown" do
    expect { scope.function_to_bytes(["5 uB"]) }.to( raise_error(Puppet::ParseError))
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the type function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
  it "should exist" do
    expect(Puppet::Parser::Functions.function("type")).to eq("function_type")
  end

  it "should raise a ParseError if there is less than 1 arguments" do
    expect { scope.function_type([]) }.to( raise_error(Puppet::ParseError))
  end

  it "should return string when given a string" do
    result = scope.function_type(["aaabbbbcccc"])
    expect(result).to(eq('string'))
  end

  it "should return array when given an array" do
    result = scope.function_type([["aaabbbbcccc","asdf"]])
    expect(result).to(eq('array'))
  end

  it "should return hash when given a hash" do
    result = scope.function_type([{"a"=>1,"b"=>2}])
    expect(result).to(eq('hash'))
  end

  it "should return integer when given an integer" do
    result = scope.function_type(["1"])
    expect(result).to(eq('integer'))
  end

  it "should return float when given a float" do
    result = scope.function_type(["1.34"])
    expect(result).to(eq('float'))
  end

  it "should return boolean when given a boolean" do
    result = scope.function_type([true])
    expect(result).to(eq('boolean'))
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the union function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("union")).to eq("function_union")
  end

  it "should raise a ParseError if there are fewer than 2 arguments" do
    expect { scope.function_union([]) }.to( raise_error(Puppet::ParseError) )
  end

  it "should join two arrays together" do
    result = scope.function_union([["a","b","c"],["b","c","d"]])
    expect(result).to(eq(["a","b","c","d"]))
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the unique function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("unique")).to eq("function_unique")
  end

  it "should raise a ParseError if there is less than 1 arguments" do
    expect { scope.function_unique([]) }.to( raise_error(Puppet::ParseError))
  end

  it "should remove duplicate elements in a string" do
    result = scope.function_unique(["aabbc"])
    expect(result).to(eq('abc'))
  end

  it "should remove duplicate elements in an array" do
    result = scope.function_unique([["a","a","b","b","c"]])
    expect(result).to(eq(['a','b','c']))
  end

  it "should accept objects which extend String" do
    class AlsoString < String
    end

    value = AlsoString.new('aabbc')
    result = scope.function_unique([value])
    result.should(eq('abc'))
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the upcase function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("upcase")).to eq("function_upcase")
  end

  it "should raise a ParseError if there is less than 1 arguments" do
    expect { scope.function_upcase([]) }.to( raise_error(Puppet::ParseError))
  end

  it "should upcase a string" do
    result = scope.function_upcase(["abc"])
    expect(result).to(eq('ABC'))
  end

  it "should do nothing if a string is already upcase" do
    result = scope.function_upcase(["ABC"])
    expect(result).to(eq('ABC'))
  end

  it "should accept objects which extend String" do
    class AlsoString < String
    end

    value = AlsoString.new('abc')
    result = scope.function_upcase([value])
    result.should(eq('ABC'))
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the uriescape function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("uriescape")).to eq("function_uriescape")
  end

  it "should raise a ParseError if there is less than 1 arguments" do
    expect { scope.function_uriescape([]) }.to( raise_error(Puppet::ParseError))
  end

  it "should uriescape a string" do
    result = scope.function_uriescape([":/?#[]@!$&'()*+,;= \"{}"])
    expect(result).to(eq(':/?%23[]@!$&\'()*+,;=%20%22%7B%7D'))
  end

  it "should do nothing if a string is already safe" do
    result = scope.function_uriescape(["ABCdef"])
    expect(result).to(eq('ABCdef'))
  end

  it "should accept objects which extend String" do
    class AlsoString < String
    end

    value = AlsoString.new('abc')
    result = scope.function_uriescape([value])
    result.should(eq('abc'))
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe Puppet::Parser::Functions.function(:validate_absolute_path) do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  # The subject of these examples is the method itself.
  subject do
    # This makes sure the function is loaded within each test
    function_name = Puppet::Parser::Functions.function(:validate_absolute_path)
    scope.method(function_name)
  end

  describe "Valid Paths" do
    def self.valid_paths
      %w{
        C:/
        C:\\
        C:\\WINDOWS\\System32
        C:/windows/system32
        X:/foo/bar
        X:\\foo\\bar
        /var/tmp
        /var/lib/puppet
        /var/opt/../lib/puppet
      }
    end

    context "Without Puppet::Util.absolute_path? (e.g. Puppet <= 2.6)" do
      before :each do
        # The intent here is to mock Puppet to behave like Puppet 2.6 does.
        # Puppet 2.6 does not have the absolute_path? method.  This is only a
        # convenience test, stdlib should be run with the Puppet 2.6.x in the
        # $LOAD_PATH in addition to 2.7.x and master.
        Puppet::Util.expects(:respond_to?).with(:absolute_path?).returns(false)
      end
      valid_paths.each do |path|
        it "validate_absolute_path(#{path.inspect}) should not fail" do
          expect { subject.call [path] }.not_to raise_error
        end
      end
    end

    context "Puppet without mocking" do
      valid_paths.each do |path|
        it "validate_absolute_path(#{path.inspect}) should not fail" do
          expect { subject.call [path] }.not_to raise_error
        end
      end
    end
  end

  describe 'Invalid paths' do
    context 'Garbage inputs' do
      [
        nil,
        [ nil ],
        { 'foo' => 'bar' },
        { },
        '',
      ].each do |path|
        it "validate_absolute_path(#{path.inspect}) should fail" do
          expect { subject.call [path] }.to raise_error Puppet::ParseError
        end
      end
    end

    context 'Relative paths' do
      %w{
        relative1
        .
        ..
        ./foo
        ../foo
        etc/puppetlabs/puppet
        opt/puppet/bin
      }.each do |path|
        it "validate_absolute_path(#{path.inspect}) should fail" do
          expect { subject.call [path] }.to raise_error Puppet::ParseError
        end
      end
    end
  end
end
#! /usr/bin/env ruby -S rspec

require 'spec_helper'

describe Puppet::Parser::Functions.function(:validate_array) do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
  describe 'when calling validate_array from puppet' do

    %w{ true false }.each do |the_string|
      it "should not compile when #{the_string} is a string" do
        Puppet[:code] = "validate_array('#{the_string}')"
        expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /is not an Array/)
      end

      it "should not compile when #{the_string} is a bare word" do
        Puppet[:code] = "validate_array(#{the_string})"
        expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /is not an Array/)
      end
    end

    it "should compile when multiple array arguments are passed" do
      Puppet[:code] = <<-'ENDofPUPPETcode'
        $foo = [ ]
        $bar = [ 'one', 'two' ]
        validate_array($foo, $bar)
      ENDofPUPPETcode
      scope.compiler.compile
    end

    it "should not compile when an undef variable is passed" do
      Puppet[:code] = <<-'ENDofPUPPETcode'
        $foo = undef
        validate_array($foo)
      ENDofPUPPETcode
      expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /is not an Array/)
    end
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe Puppet::Parser::Functions.function(:validate_augeas), :if => Puppet.features.augeas? do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  # The subject of these examplres is the method itself.
  subject do
    # This makes sure the function is loaded within each test
    function_name = Puppet::Parser::Functions.function(:validate_augeas)
    scope.method(function_name)
  end

  context 'Using Puppet::Parser::Scope.new' do

    describe 'Garbage inputs' do
      inputs = [
        [ nil ],
        [ [ nil ] ],
        [ { 'foo' => 'bar' } ],
        [ { } ],
        [ '' ],
        [ "one", "one", "MSG to User", "4th arg" ],
      ]

      inputs.each do |input|
        it "validate_augeas(#{input.inspect}) should fail" do
          expect { subject.call [input] }.to raise_error Puppet::ParseError
        end
      end
    end

    describe 'Valid inputs' do
      inputs = [
        [ "root:x:0:0:root:/root:/bin/bash\n", 'Passwd.lns' ],
        [ "proc /proc   proc    nodev,noexec,nosuid     0       0\n", 'Fstab.lns'],
      ]

      inputs.each do |input|
        it "validate_augeas(#{input.inspect}) should not fail" do
          expect { subject.call input }.not_to raise_error
        end
      end
    end

    describe "Valid inputs which should raise an exception without a message" do
      # The intent here is to make sure valid inputs raise exceptions when they
      # don't specify an error message to display.  This is the behvior in
      # 2.2.x and prior.
      inputs = [
        [ "root:x:0:0:root\n", 'Passwd.lns' ],
        [ "127.0.1.1\n", 'Hosts.lns' ],
      ]

      inputs.each do |input|
        it "validate_augeas(#{input.inspect}) should fail" do
          expect { subject.call input }.to raise_error /validate_augeas.*?matched less than it should/
        end
      end
    end

    describe "Nicer Error Messages" do
      # The intent here is to make sure the function returns the 3rd argument
      # in the exception thrown
      inputs = [
        [ "root:x:0:0:root\n", 'Passwd.lns', [], 'Failed to validate passwd content' ],
        [ "127.0.1.1\n", 'Hosts.lns', [], 'Wrong hosts content' ],
      ]

      inputs.each do |input|
        it "validate_augeas(#{input.inspect}) should fail" do
          expect { subject.call input }.to raise_error /#{input[2]}/
        end
      end
    end

    describe "Passing simple unit tests" do
      inputs = [
        [ "root:x:0:0:root:/root:/bin/bash\n", 'Passwd.lns', ['$file/foobar']],
        [ "root:x:0:0:root:/root:/bin/bash\n", 'Passwd.lns', ['$file/root/shell[.="/bin/sh"]', 'foobar']],
      ]

      inputs.each do |input|
        it "validate_augeas(#{input.inspect}) should fail" do
          expect { subject.call input }.not_to raise_error
        end
      end
    end

    describe "Failing simple unit tests" do
      inputs = [
        [ "foobar:x:0:0:root:/root:/bin/bash\n", 'Passwd.lns', ['$file/foobar']],
        [ "root:x:0:0:root:/root:/bin/sh\n", 'Passwd.lns', ['$file/root/shell[.="/bin/sh"]', 'foobar']],
      ]

      inputs.each do |input|
        it "validate_augeas(#{input.inspect}) should fail" do
          expect { subject.call input }.to raise_error /testing path/
        end
      end
    end
  end
end
#! /usr/bin/env ruby -S rspec

require 'spec_helper'

describe Puppet::Parser::Functions.function(:validate_bool) do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
  describe 'when calling validate_bool from puppet' do

    %w{ true false }.each do |the_string|

      it "should not compile when #{the_string} is a string" do
        Puppet[:code] = "validate_bool('#{the_string}')"
        expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /is not a boolean/)
      end

      it "should compile when #{the_string} is a bare word" do
        Puppet[:code] = "validate_bool(#{the_string})"
        scope.compiler.compile
      end

    end

    it "should not compile when an arbitrary string is passed" do
      Puppet[:code] = 'validate_bool("jeff and dan are awesome")'
      expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /is not a boolean/)
    end

    it "should not compile when no arguments are passed" do
      Puppet[:code] = 'validate_bool()'
      expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /wrong number of arguments/)
    end

    it "should compile when multiple boolean arguments are passed" do
      Puppet[:code] = <<-'ENDofPUPPETcode'
        $foo = true
        $bar = false
        validate_bool($foo, $bar, true, false)
      ENDofPUPPETcode
      scope.compiler.compile
    end

    it "should compile when multiple boolean arguments are passed" do
      Puppet[:code] = <<-'ENDofPUPPETcode'
        $foo = true
        $bar = false
        validate_bool($foo, $bar, true, false, 'jeff')
      ENDofPUPPETcode
      expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /is not a boolean/)
    end
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

TESTEXE = File.exists?('/usr/bin/test') ? '/usr/bin/test' : '/bin/test'
TOUCHEXE = File.exists?('/usr/bin/touch') ? '/usr/bin/touch' : '/bin/touch'

describe Puppet::Parser::Functions.function(:validate_cmd) do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  subject do
    function_name = Puppet::Parser::Functions.function(:validate_cmd)
    scope.method(function_name)
  end

  describe "with an explicit failure message" do
    it "prints the failure message on error" do
      expect {
        subject.call ['', '/bin/false', 'failure message!']
      }.to raise_error Puppet::ParseError, /failure message!/
    end
  end

  describe "on validation failure" do
    it "includes the command error output" do
      expect {
        subject.call ['', "#{TOUCHEXE} /cant/touch/this"]
      }.to raise_error Puppet::ParseError, /(cannot touch|o such file or)/
    end

    it "includes the command return value" do
      expect {
        subject.call ['', '/cant/run/this']
      }.to raise_error Puppet::ParseError, /returned 1\b/
    end
  end

  describe "when performing actual validation" do
    it "can positively validate file content" do
      expect { subject.call ["non-empty", "#{TESTEXE} -s"] }.to_not raise_error
    end

    it "can negatively validate file content" do
      expect {
        subject.call ["", "#{TESTEXE} -s"]
      }.to raise_error Puppet::ParseError, /failed to validate.*test -s/
    end
  end
end
#! /usr/bin/env ruby -S rspec

require 'spec_helper'

describe Puppet::Parser::Functions.function(:validate_hash) do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  describe 'when calling validate_hash from puppet' do

    %w{ true false }.each do |the_string|

      it "should not compile when #{the_string} is a string" do
        Puppet[:code] = "validate_hash('#{the_string}')"
        expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /is not a Hash/)
      end

      it "should not compile when #{the_string} is a bare word" do
        Puppet[:code] = "validate_hash(#{the_string})"
        expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /is not a Hash/)
      end

    end

    it "should compile when multiple hash arguments are passed" do
      Puppet[:code] = <<-'ENDofPUPPETcode'
        $foo = {}
        $bar = { 'one' => 'two' }
        validate_hash($foo, $bar)
      ENDofPUPPETcode
      scope.compiler.compile
    end

    it "should not compile when an undef variable is passed" do
      Puppet[:code] = <<-'ENDofPUPPETcode'
        $foo = undef
        validate_hash($foo)
      ENDofPUPPETcode
      expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /is not a Hash/)
    end

  end

end
#! /usr/bin/env ruby -S rspec

require "spec_helper"

describe Puppet::Parser::Functions.function(:validate_ipv4_address) do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  describe "when calling validate_ipv4_address from puppet" do
    describe "when given IPv4 address strings" do
      it "should compile with one argument" do
        Puppet[:code] = "validate_ipv4_address('1.2.3.4')"
        scope.compiler.compile
      end

      it "should compile with multiple arguments" do
        Puppet[:code] = "validate_ipv4_address('1.2.3.4', '5.6.7.8')"
        scope.compiler.compile
      end
    end

    describe "when given an IPv6 address" do
      it "should not compile" do
        Puppet[:code] = "validate_ipv4_address('3ffe:505')"
        expect {
          scope.compiler.compile
        }.to raise_error(Puppet::ParseError, /not a valid IPv4 address/)
      end
    end

    describe "when given other strings" do
      it "should not compile" do
        Puppet[:code] = "validate_ipv4_address('hello', 'world')"
        expect {
          scope.compiler.compile
        }.to raise_error(Puppet::ParseError, /not a valid IPv4 address/)
      end
    end

    describe "when given numbers" do
      it "should not compile" do
        Puppet[:code] = "validate_ipv4_address(1, 2)"
        expect {
          scope.compiler.compile
        }.to raise_error(Puppet::ParseError, /is not a valid IPv4 address/)
      end
    end

    describe "when given booleans" do
      it "should not compile" do
        Puppet[:code] = "validate_ipv4_address(true, false)"
        expect {
          scope.compiler.compile
        }.to raise_error(Puppet::ParseError, /is not a string/)
      end
    end

    it "should not compile when no arguments are passed" do
      Puppet[:code] = "validate_ipv4_address()"
      expect {
        scope.compiler.compile
      }.to raise_error(Puppet::ParseError, /wrong number of arguments/)
    end
  end
end
#! /usr/bin/env ruby -S rspec

require "spec_helper"

describe Puppet::Parser::Functions.function(:validate_ipv6_address) do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  describe "when calling validate_ipv6_address from puppet" do
    describe "when given IPv6 address strings" do
      it "should compile with one argument" do
        Puppet[:code] = "validate_ipv6_address('3ffe:0505:0002::')"
        scope.compiler.compile
      end

      it "should compile with multiple arguments" do
        Puppet[:code] = "validate_ipv6_address('3ffe:0505:0002::', '3ffe:0505:0001::')"
        scope.compiler.compile
      end
    end

    describe "when given an ipv4 address" do
      it "should not compile" do
        Puppet[:code] = "validate_ipv6_address('1.2.3.4')"
        expect {
          scope.compiler.compile
        }.to raise_error(Puppet::ParseError, /not a valid IPv6 address/)
      end
    end

    describe "when given other strings" do
      it "should not compile" do
        Puppet[:code] = "validate_ipv6_address('hello', 'world')"
        expect {
          scope.compiler.compile
        }.to raise_error(Puppet::ParseError, /not a valid IPv6 address/)
      end
    end

    # 1.8.7 is EOL'd and also absolutely insane about ipv6
    unless RUBY_VERSION == '1.8.7'
      describe "when given numbers" do
        it "should not compile" do
          Puppet[:code] = "validate_ipv6_address(1, 2)"
          expect {
            scope.compiler.compile
          }.to raise_error(Puppet::ParseError, /not a valid IPv6 address/)
        end
      end
    end

    describe "when given booleans" do
      it "should not compile" do
        Puppet[:code] = "validate_ipv6_address(true, false)"
        expect {
          scope.compiler.compile
        }.to raise_error(Puppet::ParseError, /is not a string/)
      end
    end

    it "should not compile when no arguments are passed" do
      Puppet[:code] = "validate_ipv6_address()"
      expect {
        scope.compiler.compile
      }.to raise_error(Puppet::ParseError, /wrong number of arguments/)
    end
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe Puppet::Parser::Functions.function(:validate_re) do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  # The subject of these examplres is the method itself.
  subject do
    # This makes sure the function is loaded within each test
    function_name = Puppet::Parser::Functions.function(:validate_re)
    scope.method(function_name)
  end

  context 'Using Puppet::Parser::Scope.new' do

    describe 'Garbage inputs' do
      inputs = [
        [ nil ],
        [ [ nil ] ],
        [ { 'foo' => 'bar' } ],
        [ { } ],
        [ '' ],
        [ "one", "one", "MSG to User", "4th arg" ],
      ]

      inputs.each do |input|
        it "validate_re(#{input.inspect}) should fail" do
          expect { subject.call [input] }.to raise_error Puppet::ParseError
        end
      end
    end

    describe 'Valid inputs' do
      inputs = [
        [ '/full/path/to/something', '^/full' ],
        [ '/full/path/to/something', 'full' ],
        [ '/full/path/to/something', ['full', 'absent'] ],
        [ '/full/path/to/something', ['full', 'absent'], 'Message to the user' ],
      ]

      inputs.each do |input|
        it "validate_re(#{input.inspect}) should not fail" do
          expect { subject.call input }.not_to raise_error
        end
      end
    end
    describe "Valid inputs which should raise an exception without a message" do
      # The intent here is to make sure valid inputs raise exceptions when they
      # don't specify an error message to display.  This is the behvior in
      # 2.2.x and prior.
      inputs = [
        [ "hello", [ "bye", "later", "adios" ] ],
        [ "greetings", "salutations" ],
      ]

      inputs.each do |input|
        it "validate_re(#{input.inspect}) should fail" do
          expect { subject.call input }.to raise_error /validate_re.*?does not match/
        end
      end
    end
    describe "Nicer Error Messages" do
      # The intent here is to make sure the function returns the 3rd argument
      # in the exception thrown
      inputs = [
        [ "hello", [ "bye", "later", "adios" ], "MSG to User" ],
        [ "greetings", "salutations", "Error, greetings does not match salutations" ],
      ]

      inputs.each do |input|
        it "validate_re(#{input.inspect}) should fail" do
          expect { subject.call input }.to raise_error /#{input[2]}/
        end
      end
    end
  end
end
#! /usr/bin/env ruby -S rspec

require 'spec_helper'

describe "the validate_slength function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("validate_slength")).to eq("function_validate_slength")
  end

  describe "validating the input argument types" do
    it "raises an error if there are less than two arguments" do
      expect { scope.function_validate_slength([]) }.to raise_error Puppet::ParseError, /Wrong number of arguments/
    end

    it "raises an error if there are more than three arguments" do
      expect { scope.function_validate_slength(['input', 1, 2, 3]) }.to raise_error Puppet::ParseError, /Wrong number of arguments/
    end

    it "raises an error if the first argument is not a string" do
      expect { scope.function_validate_slength([Object.new, 2, 1]) }.to raise_error Puppet::ParseError, /Expected first argument.*got .*Object/
    end

    it "raises an error if the second argument cannot be cast to an Integer" do
      expect { scope.function_validate_slength(['input', Object.new]) }.to raise_error Puppet::ParseError, /Expected second argument.*got .*Object/
    end

    it "raises an error if the third argument cannot be cast to an Integer" do
      expect { scope.function_validate_slength(['input', 1, Object.new]) }.to raise_error Puppet::ParseError, /Expected third argument.*got .*Object/
    end

    it "raises an error if the second argument is smaller than the third argument" do
      expect { scope.function_validate_slength(['input', 1, 2]) }.to raise_error Puppet::ParseError, /Expected second argument to be larger than third argument/
    end
  end

  describe "validating the input string length" do
    describe "when the input is a string" do
      it "fails validation if the string is larger than the max length" do
        expect { scope.function_validate_slength(['input', 1]) }.to raise_error Puppet::ParseError, /Expected length .* between 0 and 1, was 5/
      end

      it "fails validation if the string is less than the min length" do
        expect { scope.function_validate_slength(['input', 10, 6]) }.to raise_error Puppet::ParseError, /Expected length .* between 6 and 10, was 5/
      end

      it "doesn't raise an error if the string is under the max length" do
        scope.function_validate_slength(['input', 10])
      end

      it "doesn't raise an error if the string is equal to the max length" do
        scope.function_validate_slength(['input', 5])
      end

      it "doesn't raise an error if the string is equal to the min length" do
        scope.function_validate_slength(['input', 10, 5])
      end
    end

    describe "when the input is an array" do
      it "fails validation if one of the array elements is not a string" do
        expect { scope.function_validate_slength([["a", "b", Object.new], 2]) }.to raise_error Puppet::ParseError, /Expected element at array position 2 .*String, got .*Object/
      end
    end
  end
end
#! /usr/bin/env ruby -S rspec

require 'spec_helper'

describe Puppet::Parser::Functions.function(:validate_string) do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  describe 'when calling validate_string from puppet' do

    %w{ foo bar baz }.each do |the_string|

      it "should compile when #{the_string} is a string" do
        Puppet[:code] = "validate_string('#{the_string}')"
        scope.compiler.compile
      end

      it "should compile when #{the_string} is a bare word" do
        Puppet[:code] = "validate_string(#{the_string})"
        scope.compiler.compile
      end

    end

    %w{ true false }.each do |the_string|
      it "should compile when #{the_string} is a string" do
        Puppet[:code] = "validate_string('#{the_string}')"
        scope.compiler.compile
      end

      it "should not compile when #{the_string} is a bare word" do
        Puppet[:code] = "validate_string(#{the_string})"
        expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /is not a string/)
      end
    end

    it "should compile when multiple string arguments are passed" do
      Puppet[:code] = <<-'ENDofPUPPETcode'
        $foo = ''
        $bar = 'two'
        validate_string($foo, $bar)
      ENDofPUPPETcode
      scope.compiler.compile
    end

    it "should compile when an explicitly undef variable is passed (NOTE THIS MAY NOT BE DESIRABLE)" do
      Puppet[:code] = <<-'ENDofPUPPETcode'
        $foo = undef
        validate_string($foo)
      ENDofPUPPETcode
      scope.compiler.compile
    end

    it "should compile when an undefined variable is passed (NOTE THIS MAY NOT BE DESIRABLE)" do
      Puppet[:code] = <<-'ENDofPUPPETcode'
        validate_string($foobarbazishouldnotexist)
      ENDofPUPPETcode
      scope.compiler.compile
    end
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the values_at function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("values_at")).to eq("function_values_at")
  end

  it "should raise a ParseError if there is less than 1 arguments" do
    expect { scope.function_values_at([]) }.to( raise_error(Puppet::ParseError))
  end

  it "should raise a ParseError if you try to use a range where stop is greater then start" do
    expect { scope.function_values_at([['a','b'],["3-1"]]) }.to( raise_error(Puppet::ParseError))
  end

  it "should return a value at from an array" do
    result = scope.function_values_at([['a','b','c'],"1"])
    expect(result).to(eq(['b']))
  end

  it "should return a value at from an array when passed a range" do
    result = scope.function_values_at([['a','b','c'],"0-1"])
    expect(result).to(eq(['a','b']))
  end

  it "should return chosen values from an array when passed number of indexes" do
    result = scope.function_values_at([['a','b','c'],["0","2"]])
    expect(result).to(eq(['a','c']))
  end

  it "should return chosen values from an array when passed ranges and multiple indexes" do
    result = scope.function_values_at([['a','b','c','d','e','f','g'],["0","2","4-5"]])
    expect(result).to(eq(['a','c','e','f']))
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the values function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("values")).to eq("function_values")
  end

  it "should raise a ParseError if there is less than 1 arguments" do
    expect { scope.function_values([]) }.to( raise_error(Puppet::ParseError))
  end

  it "should return values from a hash" do
    result = scope.function_values([{'a'=>'1','b'=>'2','c'=>'3'}])
    # =~ is the RSpec::Matchers::MatchArray matcher.
    # A.K.A. "array with same elements" (multiset) matching
    expect(result).to match_array(%w{ 1 2 3 })
  end

  it "should return a multiset" do
    result = scope.function_values([{'a'=>'1','b'=>'3','c'=>'3'}])
    expect(result).to     match_array(%w{ 1 3 3 })
    expect(result).not_to match_array(%w{ 1 3 })
  end

  it "should raise a ParseError unless a Hash is provided" do
    expect { scope.function_values([['a','b','c']]) }.to( raise_error(Puppet::ParseError))
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the zip function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should raise a ParseError if there is less than 1 arguments" do
    expect { scope.function_zip([]) }.to( raise_error(Puppet::ParseError))
  end

  it "should be able to zip an array" do
    result = scope.function_zip([['1','2','3'],['4','5','6']])
    expect(result).to(eq([["1", "4"], ["2", "5"], ["3", "6"]]))
    result = scope.function_zip([['1','2','3'],['4','5','6'], false])
    result.should(eq([["1", "4"], ["2", "5"], ["3", "6"]]))
  end

  it "should be able to zip an array and flatten" do
    result = scope.function_zip([['1','2','3'],['4','5','6'], true])
    result.should(eq(["1", "4", "2", "5", "3", "6"]))
  end

  it "should accept objects which extend String for the second argument" do
    class AlsoString < String
    end

    value = AlsoString.new('false')
    result = scope.function_zip([['1','2','3'],['4','5','6'],value])
    result.should(eq([["1", "4"], ["2", "5"], ["3", "6"]]))
  end
end
#! /usr/bin/env ruby -S rspec
module PuppetSpec::Compiler
  def compile_to_catalog(string, node = Puppet::Node.new('foonode'))
    Puppet[:code] = string
    Puppet::Parser::Compiler.compile(node)
  end

  def compile_to_ral(manifest)
    catalog = compile_to_catalog(manifest)
    ral = catalog.to_ral
    ral.finalize
    ral
  end

  def compile_to_relationship_graph(manifest, prioritizer = Puppet::Graph::SequentialPrioritizer.new)
    ral = compile_to_ral(manifest)
    graph = Puppet::Graph::RelationshipGraph.new(prioritizer)
    graph.populate_from(ral)
    graph
  end

  if Puppet.version.to_f >= 3.3
    def apply_compiled_manifest(manifest, prioritizer = Puppet::Graph::SequentialPrioritizer.new)
      transaction = Puppet::Transaction.new(compile_to_ral(manifest),
                                          Puppet::Transaction::Report.new("apply"),
                                          prioritizer)
      transaction.evaluate
      transaction.report.finalize_report

      transaction
    end
  else
    def apply_compiled_manifest(manifest)
      transaction = Puppet::Transaction.new(compile_to_ral(manifest), Puppet::Transaction::Report.new("apply"))
      transaction.evaluate
      transaction.report.finalize_report

      transaction
    end
  end

  def order_resources_traversed_in(relationships)
    order_seen = []
    relationships.traverse { |resource| order_seen << resource.ref }
    order_seen
  end
end
#! /usr/bin/env ruby -S rspec
# This just makes some nice things available at global scope, and for setup of
# tests to use a real fake database, rather than a fake stubs-that-don't-work
# version of the same.  Fun times.
def sqlite?
  if $sqlite.nil?
    begin
      require 'sqlite3'
      $sqlite = true
    rescue LoadError
      $sqlite = false
    end
  end
  $sqlite
end

def can_use_scratch_database?
  sqlite? and Puppet.features.rails?
end


# This is expected to be called in your `before :each` block, and will get you
# ready to roll with a serious database and all.  Cleanup is handled
# automatically for you.  Nothing to do there.
def setup_scratch_database
  Puppet[:dbadapter] = 'sqlite3'
  Puppet[:dblocation] = ':memory:'
  Puppet[:railslog] = PuppetSpec::Files.tmpfile('storeconfigs.log')
  Puppet::Rails.init
end
#! /usr/bin/env ruby -S rspec
require 'fileutils'
require 'tempfile'
require 'tmpdir'
require 'pathname'

# A support module for testing files.
module PuppetSpec::Files
  def self.cleanup
    $global_tempfiles ||= []
    while path = $global_tempfiles.pop do
      begin
        Dir.unstub(:entries)
        FileUtils.rm_rf path, :secure => true
      rescue Errno::ENOENT
        # nothing to do
      end
    end
  end

  def make_absolute(path) PuppetSpec::Files.make_absolute(path) end
  def self.make_absolute(path)
    path = File.expand_path(path)
    path[0] = 'c' if Puppet.features.microsoft_windows?
    path
  end

  def tmpfile(name, dir = nil) PuppetSpec::Files.tmpfile(name, dir) end
  def self.tmpfile(name, dir = nil)
    # Generate a temporary file, just for the name...
    source = dir ? Tempfile.new(name, dir) : Tempfile.new(name)
    path = source.path
    source.close!

    record_tmp(File.expand_path(path))

    path
  end

  def file_containing(name, contents) PuppetSpec::Files.file_containing(name, contents) end
  def self.file_containing(name, contents)
    file = tmpfile(name)
    File.open(file, 'wb') { |f| f.write(contents) }
    file
  end

  def tmpdir(name) PuppetSpec::Files.tmpdir(name) end
  def self.tmpdir(name)
    dir = Dir.mktmpdir(name)

    record_tmp(dir)

    dir
  end

  def self.record_tmp(tmp)
    # ...record it for cleanup,
    $global_tempfiles ||= []
    $global_tempfiles << tmp
  end
end
#! /usr/bin/env ruby -S rspec
module PuppetSpec::Fixtures
  def fixtures(*rest)
    File.join(PuppetSpec::FIXTURE_DIR, *rest)
  end
  def my_fixture_dir
    callers = caller
    while line = callers.shift do
      next unless found = line.match(%r{/spec/(.*)_spec\.rb:})
      return fixtures(found[1])
    end
    fail "sorry, I couldn't work out your path from the caller stack!"
  end
  def my_fixture(name)
    file = File.join(my_fixture_dir, name)
    unless File.readable? file then
      fail Puppet::DevError, "fixture '#{name}' for #{my_fixture_dir} is not readable"
    end
    return file
  end
  def my_fixtures(glob = '*', flags = 0)
    files = Dir.glob(File.join(my_fixture_dir, glob), flags)
    unless files.length > 0 then
      fail Puppet::DevError, "fixture '#{glob}' for #{my_fixture_dir} had no files!"
    end
    block_given? and files.each do |file| yield file end
    files
  end
end
#! /usr/bin/env ruby -S rspec
require 'stringio'

########################################################################
# Backward compatibility for Jenkins outdated environment.
module RSpec
  module Matchers
    module BlockAliases
      alias_method :to,     :should      unless method_defined? :to
      alias_method :to_not, :should_not  unless method_defined? :to_not
      alias_method :not_to, :should_not  unless method_defined? :not_to
    end
  end
end


########################################################################
# Custom matchers...
RSpec::Matchers.define :have_matching_element do |expected|
  match do |actual|
    actual.any? { |item| item =~ expected }
  end
end


RSpec::Matchers.define :exit_with do |expected|
  actual = nil
  match do |block|
    begin
      block.call
    rescue SystemExit => e
      actual = e.status
    end
    actual and actual == expected
  end
  failure_message_for_should do |block|
    "expected exit with code #{expected} but " +
      (actual.nil? ? " exit was not called" : "we exited with #{actual} instead")
  end
  failure_message_for_should_not do |block|
    "expected that exit would not be called with #{expected}"
  end
  description do
    "expect exit with #{expected}"
  end
end

class HavePrintedMatcher
  attr_accessor :expected, :actual

  def initialize(expected)
    case expected
    when String, Regexp
      @expected = expected
    else
      @expected = expected.to_s
    end
  end

  def matches?(block)
    begin
      $stderr = $stdout = StringIO.new
      $stdout.set_encoding('UTF-8') if $stdout.respond_to?(:set_encoding)
      block.call
      $stdout.rewind
      @actual = $stdout.read
    ensure
      $stdout = STDOUT
      $stderr = STDERR
    end

    if @actual then
      case @expected
      when String
        @actual.include? @expected
      when Regexp
        @expected.match @actual
      end
    else
      false
    end
  end

  def failure_message_for_should
    if @actual.nil? then
      "expected #{@expected.inspect}, but nothing was printed"
    else
      "expected #{@expected.inspect} to be printed; got:\n#{@actual}"
    end
  end

  def failure_message_for_should_not
    "expected #{@expected.inspect} to not be printed; got:\n#{@actual}"
  end

  def description
    "expect #{@expected.inspect} to be printed"
  end
end

def have_printed(what)
  HavePrintedMatcher.new(what)
end

RSpec::Matchers.define :equal_attributes_of do |expected|
  match do |actual|
    actual.instance_variables.all? do |attr|
      actual.instance_variable_get(attr) == expected.instance_variable_get(attr)
    end
  end
end

RSpec::Matchers.define :be_one_of do |*expected|
  match do |actual|
    expected.include? actual
  end

  failure_message_for_should do |actual|
    "expected #{actual.inspect} to be one of #{expected.map(&:inspect).join(' or ')}"
  end
end
#! /usr/bin/env ruby -S rspec
module PuppetSpec::Modules
  class << self
    def create(name, dir, options = {})
      module_dir = File.join(dir, name)
      FileUtils.mkdir_p(module_dir)

      environment = options[:environment]

      if metadata = options[:metadata]
        metadata[:source]  ||= 'github'
        metadata[:author]  ||= 'puppetlabs'
        metadata[:version] ||= '9.9.9'
        metadata[:license] ||= 'to kill'
        metadata[:dependencies] ||= []

        metadata[:name] = "#{metadata[:author]}/#{name}"

        File.open(File.join(module_dir, 'metadata.json'), 'w') do |f|
          f.write(metadata.to_pson)
        end
      end

      Puppet::Module.new(name, module_dir, environment)
    end
  end
end
#! /usr/bin/env ruby -S rspec
module PuppetSpec::Pops
  extend RSpec::Matchers::DSL

  # Checks if an Acceptor has a specific issue in its list of diagnostics
  matcher :have_issue do |expected|
    match do |actual|
      actual.diagnostics.index { |i| i.issue == expected } != nil
    end
    failure_message_for_should do |actual|
      "expected Acceptor[#{actual.diagnostics.collect { |i| i.issue.issue_code }.join(',')}] to contain issue #{expected.issue_code}"
    end
    failure_message_for_should_not do |actual|
      "expected Acceptor[#{actual.diagnostics.collect { |i| i.issue.issue_code }.join(',')}] to not contain issue #{expected.issue_code}"
    end
  end
end
#! /usr/bin/env ruby -S rspec

module PuppetSpec::Scope
  # Initialize a new scope suitable for testing.
  #
  def create_test_scope_for_node(node_name)
    node = Puppet::Node.new(node_name)
    compiler = Puppet::Parser::Compiler.new(node)
    scope = Puppet::Parser::Scope.new(compiler)
    scope.source = Puppet::Resource::Type.new(:node, node_name)
    scope.parent = compiler.topscope
    scope
  end

end
#! /usr/bin/env ruby -S rspec
module PuppetSpec::Settings

  # It would probably be preferable to refactor defaults.rb such that the real definitions of
  #  these settings were available as a variable, which was then accessible for use during tests.
  #  However, I'm not doing that yet because I don't want to introduce any additional moving parts
  #  to this already very large changeset.
  #  Would be nice to clean this up later.  --cprice 2012-03-20
  TEST_APP_DEFAULT_DEFINITIONS = {
    :name         => { :default => "test", :desc => "name" },
    :logdir       => { :type => :directory, :default => "test", :desc => "logdir" },
    :confdir      => { :type => :directory, :default => "test", :desc => "confdir" },
    :vardir       => { :type => :directory, :default => "test", :desc => "vardir" },
    :rundir       => { :type => :directory, :default => "test", :desc => "rundir" },
  }
end
#! /usr/bin/env ruby -S rspec
# Support code for running stuff with warnings disabled.
module Kernel
  def with_verbose_disabled
    verbose, $VERBOSE = $VERBOSE, nil
    result = yield
    $VERBOSE = verbose
    return result
  end
end
#! /usr/bin/env ruby -S rspec
require 'rspec'

class Object
  # This is necessary because the RAL has a 'should'
  # method.
  alias :must :should
  alias :must_not :should_not
end
#! /usr/bin/env ruby -S rspec
# Some monkey-patching to allow us to test private methods.
class Class
    def publicize_methods(*methods)
        saved_private_instance_methods = methods.empty? ? self.private_instance_methods : methods

        self.class_eval { public(*saved_private_instance_methods) }
        yield
        self.class_eval { private(*saved_private_instance_methods) }
    end
end
s
mtime
#! /usr/bin/env ruby -S rspec
dir = File.expand_path(File.dirname(__FILE__))
$LOAD_PATH.unshift File.join(dir, 'lib')

# So everyone else doesn't have to include this base constant.
module PuppetSpec
  FIXTURE_DIR = File.join(dir = File.expand_path(File.dirname(__FILE__)), "fixtures") unless defined?(FIXTURE_DIR)
end

require 'puppet'
require 'rspec-puppet'
require 'puppetlabs_spec_helper/module_spec_helper'
require 'puppet_spec/verbose'
require 'puppet_spec/files'
require 'puppet_spec/settings'
require 'puppet_spec/fixtures'
require 'puppet_spec/matchers'
require 'puppet_spec/database'
require 'monkey_patches/alias_should_to_must'
require 'mocha/setup'



RSpec.configure do |config|
  config.before :each do
    # Ensure that we don't accidentally cache facts and environment between
    # test cases.  This requires each example group to explicitly load the
    # facts being exercised with something like
    # Facter.collection.loader.load(:ipaddress)
    Facter::Util::Loader.any_instance.stubs(:load_all)
    Facter.clear
    Facter.clear_messages
  end
end
#! /usr/bin/env ruby -S rspec
require 'beaker-rspec'

UNSUPPORTED_PLATFORMS = []

unless ENV['RS_PROVISION'] == 'no' or ENV['BEAKER_provision'] == 'no'
  foss_opts = {
    :default_action => 'gem_install',
    :version        => (ENV['PUPPET_VERSION'] ? ENV['PUPPET_VERSION'] : '3.7.2'),
  }

  if default.is_pe?; then install_pe; else install_puppet( foss_opts ); end

  hosts.each do |host|
    if host['platform'] !~ /windows/i
      if host.is_pe?
        on host, 'mkdir -p /etc/puppetlabs/facter/facts.d'
      else
        on host, "/bin/touch #{host['puppetpath']}/hiera.yaml"
        on host, "mkdir -p #{host['distmoduledir']}"
        on host, 'mkdir -p /etc/facter/facts.d'
      end
    end
  end
end

RSpec.configure do |c|
  # Project root
  proj_root = File.expand_path(File.join(File.dirname(__FILE__), '..'))

  # Readable test descriptions
  c.formatter = :documentation

  # Configure all nodes in nodeset
  c.before :suite do
    if ENV['FUTURE_PARSER'] == 'true'
      default[:default_apply_opts] ||= {}
      default[:default_apply_opts].merge!({:parser => 'future'})
    end

    copy_root_module_to(default, :source => proj_root, :module_name => 'stdlib')
  end
end

def is_future_parser_enabled?
  if default[:default_apply_opts]
    return default[:default_apply_opts][:parser] == 'future'
  end
  return false
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'
require 'facter/facter_dot_d'

describe Facter::Util::DotD do

  context 'returns a simple fact' do
    before :each do
      Facter.stubs(:version).returns('1.6.1')
      subject.stubs(:entries).returns(['/etc/facter/facts.d/fake_fact.txt'])
      File.stubs(:readlines).with('/etc/facter/facts.d/fake_fact.txt').returns(['fake_fact=fake fact'])
      subject.create
    end

    it 'should return successfully' do
      expect(Facter.fact(:fake_fact).value).to eq('fake fact')
    end
  end

  context 'returns a fact with equals signs' do
    before :each do
      Facter.stubs(:version).returns('1.6.1')
      subject.stubs(:entries).returns(['/etc/facter/facts.d/foo.txt'])
      File.stubs(:readlines).with('/etc/facter/facts.d/foo.txt').returns(['foo=1+1=2'])
      subject.create
    end

    it 'should return successfully' do
      expect(Facter.fact(:foo).value).to eq('1+1=2')
    end
  end
end
#!/usr/bin/env rspec

require 'spec_helper'

describe "PE Version specs" do
  before :each do
    # Explicitly load the pe_version.rb file which contains generated facts
    # that cannot be automatically loaded.  Puppet 2.x implements
    # Facter.collection.load while Facter 1.x markes Facter.collection.load as
    # a private method.
    if Facter.collection.respond_to? :load
      Facter.collection.load(:pe_version)
    else
      Facter.collection.loader.load(:pe_version)
    end
  end

  context "If PE is installed" do
    %w{ 2.6.1 2.10.300 }.each do |version|
      puppetversion = "2.7.19 (Puppet Enterprise #{version})"
      context "puppetversion => #{puppetversion}" do
        before :each do
          Facter.fact(:puppetversion).stubs(:value).returns(puppetversion)
        end

        (major,minor,patch) = version.split(".")

        it "Should return true" do
          expect(Facter.fact(:is_pe).value).to eq(true)
        end

        it "Should have a version of #{version}" do
          expect(Facter.fact(:pe_version).value).to eq(version)
        end

        it "Should have a major version of #{major}" do
          expect(Facter.fact(:pe_major_version).value).to eq(major)
        end

        it "Should have a minor version of #{minor}" do
          expect(Facter.fact(:pe_minor_version).value).to eq(minor)
        end

        it "Should have a patch version of #{patch}" do
          expect(Facter.fact(:pe_patch_version).value).to eq(patch)
        end
      end
    end
  end

  context "When PE is not installed" do
    before :each do
      Facter.fact(:puppetversion).stubs(:value).returns("2.7.19")
    end

    it "is_pe is false" do
      expect(Facter.fact(:is_pe).value).to eq(false)
    end

    it "pe_version is nil" do
      expect(Facter.fact(:pe_version).value).to be_nil
    end

    it "pe_major_version is nil" do
      expect(Facter.fact(:pe_major_version).value).to be_nil
    end

    it "pe_minor_version is nil" do
      expect(Facter.fact(:pe_minor_version).value).to be_nil
    end

    it "Should have a patch version" do
      expect(Facter.fact(:pe_patch_version).value).to be_nil
    end
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'
require 'facter/root_home'

describe Facter::Util::RootHome do
  context "solaris" do
    let(:root_ent) { "root:x:0:0:Super-User:/:/sbin/sh" }
    let(:expected_root_home) { "/" }

    it "should return /" do
      Facter::Util::Resolution.expects(:exec).with("getent passwd root").returns(root_ent)
      expect(Facter::Util::RootHome.get_root_home).to eq(expected_root_home)
    end
  end
  context "linux" do
    let(:root_ent) { "root:x:0:0:root:/root:/bin/bash" }
    let(:expected_root_home) { "/root" }

    it "should return /root" do
      Facter::Util::Resolution.expects(:exec).with("getent passwd root").returns(root_ent)
      expect(Facter::Util::RootHome.get_root_home).to eq(expected_root_home)
    end
  end
  context "windows" do
    before :each do
      Facter::Util::Resolution.expects(:exec).with("getent passwd root").returns(nil)
    end
    it "should be nil on windows" do
      expect(Facter::Util::RootHome.get_root_home).to be_nil
    end
  end
end

describe 'root_home', :type => :fact do
  before { Facter.clear }
  after { Facter.clear }

  context "macosx" do
    before do
      Facter.fact(:kernel).stubs(:value).returns("Darwin")
      Facter.fact(:osfamily).stubs(:value).returns("Darwin")
    end
    let(:expected_root_home) { "/var/root" }
    sample_dscacheutil = File.read(fixtures('dscacheutil','root'))

    it "should return /var/root" do
      Facter::Util::Resolution.stubs(:exec).with("dscacheutil -q user -a name root").returns(sample_dscacheutil)
      expect(Facter.fact(:root_home).value).to eq(expected_root_home)
    end
  end

end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'
require 'facter/util/puppet_settings'

describe Facter::Util::PuppetSettings do

  describe "#with_puppet" do
    context "Without Puppet loaded" do
      before(:each) do
        Module.expects(:const_get).with("Puppet").raises(NameError)
      end

      it 'should be nil' do
        expect(subject.with_puppet { Puppet[:vardir] }).to be_nil
      end
      it 'should not yield to the block' do
        Puppet.expects(:[]).never
        expect(subject.with_puppet { Puppet[:vardir] }).to be_nil
      end
    end
    context "With Puppet loaded" do
      module Puppet; end
      let(:vardir) { "/var/lib/puppet" }

      before :each do
        Puppet.expects(:[]).with(:vardir).returns vardir
      end
      it 'should yield to the block' do
        subject.with_puppet { Puppet[:vardir] }
      end
      it 'should return the nodes vardir' do
        expect(subject.with_puppet { Puppet[:vardir] }).to eq vardir
      end
    end
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the bool2str function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("bool2str")).to eq("function_bool2str")
  end

  it "should raise a ParseError if there is less than 1 arguments" do
    expect { scope.function_bool2str([]) }.to( raise_error(Puppet::ParseError))
  end

  it "should convert true to 'true'" do
    result = scope.function_bool2str([true])
    expect(result).to(eq('true'))
  end

  it "should convert true to a string" do
    result = scope.function_bool2str([true])
    expect(result.class).to(eq(String))
  end

  it "should convert false to 'false'" do
    result = scope.function_bool2str([false])
    expect(result).to(eq('false'))
  end

  it "should convert false to a string" do
    result = scope.function_bool2str([false])
    expect(result.class).to(eq(String))
  end

  it "should not accept a string" do
    expect { scope.function_bool2str(["false"]) }.to( raise_error(Puppet::ParseError))
  end

  it "should not accept a nil value" do
    expect { scope.function_bool2str([nil]) }.to( raise_error(Puppet::ParseError))
  end

  it "should not accept an undef" do
    expect { scope.function_bool2str([:undef]) }.to( raise_error(Puppet::ParseError))
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'

describe "the camelcase function" do
  let(:scope) { PuppetlabsSpec::PuppetInternals.scope }

  it "should exist" do
    expect(Puppet::Parser::Functions.function("camelcase")).to eq("function_camelcase")
  end

  it "should raise a ParseError if there is less than 1 arguments" do
    expect { scope.function_camelcase([]) }.to( raise_error(Puppet::ParseError))
  end

  it "should capitalize the beginning of a normal string" do
    result = scope.function_camelcase(["abc"])
    expect(result).to(eq("Abc"))
  end

  it "should camelcase an underscore-delimited string" do
    result = scope.function_camelcase(["aa_bb_cc"])
    expect(result).to(eq("AaBbCc"))
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'
require 'tempfile'
provider_class = Puppet::Type.type(:file_line).provider(:ruby)
describe provider_class do
  context "when adding" do
    let :tmpfile do
      tmp = Tempfile.new('tmp')
      path = tmp.path
      tmp.close!
      path
    end
    let :resource do
      Puppet::Type::File_line.new(
        {:name => 'foo', :path => tmpfile, :line => 'foo'}
      )
    end
    let :provider do
      provider_class.new(resource)
    end

    it 'should detect if the line exists in the file' do
      File.open(tmpfile, 'w') do |fh|
        fh.write('foo')
      end
      expect(provider.exists?).to be_truthy
    end
    it 'should detect if the line does not exist in the file' do
      File.open(tmpfile, 'w') do |fh|
        fh.write('foo1')
      end
      expect(provider.exists?).to be_nil
    end
    it 'should append to an existing file when creating' do
      provider.create
      expect(File.read(tmpfile).chomp).to eq('foo')
    end
  end

  context "when matching" do
    before :each do
      # TODO: these should be ported over to use the PuppetLabs spec_helper
      #  file fixtures once the following pull request has been merged:
      # https://github.com/puppetlabs/puppetlabs-stdlib/pull/73/files
      tmp = Tempfile.new('tmp')
      @tmpfile = tmp.path
      tmp.close!
      @resource = Puppet::Type::File_line.new(
          {
           :name => 'foo',
           :path => @tmpfile,
           :line => 'foo = bar',
           :match => '^foo\s*=.*$',
          }
      )
      @provider = provider_class.new(@resource)
    end

    describe 'using match' do
      it 'should raise an error if more than one line matches, and should not have modified the file' do
        File.open(@tmpfile, 'w') do |fh|
          fh.write("foo1\nfoo=blah\nfoo2\nfoo=baz")
        end
        expect(@provider.exists?).to be_nil
        expect { @provider.create }.to raise_error(Puppet::Error, /More than one line.*matches/)
        expect(File.read(@tmpfile)).to eql("foo1\nfoo=blah\nfoo2\nfoo=baz")
      end

      it 'should replace all lines that matches' do
        @resource = Puppet::Type::File_line.new(
          {
            :name => 'foo',
            :path => @tmpfile,
            :line => 'foo = bar',
            :match => '^foo\s*=.*$',
            :multiple => true
          }
        )
        @provider = provider_class.new(@resource)
        File.open(@tmpfile, 'w') do |fh|
          fh.write("foo1\nfoo=blah\nfoo2\nfoo=baz")
        end
        expect(@provider.exists?).to be_nil
        @provider.create
        expect(File.read(@tmpfile).chomp).to eql("foo1\nfoo = bar\nfoo2\nfoo = bar")
      end

      it 'should raise an error with invalid values' do
        expect {
          @resource = Puppet::Type::File_line.new(
            {
              :name => 'foo',
              :path => @tmpfile,
              :line => 'foo = bar',
              :match => '^foo\s*=.*$',
              :multiple => 'asgadga'
            }
          )
        }.to raise_error(Puppet::Error, /Invalid value "asgadga"\. Valid values are true, false\./)
      end

      it 'should replace a line that matches' do
        File.open(@tmpfile, 'w') do |fh|
          fh.write("foo1\nfoo=blah\nfoo2")
        end
        expect(@provider.exists?).to be_nil
        @provider.create
        expect(File.read(@tmpfile).chomp).to eql("foo1\nfoo = bar\nfoo2")
      end
      it 'should add a new line if no lines match' do
        File.open(@tmpfile, 'w') do |fh|
          fh.write("foo1\nfoo2")
        end
        expect(@provider.exists?).to be_nil
        @provider.create
        expect(File.read(@tmpfile)).to eql("foo1\nfoo2\nfoo = bar\n")
      end
      it 'should do nothing if the exact line already exists' do
        File.open(@tmpfile, 'w') do |fh|
          fh.write("foo1\nfoo = bar\nfoo2")
        end
        expect(@provider.exists?).to be_truthy
        @provider.create
        expect(File.read(@tmpfile).chomp).to eql("foo1\nfoo = bar\nfoo2")
      end
    end

    describe 'using after' do
      let :resource do
        Puppet::Type::File_line.new(
          {
            :name  => 'foo',
            :path  => @tmpfile,
            :line  => 'inserted = line',
            :after => '^foo1',
          }
        )
      end

      let :provider do
        provider_class.new(resource)
      end

      context 'with one line matching the after expression' do
        before :each do
          File.open(@tmpfile, 'w') do |fh|
            fh.write("foo1\nfoo = blah\nfoo2\nfoo = baz")
          end
        end

        it 'inserts the specified line after the line matching the "after" expression' do
          provider.create
          expect(File.read(@tmpfile).chomp).to eql("foo1\ninserted = line\nfoo = blah\nfoo2\nfoo = baz")
        end
      end

      context 'with two lines matching the after expression' do
        before :each do
          File.open(@tmpfile, 'w') do |fh|
            fh.write("foo1\nfoo = blah\nfoo2\nfoo1\nfoo = baz")
          end
        end

        it 'errors out stating "One or no line must match the pattern"' do
          expect { provider.create }.to raise_error(Puppet::Error, /One or no line must match the pattern/)
        end
      end

      context 'with no lines matching the after expression' do
        let :content do
          "foo3\nfoo = blah\nfoo2\nfoo = baz\n"
        end

        before :each do
          File.open(@tmpfile, 'w') do |fh|
            fh.write(content)
          end
        end

        it 'appends the specified line to the file' do
          provider.create
          expect(File.read(@tmpfile)).to eq(content << resource[:line] << "\n")
        end
      end
    end
  end

  context "when removing" do
    before :each do
      # TODO: these should be ported over to use the PuppetLabs spec_helper
      #  file fixtures once the following pull request has been merged:
      # https://github.com/puppetlabs/puppetlabs-stdlib/pull/73/files
      tmp = Tempfile.new('tmp')
      @tmpfile = tmp.path
      tmp.close!
      @resource = Puppet::Type::File_line.new(
        {:name => 'foo', :path => @tmpfile, :line => 'foo', :ensure => 'absent' }
      )
      @provider = provider_class.new(@resource)
    end
    it 'should remove the line if it exists' do
      File.open(@tmpfile, 'w') do |fh|
        fh.write("foo1\nfoo\nfoo2")
      end
      @provider.destroy
      expect(File.read(@tmpfile)).to eql("foo1\nfoo2")
    end

    it 'should remove the line without touching the last new line' do
      File.open(@tmpfile, 'w') do |fh|
        fh.write("foo1\nfoo\nfoo2\n")
      end
      @provider.destroy
      expect(File.read(@tmpfile)).to eql("foo1\nfoo2\n")
    end

    it 'should remove any occurence of the line' do
      File.open(@tmpfile, 'w') do |fh|
        fh.write("foo1\nfoo\nfoo2\nfoo\nfoo")
      end
      @provider.destroy
      expect(File.read(@tmpfile)).to eql("foo1\nfoo2\n")
    end
  end
end
#!/usr/bin/env ruby

require 'spec_helper'

anchor = Puppet::Type.type(:anchor).new(:name => "ntp::begin")

describe anchor do
  it "should stringify normally" do
    expect(anchor.to_s).to eq("Anchor[ntp::begin]")
  end
end
#! /usr/bin/env ruby -S rspec
require 'spec_helper'
require 'tempfile'
describe Puppet::Type.type(:file_line) do
  let :file_line do
    Puppet::Type.type(:file_line).new(:name => 'foo', :line => 'line', :path => '/tmp/path')
  end
  it 'should accept a line and path' do
    file_line[:line] = 'my_line'
    expect(file_line[:line]).to eq('my_line')
    file_line[:path] = '/my/path'
    expect(file_line[:path]).to eq('/my/path')
  end
  it 'should accept a match regex' do
    file_line[:match] = '^foo.*$'
    expect(file_line[:match]).to eq('^foo.*$')
  end
  it 'should not accept a match regex that does not match the specified line' do
    expect {
      Puppet::Type.type(:file_line).new(
          :name   => 'foo',
          :path   => '/my/path',
          :line   => 'foo=bar',
          :match  => '^bar=blah$'
    )}.to raise_error(Puppet::Error, /the value must be a regex that matches/)
  end
  it 'should accept a match regex that does match the specified line' do
    expect {
      Puppet::Type.type(:file_line).new(
          :name   => 'foo',
          :path   => '/my/path',
          :line   => 'foo=bar',
          :match  => '^\s*foo=.*$'
      )}.not_to raise_error
  end
  it 'should accept posix filenames' do
    file_line[:path] = '/tmp/path'
    expect(file_line[:path]).to eq('/tmp/path')
  end
  it 'should not accept unqualified path' do
    expect { file_line[:path] = 'file' }.to raise_error(Puppet::Error, /File paths must be fully qualified/)
  end
  it 'should require that a line is specified' do
    expect { Puppet::Type.type(:file_line).new(:name => 'foo', :path => '/tmp/file') }.to raise_error(Puppet::Error, /Both line and path are required attributes/)
  end
  it 'should require that a file is specified' do
    expect { Puppet::Type.type(:file_line).new(:name => 'foo', :line => 'path') }.to raise_error(Puppet::Error, /Both line and path are required attributes/)
  end
  it 'should default to ensure => present' do
    expect(file_line[:ensure]).to eq :present
  end

  it "should autorequire the file it manages" do
    catalog = Puppet::Resource::Catalog.new
    file = Puppet::Type.type(:file).new(:name => "/tmp/path")
    catalog.add_resource file
    catalog.add_resource file_line

    relationship = file_line.autorequire.find do |rel|
      (rel.source.to_s == "File[/tmp/path]") and (rel.target.to_s == file_line.to_s)
    end
    expect(relationship).to be_a Puppet::Relationship
  end

  it "should not autorequire the file it manages if it is not managed" do
    catalog = Puppet::Resource::Catalog.new
    catalog.add_resource file_line
    expect(file_line.autorequire).to be_empty
  end
end
# This is a simple smoke test
# of the file_line resource type.
file { '/tmp/dansfile':
  ensure => present
}->
file_line { 'dans_line':
  line => 'dan is awesome',
  path => '/tmp/dansfile',
}
include stdlib
info('has_interface_with(\'lo\'):', has_interface_with('lo'))
info('has_interface_with(\'loX\'):', has_interface_with('loX'))
info('has_interface_with(\'ipaddress\', \'127.0.0.1\'):', has_interface_with('ipaddress', '127.0.0.1'))
info('has_interface_with(\'ipaddress\', \'127.0.0.100\'):', has_interface_with('ipaddress', '127.0.0.100'))
info('has_interface_with(\'network\', \'127.0.0.0\'):', has_interface_with('network', '127.0.0.0'))
info('has_interface_with(\'network\', \'128.0.0.0\'):', has_interface_with('network', '128.0.0.0'))
info('has_interface_with(\'netmask\', \'255.0.0.0\'):', has_interface_with('netmask', '255.0.0.0'))
info('has_interface_with(\'netmask\', \'256.0.0.0\'):', has_interface_with('netmask', '256.0.0.0'))

include stdlib
info('has_ip_address(\'192.168.1.256\'):', has_ip_address('192.168.1.256'))
info('has_ip_address(\'127.0.0.1\'):', has_ip_address('127.0.0.1'))
include stdlib
info('has_ip_network(\'127.0.0.0\'):', has_ip_network('127.0.0.0'))
info('has_ip_network(\'128.0.0.0\'):', has_ip_network('128.0.0.0'))

include stdlib
fixtures:
  repositories:
    'stdlib':
      repo: 'git://github.com/puppetlabs/puppetlabs-stdlib'
      ref: '4.1.0'
    'concat':
      repo: 'git://github.com/puppetlabs/puppetlabs-concat'
      ref: '1.0.1'
  symlinks:
    supervisord: "#{source_dir}"
default_set: 'centos-64-x64'
sets:
  'centos-59-x64':
    nodes:
      "main.foo.vm":
        prefab: 'centos-59-x64'
  'centos-64-x64':
    nodes:
      "main.foo.vm":
        prefab: 'centos-64-x64'
  'debian-607-x64':
    nodes:
      "main.foo.vm":
        prefab: 'debian-607-x64'
  'debian-70rc1-x64':
    nodes:
      "main.foo.vm":
        prefab: 'debian-70rc1-x64'
  'ubuntu-server-10044-x64':
    nodes:
      "main.foo.vm":
        prefab: 'ubuntu-server-10044-x64'
  'ubuntu-server-12042-x64':
    nodes:
      "main.foo.vm":
        prefab: 'ubuntu-server-12042-x64'
language: ruby
bundler_args: --without development
script: "bundle exec rake test"
rvm:
- 1.8.7
- 1.9.3
- 2.0.0
env:
  - PUPPET_VERSION="~> 2.7.0"
  - PUPPET_VERSION="~> 3.1.0"
  - PUPPET_VERSION="~> 3.2.0"
  - PUPPET_VERSION="~> 3.3.0"
  - PUPPET_VERSION="~> 3.4.0"
  - PUPPET_VERSION="~> 3.5.0"
  - PUPPET_VERSION="~> 3.6.0"
matrix:
  exclude:
  - rvm: 2.0.0
    env: PUPPET_VERSION="~> 2.7.0"
  - rvm: 1.9.3
    env: PUPPET_VERSION="~> 2.7.0"
  - rvm: 2.0.0
    env: PUPPET_VERSION="~> 3.1.0"
  - rvm: 1.8.7
    env: PUPPET_VERSION="~> 3.2.0"
notifications:
  email: false

before_install:
  - gem update --system 2.1.11
  - gem --version
2014-07-02 - v0.4.1

Fixes:

- Fixed status code error on supervisord::supervisorctl commands, thanks to @jtreminio for the PR.

2014-06-20 - v0.4.0

Fixes:

- Removed root as group and replaced with uid 0 to enhance system
compatibility

Enhancements:

- Made package provider a user definable param see supervisord::package_provider and README for details of how to change this.
- All define types can now be automatically pulled in from hiera see example https://github.com/ajcrowe/puppet-supervisord#configure-a-program
- You can now override the default include path of $config_include/*.conf with your own array using $config_dirs. Bear in mind this would need to include whatever you set $config_include to be, with *.conf on the end.

Many thanks for the PRs from @jasperla, @mvantellingen for the bug report on the service name and @hasc for the enhancement ideas.

2014-06-06 - v0.3.3

Fixes:

- Fixed typo in stopwaitsec param, should have been stopwaitsecs, thanks to @rchrd2

2014-05-03 - v0.3.2

Changes:

- Added supervisord::executable_ctl variable for supervisorctl binary path, thanks to @bpgoldsb

2014-04-22 - v0.3.1

Fixes:

- Fixed typo in unix_socket_group param, thanks to @dig412

2014-03-11 - v0.3.0

Fixes:

- Fixed typo in fcgi config
- Fixed typo in supervisord config with minfds and minprocs, thanks to @peefourtee
- Typo in README fixed thanks to @hopkinsth
- Removed refreshonly from pip_install exec resource
- Number of syntax fixes thanks to `puppet lint`

Important Changes:

- Lots of input validation has been added **PLEASE** check your config works before upgrading!
- Changed init_extras naming to defaults and cleaned things up.
- Starting and stopping apps is now done with supervisorctl commands to avoid service restarts

Other Changes:

- CSV functions now order things consistently
- Included description for classes and functions
- Expanded spec testing built with Travis CI
- Added beaker acceptance tests
- Added greater validation of various parameters
- Added coverage reporting for resources

To-Do:

- Add support for additional OS families such as Solaris.


2013-10-31 - v0.2.3

Fixes:

- Fixed large bug on debian wheezy where /var/run is changed from a symlink to a 
  directory causing all pids to be inaccessible breaking lots of services


2013-10-30 - v0.2.2

Fixes:

- Fixed syntax error in README examples and tests

2013-10-16 - v0.2.1

Fixes:

- Fixed user params in templates
- Added missing environment support in main supervisord.conf


2013-10-15 - v0.2.0

Feature complete release

- Added Eventlistener template and function
- Added FGCI-Program template and function
- More consistent log naming and fixed missing new lines


2013-10-15 - v0.1.1

Fixes:

- Missing '=' in template tags when using certain parameters
- Added log file default to program define to avoid /tmp being used when not specified
- Fixed logic when not using environment variables in program


2013-10-15 - v0.1.0

Summary:

Completed basic module functionality for

- Install with pip
- Configure programs
- Configure groups
- Install init scripts for RedHat and Debian families 
source 'https://rubygems.org'

group :test do
  gem 'rake'
  gem 'puppet-lint'
  gem 'puppet-syntax'
  gem 'puppetlabs_spec_helper'
  gem 'rspec-puppet', :git => 'https://github.com/rodjek/rspec-puppet.git' , :ref => 'c44381a240ec420d4ffda7bffc55ee4d9c08d682'
  gem 'rspec', '2.14.1'
end

group :development do
  gem 'travis'
  gem 'travis-lint'
  gem 'beaker'
  gem 'beaker-rspec'
  gem 'pry'
  gem 'guard-rake'
end


if puppetversion = ENV['PUPPET_VERSION']
  gem 'puppet', puppetversion
else
  gem 'puppet', '~> 3.4.0'
end
name    'ajcrowe-supervisord'
version '0.4.1'
source 'git@github.com/ajcrowe/puppet-supervisord.git'
author 'Alex Crowe'
license 'Apache License, Version 2.0'
summary 'supervisord class and functions'
description 'supervisord class and functions'
project_page 'https://github.com/ajcrowe/puppet-supervisord'

dependency 'puppetlabs/concat', '>= 1.0.0 <2.0.0'
dependency 'puppetlabs/stdlib', '>= 4.1.0'
# Puppet Supervisord

[![Build Status](https://travis-ci.org/ajcrowe/puppet-supervisord.png?branch=master)](https://travis-ci.org/ajcrowe/puppet-supervisord)

Puppet module to manage the [supervisord](http://supervisord.org/) process control system.

Functions available to configure

* [programs](http://supervisord.org/configuration.html#program-x-section-settings)
* [groups](http://supervisord.org/configuration.html#group-x-section-settings)
* [fcgi-programs](http://supervisord.org/configuration.html#fcgi-program-x-section-settings)
* [eventlisteners](http://supervisord.org/configuration.html#eventlistener-x-section-settings)

## Examples

### Configuring supervisord with defaults

Install supervisord with pip and install an init script if available

```ruby
include supervisord
```

### Install supervisord and pip

Install supervisord and install pip if not available.

```ruby
class supervisord {
  $install_pip  => true,
}
```

This will download [setuptool](https://bitbucket.org/pypa/setuptools) and install pip with easy_install.

You can pass a specific url with `$setuptools_url = 'url'`

### Install without pip

If you want to use your system package manager you can specify that with `supervisord::package_provider`.

You'll also likely need to adjust the `supervisord::service_name` to match that installed by the system package. If you're using Debian or Redhat OS families you'll also want to disable the init scripts with `supervisord::install_init = false`.

Note: Only Debian and RedHat families have an init script currently.

### Configure a program

```ruby
supervisord::program { 'myprogram':
  command     => 'command --args',
  priority    => '100',
  environment => {
    'HOME'   => '/home/myuser',
    'PATH'   => '/bin:/sbin:/usr/bin:/usr/sbin',
    'SECRET' => 'mysecret'
  }
}
```

You may also specify a variable for a hiera lookup to retreive your environment hash. This allows you to reuse existing environment variable hashes.

```ruby
supervisord::program { 'myprogram':
  command  => 'command --args',
  priority => '100',
  env_var  => 'my_common_envs'
}
```

Or you can fully define your programs in hiera:

```yaml
supervisord::programs:
  'myprogram':
    command: 'command --args'
    autostart: yes
    autorestart: 'true'
    environment:
      HOME: '/home/myuser'
      PATH: '/bin:/sbin:/usr/bin:/usr/sbin'
      SECRET: 'mysecret'
```

### Configure a group

```ruby
supervisord::group { 'mygroup':
  priority => 100,
  programs  => ['program1', 'program2', 'program3']
}
```

### Configure an eventlistener

```ruby
supervisord::eventlistener { 'mylistener':
  command  => 'command --args',
  events   => ['PROCESS_STATE', 'PROCESS_STATE_START']
  priority => '100',
  env_var  => 'my_common_envs'
}
```

### Run supervisorctl Commands

Should you need to run a sequence of command with `supervisorctl` you can use the define type `supervisord::supervisorctl`

```ruby
supervisord::supervisorctl { 'restart_myapp':
  command => 'restart',
  process => 'myapp'
}
```

You can also issue a command without specifying a process.

### Development

If you have suggestions or improvements please file an issue or pull request, i'll try and sort them as quickly as possble.

If you submit a pull please try and include tests for the new functionality/fix. The module is tested with [Travis-CI](https://travis-ci.org/ajcrowe/puppet-supervisord).


### Credits

* Debian init script sourced from the system package.
* RedHat/Centos init script sourced from https://github.com/Supervisor/initscripts
require 'puppetlabs_spec_helper/rake_tasks'
require 'puppet-lint/tasks/puppet-lint'
require 'puppet-syntax/tasks/puppet-syntax'

PuppetLint.configuration.send('disable_80chars')
PuppetLint.configuration.send('disable_class_inherits_from_params_class')
PuppetLint.configuration.send('disable_quoted_booleans')
PuppetLint.configuration.send('disable_autoloader_layout')

exclude_paths = [
  "pkg/**/*",
  "vendor/**/*",
  "spec/**/*",
]
PuppetLint.configuration.ignore_paths = exclude_paths
PuppetSyntax.exclude_paths = exclude_paths

desc "Acceptance Tests"
RSpec::Core::RakeTask.new(:acceptance) do |t|
  t.pattern = 'spec/acceptance'
end

desc "Test Suite"
task :test => [
  :lint,
  :syntax,
  :spec
]
#
# Converts the array to a csv string
#
# $array = [ 'string1', 'string2', 'string3' ]
#
# becomes:
#
# $string = "string1,string2,string3"
#
module Puppet::Parser::Functions
  newfunction(:array2csv, :type => :rvalue, :doc => <<-'EOS'
    Returns a sorted csv formatted string from an array in the form
    VALUE1,VALUE2,VALUE3
    EOS
  ) do |args|

    raise(Puppet::ParseError, "array2csv(): Wrong number of arguments " +
      "given (#{args.size} of 1)") if args.size < 1

    array = args[0]

    unless array.is_a?(Array)
      raise(Puppet::ParseError, 'array2csv(): Requires an Array')
    end

    sorted_array = array.sort
    result = ''

    sorted_array.each {|value|
      result += "#{value},"
    }

    return result.chop!
    
  end
end
#
# Converts the hash to a csv string
#
# $hash = {
#   HOME   => '/home/user',
#   ENV1   => 'env1',
#   SECRET => 'secret'	
# }
#
# becomes:
#
# $string = "HOME='/home/user',ENV1='env1',SECRET='secret'"
#
module Puppet::Parser::Functions
  newfunction(:hash2csv, :type => :rvalue, :doc => <<-'EOS'
    Returns a csv formatted string from an hash in the form
    KEY=VALUE,KEY2=VALUE2,KEY3=VALUE3 ordered by key
    EOS
  ) do |args|

    raise(Puppet::ParseError, "hash2csv(): Wrong number of arguments " +
      "given (#{args.size} of 1)") if args.size < 1

    hash = args[0]

    unless hash.is_a?(Hash)
      raise(Puppet::ParseError, 'hash2csv(): Requires an Hash')
    end

    sorted_hash = hash.sort
    result = ''

    sorted_hash.each {|key, value|
      result += "#{key}='#{value}',"
    }

    return result.chop!

  end
end
# Class: supervisord::config
#
# Configuration class for supervisor init and conf directories
#
class supervisord::config inherits supervisord {

  file { $supervisord::config_include:
    ensure => directory,
    owner  => 'root',
    mode   => '0755'
  }

  file { $supervisord::log_path:
    ensure => directory,
    owner  => 'root',
    mode   => '0755'
  }

  if $supervisord::run_path != '/var/run' {
    file { $supervisord::run_path:
      ensure => directory,
      owner  => 'root',
      mode   => '0755'
    }
  }

  if $supervisord::install_init {
    file { '/etc/init.d/supervisord':
      ensure  => present,
      owner   => 'root',
      mode    => '0755',
      content => template("supervisord/init/${::osfamily}/init.erb")
    }

    if $supervisord::init_defaults {
      file { $supervisord::init_defaults:
        ensure  => present,
        owner   => 'root',
        mode    => '0755',
        content => template("supervisord/init/${::osfamily}/defaults.erb")
      }
    }
  }

  concat { $supervisord::config_file:
    owner => 'root',
    group => '0',
    mode  => '0755'
  }

  if $supervisord::unix_socket {
    concat::fragment { 'supervisord_unix':
      target  => $supervisord::config_file,
      content => template('supervisord/supervisord_unix.erb'),
      order   => 01
    }
  }

  if $supervisord::inet_server {
    concat::fragment { 'supervisord_inet':
      target  => $supervisord::config_file,
      content => template('supervisord/supervisord_inet.erb'),
      order   => 01
    }
  }

  concat::fragment { 'supervisord_main':
    target  => $supervisord::config_file,
    content => template('supervisord/supervisord_main.erb'),
    order   => 02
  }
}
# Define: supervisord::eventlistener
#
# This define creates an eventlistener configuration file
#
# Documentation on parameters available at:
# http://supervisord.org/configuration.html#eventlistener-x-section-settings
#
define supervisord::eventlistener(
  $command,
  $ensure                  = present,
  $ensure_process          = 'running',
  $buffer_size             = 10,
  $events                  = undef,
  $result_handler          = undef,
  $env_var                 = undef,
  $process_name            = undef,
  $numprocs                = undef,
  $numprocs_start          = undef,
  $priority                = undef,
  $autostart               = undef,
  $autorestart             = undef,
  $startsecs               = undef,
  $startretries            = undef,
  $exitcodes               = undef,
  $stopsignal              = undef,
  $stopwaitsecs            = undef,
  $stopasgroup             = undef,
  $killasgroup             = undef,
  $user                    = undef,
  $redirect_stderr         = undef,
  $stdout_logfile          = "eventlistener_${name}.log",
  $stdout_logfile_maxbytes = undef,
  $stdout_logfile_backups  = undef,
  $stdout_events_enabled   = undef,
  $stderr_logfile          = "eventlistener_${name}.error",
  $stderr_logfile_maxbytes = undef,
  $stderr_logfile_backups  = undef,
  $stderr_events_enabled   = undef,
  $environment             = undef,
  $directory               = undef,
  $umask                   = undef,
  $serverurl               = undef
) {

  include supervisord

  # parameter validation
  validate_string($command)
  validate_re($ensure_process, ['running', 'stopped', 'removed'])
  validate_re($buffer_size, '^\d+')
  if $events { validate_array($events) }
  if $result_handler { validate_string($result_handler) }
  if $numprocs { validate_re($numprocs, '^\d+')}
  if $numprocs_start { validate_re($numprocs_start, '^\d+')}
  if $priority { validate_re($priority, '^\d+') }
  if $autostart { validate_bool($autostart) }
  if $autorestart { validate_re($autorestart, ['true', 'false', 'unexpected']) }
  if $startsecs { validate_re($startsecs, '^\d+')}
  if $startretries { validate_re($startretries, '^\d+')}
  if $exitcodes { validate_string($exitcodes)}
  if $stopsignal { validate_re($stopsignal, ['TERM', 'HUP', 'INT', 'QUIT', 'KILL', 'USR1', 'USR2']) }
  if $stopwaitsecs { validate_re($stopwaitsecs, '^\d+')}
  if $stopasgroup { validate_bool($stopasgroup) }
  if $killasgroup { validate_bool($killasgroup) }
  if $user { validate_string($user) }
  if $redirect_stderr { validate_bool($redirect_stderr) }
  validate_string($stdout_logfile)
  if $stdout_logfile_maxbytes { validate_string($stdout_logfile_maxbytes) }
  if $stdout_logfile_backups { validate_re($stdout_logfile_backups, '^\d+')}
  if $stdout_events_enabled { validate_bool($stdout_events_enabled) }
  validate_string($stderr_logfile)
  if $stderr_logfile_maxbytes { validate_string($stderr_logfile_maxbytes) }
  if $stderr_logfile_backups { validate_re($stderr_logfile_backups, '^\d+')}
  if $stderr_events_enabled { validate_bool($stderr_events_enabled) }
  if $directory { validate_absolute_path($directory) }
  if $umask { validate_re($umask, '^[0-7][0-7][0-7]$') }

  # convert environment data into a csv
  if $env_var {
    $env_hash = hiera_hash($env_var)
    validate_hash($env_hash)
    $env_string = hash2csv($env_hash)
  }
  elsif $environment {
    validate_hash($environment)
    $env_string = hash2csv($environment)
  }

  if $events {
    $events_string = array2csv($events)
  }

  $conf = "${supervisord::config_include}/eventlistener_${name}.conf"

  file { $conf:
    ensure  => $ensure,
    owner   => 'root',
    mode    => '0755',
    content => template('supervisord/conf/eventlistener.erb'),
    notify  => Class['supervisord::reload']
  }

  case $ensure_process {
    'stopped': {
      supervisord::supervisorctl { "stop_${name}":
        command => 'stop',
        process => $name
      }
    }
    'removed': {
      supervisord::supervisorctl { "remove_${name}":
        command => 'remove',
        process => $name
      }
    }
    default: { }
  }
}
# Define: supervisord::fcgi_program
#
# This define creates an eventlistener configuration file
#
# Documentation on parameters available at:
# http://supervisord.org/configuration.html#fcgi-program-x-section-settings
#
define supervisord::fcgi_program(
  $command,
  $socket,
  $ensure                  = present,
  $ensure_process          = 'running',
  $socket_owner            = undef,
  $socket_mode             = undef,
  $env_var                 = undef,
  $process_name            = undef,
  $numprocs                = undef,
  $numprocs_start          = undef,
  $priority                = undef,
  $autostart               = undef,
  $autorestart             = undef,
  $startsecs               = undef,
  $startretries            = undef,
  $exitcodes               = undef,
  $stopsignal              = undef,
  $stopwaitsecs            = undef,
  $stopasgroup             = undef,
  $killasgroup             = undef,
  $user                    = undef,
  $redirect_stderr         = undef,
  $stdout_logfile          = "fcgi-program_${name}.log",
  $stdout_logfile_maxbytes = undef,
  $stdout_logfile_backups  = undef,
  $stdout_capture_maxbytes = undef,
  $stdout_events_enabled   = undef,
  $stderr_logfile          = "fcgi-program_${name}.error",
  $stderr_logfile_maxbytes = undef,
  $stderr_logfile_backups  = undef,
  $stderr_capture_maxbytes = undef,
  $stderr_events_enabled   = undef,
  $environment             = undef,
  $directory               = undef,
  $umask                   = undef,
  $serverurl               = undef
) {

  include supervisord

  # parameter validation
  validate_string($command)
  validate_re($ensure_process, ['running', 'stopped', 'removed'])
  validate_re($socket, ['^tcp:\/\/.*:\d+$', '^unix:\/\/\/'])
  if $process_name { validate_string($process_name) }
  if $numprocs { validate_re($numprocs, '^\d+')}
  if $numprocs_start { validate_re($numprocs_start, '^\d+')}
  if $priority { validate_re($priority, '^\d+') }
  if $autostart { validate_bool($autostart) }
  if $autorestart { validate_re($autorestart, ['true', 'false', 'unexpected']) }
  if $startsecs { validate_re($startsecs, '^\d+')}
  if $startretries { validate_re($startretries, '^\d+')}
  if $exitcodes { validate_string($exitcodes)}
  if $stopsignal { validate_re($stopsignal, ['TERM', 'HUP', 'INT', 'QUIT', 'KILL', 'USR1', 'USR2']) }
  if $stopwaitsecs { validate_re($stopwaitsecs, '^\d+')}
  if $stopasgroup { validate_bool($stopasgroup) }
  if $killasgroup { validate_bool($killasgroup) }
  if $user { validate_string($user) }
  if $redirect_stderr { validate_bool($redirect_stderr) }
  validate_string($stdout_logfile)
  if $stdout_logfile_maxbytes { validate_string($stdout_logfile_maxbytes) }
  if $stdout_logfile_backups { validate_re($stdout_logfile_backups, '^\d+')}
  if $stdout_capture_maxbytes { validate_string($stdout_capture_maxbytes) }
  if $stdout_events_enabled { validate_bool($stdout_events_enabled) }
  validate_string($stderr_logfile)
  if $stderr_logfile_maxbytes { validate_string($stderr_logfile_maxbytes) }
  if $stderr_logfile_backups { validate_re($stderr_logfile_backups, '^\d+')}
  if $stderr_capture_maxbytes { validate_string($stderr_capture_maxbytes) }
  if $stderr_events_enabled { validate_bool($stderr_events_enabled) }
  if $directory { validate_absolute_path($directory) }
  if $umask { validate_re($umask, '^[0-7][0-7][0-7]$') }

  # convert environment data into a csv
  if $env_var {
    $env_hash = hiera_hash($env_var)
    validate_hash($env_hash)
    $env_string = hash2csv($env_hash)
  }
  elsif $environment {
    validate_hash($environment)
    $env_string = hash2csv($environment)
  }

  $conf = "${supervisord::config_include}/fcgi-program_${name}.conf"

  file { $conf:
    ensure  => $ensure,
    owner   => 'root',
    mode    => '0755',
    content => template('supervisord/conf/fcgi_program.erb'),
    notify  => Class['supervisord::reload']
  }

  case $ensure_process {
    'stopped': {
      supervisord::supervisorctl { "stop_${name}":
        command => 'stop',
        process => $name
      }
    }
    'removed': {
      supervisord::supervisorctl { "remove_${name}":
        command => 'remove',
        process => $name
      }
    }
    default: { }
  }
}
# Define: supervisord::group
#
# This define creates an group configuration file
#
# Documentation on parameters available at:
# http://supervisord.org/configuration.html#group-x-section-settings
#
define supervisord::group (
  $programs,
  $ensure   = present,
  $priority = undef
) {

  include supervisord

  # parameter validation
  validate_array($programs)
  if $priority { validate_re($priority, '^\d+', "invalid priority value of: ${priority}") }

  $progstring = array2csv($programs)
  $conf = "${supervisord::config_include}/group_${name}.conf"

  file { $conf:
    ensure  => $ensure,
    owner   => 'root',
    mode    => '0755',
    content => template('supervisord/conf/group.erb'),
    notify  => Class['supervisord::reload']
  }
}
# Class: supervisord
#
# This class installs supervisord via pip
#
class supervisord(
  $package_ensure       = $supervisord::params::package_ensure,
  $package_name         = $supervisord::params::package_name,
  $package_provider     = $supervisord::params::package_provider,
  $service_ensure       = $supervisord::params::service_ensure,
  $service_name         = $supervisord::params::service_name,
  $install_init         = $supervisord::params::install_init,
  $install_pip          = false,
  $init_defaults        = $supervisord::params::init_defaults,
  $setuptools_url       = $supervisord::params::setuptools_url,
  $executable_path      = $supervisord::params::executable_path,
  $executable           = $supervisord::params::executable,
  $executable_ctl       = $supervisord::params::executable_ctl,

  $log_path             = $supervisord::params::log_path,
  $log_file             = $supervisord::params::log_file,
  $log_level            = $supervisord::params::log_level,
  $logfile_maxbytes     = $supervisord::params::logfile_maxbytes,
  $logfile_backups      = $supervisord::params::logfile_backups,

  $run_path             = $supervisord::params::run_path,
  $pid_file             = $supervisord::params::pid_file,
  $nodaemon             = $supervisord::params::nodaemon,
  $minfds               = $supervisord::params::minfds,
  $minprocs             = $supervisord::params::minprocs,
  $config_include       = $supervisord::params::config_include,
  $config_file          = $supervisord::params::config_file,
  $config_dirs          = undef,
  $umask                = $supervisord::params::umask,

  $unix_socket          = $supervisord::params::unix_socket,
  $unix_socket_file     = $supervisord::params::unix_socket_file,
  $unix_socket_mode     = $supervisord::params::unix_socket_mode,
  $unix_socket_owner    = $supervisord::params::unix_socket_owner,
  $unix_socket_group    = $supervisord::params::unix_socket_group,

  $inet_server          = $supervisord::params::inet_server,
  $inet_server_hostname = $supervisord::params::inet_server_hostname,
  $inet_server_port     = $supervisord::params::inet_server_port,

  $unix_auth            = false,
  $unix_username        = undef,
  $unix_password        = undef,

  $inet_auth            = false,
  $inet_username        = undef,
  $inet_password        = undef,

  $user                 = undef,
  $identifier           = undef,
  $childlogdir          = undef,
  $environment          = undef,
  $env_var              = undef,
  $directory            = undef,
  $strip_ansi           = false,
  $nocleanup            = false,

  $eventlisteners       = {},
  $fcgi_programs        = {},
  $groups               = {},
  $programs             = {}

) inherits supervisord::params {

  validate_bool($install_pip)
  validate_bool($install_init)
  validate_bool($nodaemon)
  validate_bool($unix_auth)
  validate_bool($inet_auth)
  validate_bool($strip_ansi)
  validate_bool($nocleanup)

  validate_hash($eventlisteners)
  validate_hash($fcgi_programs)
  validate_hash($groups)
  validate_hash($programs)

  validate_absolute_path($config_include)
  validate_absolute_path($log_path)
  validate_absolute_path($run_path)
  if $childlogdir { validate_absolute_path($childlogdir) }
  if $directory { validate_absolute_path($directory) }

  $log_levels = ['^critical$', '^error$', '^warn$', '^info$', '^debug$', '^trace$', '^blather$']
  validate_re($log_level, $log_levels, "invalid log_level: ${log_level}")
  validate_re($umask, '^0[0-7][0-7]$', "invalid umask: ${umask}.")
  validate_re($unix_socket_mode, '^[0-7][0-7][0-7][0-7]$', "invalid unix_socket_mode: ${unix_socket_mode}")

  if ! is_integer($logfile_backups) { fail("invalid logfile_backups: ${logfile_backups}.")}
  if ! is_integer($minfds) { fail("invalid minfds: ${minfds}.")}
  if ! is_integer($minprocs) { fail("invalid minprocs: ${minprocs}.")}
  if ! is_integer($inet_server_port) { fail("invalid inet_server_port: ${inet_server_port}.")}

  if $env_var {
    validate_hash($env_var)
    $env_hash = hiera($env_var)
    $env_string = hash2csv($env_hash)
  }
  elsif $environment {
    validate_hash($environment)
    $env_string = hash2csv($environment)
  }

  if $config_dirs {
    validate_array($config_dirs)
    $config_include_string = join($config_dirs, " ")
  }
  else {
    $config_include_string = "${config_include}/*.conf"
  }

  create_resources('supervisord::eventlistener', $eventlisteners)
  create_resources('supervisord::fcgi_program', $fcgi_programs)
  create_resources('supervisord::group', $groups)
  create_resources('supervisord::program', $programs)

  if $install_pip {
    include supervisord::pip
    Class['supervisord::pip'] -> Class['supervisord::install']
  }

  include supervisord::install, supervisord::config, supervisord::service, supervisord::reload

  Class['supervisord::install'] -> Class['supervisord::config'] ~> Class['supervisord::service']
  Class['supervisord::reload'] -> Supervisord::Supervisorctl <| |>
}
# Class supervisord::install
#
# Installs supervisor package (defaults to using pip)
#
class supervisord::install inherits supervisord {
  package { $supervisord::package_name:
    ensure   => $supervisord::package_ensure,
    provider => $supervisord::package_provider
  }
}
# Class: supervisord::params
#
# Default parameters for supervisord
#
class supervisord::params {
  case $::osfamily {
    'RedHat': {
      $init_defaults     = '/etc/sysconfig/supervisord'
      $unix_socket_group = 'nobody'
      $install_init      = true
      $executable_path   = '/usr/bin'
    }
    'Debian': {
      $init_defaults     = '/etc/default/supervisor'
      $unix_socket_group = 'nogroup'
      $install_init      = true
      $executable_path   = '/usr/local/bin'
    }
    default:  {
      $init_defaults     = false
      $unix_socket_group = 'nogroup'
      $install_init      = false
      $executable_path   = '/usr/local/bin'
    }
  }

  # default supervisord params
  $package_ensure       = 'installed'
  $package_provider     = 'pip'
  $service_ensure       = 'running'
  $service_name         = 'supervisord'
  $package_name         = 'supervisor'
  $executable           = "${$executable_path}/supervisord"
  $executable_ctl       = "${executable_path}/supervisorctl"

  $run_path             = '/var/run'
  $pid_file             = 'supervisord.pid'
  $log_path             = '/var/log/supervisor'
  $log_file             = 'supervisord.log'
  $logfile_maxbytes     = '50MB'
  $logfile_backups      = '10'
  $log_level            = 'info'
  $nodaemon             = false
  $minfds               = '1024'
  $minprocs             = '200'
  $umask                = '022'
  $config_include       = '/etc/supervisor.d'
  $config_file          = '/etc/supervisord.conf'
  $setuptools_url       = 'https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py'

  $unix_socket          = true
  $unix_socket_file     = 'supervisor.sock'
  $unix_socket_mode     = '0700'
  $unix_socket_owner    = 'nobody'

  $inet_server          = false
  $inet_server_hostname = '127.0.0.1'
  $inet_server_port     = '9001'
  $inet_auth            = false
}
# Class: supervisord::pip
#
# Optional class to install setuptool and pip
#
class supervisord::pip inherits supervisord {

  Exec {
    path => '/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin'
  }

  exec { 'install_setuptools':
    command => "curl ${supervisord::setuptools_url} | python",
    cwd     => '/tmp',
    unless  => 'which easy_install',
    before  => Exec['install_pip']
  }

  exec { 'install_pip':
    command     => 'easy_install pip',
    unless      => 'which pip'
  }

  if $::osfamily == 'RedHat' {
    exec { 'pip_provider_name_fix':
      command     => 'alternatives --install /usr/bin/pip-python pip-python /usr/bin/pip 1',
      subscribe   => Exec['install_pip'],
      unless      => 'which pip-python'
    }
  }
}
# Define: supervisord::program
#
# This define creates an program configuration file
#
# Documentation on parameters available at:
# http://supervisord.org/configuration.html#program-x-section-settings
#
define supervisord::program(
  $command,
  $ensure                  = present,
  $ensure_process          = 'running',
  $env_var                 = undef,
  $process_name            = undef,
  $numprocs                = undef,
  $numprocs_start          = undef,
  $priority                = undef,
  $autostart               = undef,
  $autorestart             = undef,
  $startsecs               = undef,
  $startretries            = undef,
  $exitcodes               = undef,
  $stopsignal              = undef,
  $stopwaitsecs            = undef,
  $stopasgroup             = undef,
  $killasgroup             = undef,
  $user                    = undef,
  $redirect_stderr         = undef,
  $stdout_logfile          = "program_${name}.log",
  $stdout_logfile_maxbytes = undef,
  $stdout_logfile_backups  = undef,
  $stdout_capture_maxbytes = undef,
  $stdout_events_enabled   = undef,
  $stderr_logfile          = "program_${name}.error",
  $stderr_logfile_maxbytes = undef,
  $stderr_logfile_backups  = undef,
  $stderr_capture_maxbytes = undef,
  $stderr_events_enabled   = undef,
  $environment             = undef,
  $directory               = undef,
  $umask                   = undef,
  $serverurl               = undef
) {

  include supervisord

  # parameter validation
  validate_string($command)
  validate_re($ensure_process, ['running', 'stopped', 'removed'])
  if $process_name { validate_string($process_name) }
  if $numprocs { validate_re($numprocs, '^\d+')}
  if $numprocs_start { validate_re($numprocs_start, '^\d+')}
  if $priority { validate_re($priority, '^\d+') }
  if $autostart { validate_bool($autostart) }
  if $autorestart { validate_re($autorestart, ['true', 'false', 'unexpected']) }
  if $startsecs { validate_re($startsecs, '^\d+')}
  if $startretries { validate_re($startretries, '^\d+')}
  if $exitcodes { validate_string($exitcodes)}
  if $stopsignal { validate_re($stopsignal, ['TERM', 'HUP', 'INT', 'QUIT', 'KILL', 'USR1', 'USR2']) }
  if $stopwaitsecs { validate_re($stopwaitsecs, '^\d+')}
  if $stopasgroup { validate_bool($stopasgroup) }
  if $killasgroup { validate_bool($killasgroup) }
  if $user { validate_string($user) }
  if $redirect_stderr { validate_bool($redirect_stderr) }
  validate_string($stdout_logfile)
  if $stdout_logfile_maxbytes { validate_string($stdout_logfile_maxbytes) }
  if $stdout_logfile_backups { validate_re($stdout_logfile_backups, '^\d+')}
  if $stdout_capture_maxbytes { validate_string($stdout_capture_maxbytes) }
  if $stdout_events_enabled { validate_bool($stdout_events_enabled) }
  validate_string($stderr_logfile)
  if $stderr_logfile_maxbytes { validate_string($stderr_logfile_maxbytes) }
  if $stderr_logfile_backups { validate_re($stderr_logfile_backups, '^\d+')}
  if $stderr_capture_maxbytes { validate_string($stderr_capture_maxbytes) }
  if $stderr_events_enabled { validate_bool($stderr_events_enabled) }
  if $directory { validate_absolute_path($directory) }
  if $umask { validate_re($umask, '^[0-7][0-7][0-7]$') }

  # convert environment data into a csv
  if $env_var {
    $env_hash = hiera_hash($env_var)
    validate_hash($env_hash)
    $env_string = hash2csv($env_hash)
  }
  elsif $environment {
    validate_hash($environment)
    $env_string = hash2csv($environment)
  }

  $conf = "${supervisord::config_include}/program_${name}.conf"

  file { $conf:
    ensure  => $ensure,
    owner   => 'root',
    mode    => '0755',
    content => template('supervisord/conf/program.erb'),
    notify  => Class['supervisord::reload']
  }

  case $ensure_process {
    'stopped': {
      supervisord::supervisorctl { "stop_${name}":
        command => 'stop',
        process => $name
      }
    }
    'removed': {
      supervisord::supervisorctl { "remove_${name}":
        command => 'remove',
        process => $name
      }
    }
    default: { }
  }
}
# Class: supervisord::reload
#
# Class to reread and update supervisord with supervisorctl
#
class supervisord::reload inherits supervisord {

  $supervisorctl = $::supervisord::executable_ctl

  exec { 'supervisorctl_reread':
    command     => "${supervisorctl} reread",
    refreshonly => true,
    require     => Service[$supervisord::service_name],
  }
  exec { 'supervisorctl_update':
    command     => "${supervisorctl} update",
    refreshonly => true,
    require     => Service[$supervisord::service_name],
  }
}
# Class: supervisord::service
#
# Class for the supervisord service
#
class supervisord::service inherits supervisord  {
  service { $supervisord::service_name:
    ensure     => $supervisord::service_ensure,
    enable     => true,
    hasrestart => true,
    hasstatus  => true
  }
}
# Define: supervisord:supervisorctl
#
# This define executes command with the supervisorctl tool
#
define supervisord::supervisorctl(
  $command,
  $process       = undef,
  $refreshonly   = false
) {

  validate_string($command)
  validate_string($process)

  $supervisorctl = $::supervisord::executable_ctl

  if $process {
    $cmd = join([$supervisorctl, $command, $process], ' ')
  }
  else {
    $cmd = join([$supervisorctl, $command])
  }

  exec { "supervisorctl_command_${name}":
    command     => $cmd,
    refreshonly => $refreshonly
  }
}
HOSTS:
  centos-65-i386:
    roles:
      - master
    platform: el-6-i386
    box : centos-65-i386-virtualbox-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-65-i386-virtualbox-nocm.box
    hypervisor : vagrant
CONFIG:
  type: foss
HOSTS:
  centos-65-x64:
    roles:
      - master
    platform: el-6-x86_64
    box : centos-65-x64-virtualbox-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-65-x64-virtualbox-nocm.box
    hypervisor : vagrant
CONFIG:
  type: foss
HOSTS:
  debian-73-i386:
    roles:
      - master
    platform: debian-7-i386
    box : debian-73-i386-virtualbox-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/debian-73-i386-virtualbox-nocm.box
    hypervisor : vagrant
CONFIG:
  type: foss
HOSTS:
  debian-73-x64:
    roles:
      - master
    platform: debian-7-amd64
    box : debian-73-x64-virtualbox-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/debian-73-x64-virtualbox-nocm.box
    hypervisor : vagrant
CONFIG:
  type: foss
HOSTS:
  debian-73-x64:
    roles:
      - master
    platform: debian-7-amd64
    box : debian-73-x64-virtualbox-nocm
    box_url : http://puppet-vagrant-boxes.puppetlabs.com/debian-73-x64-virtualbox-nocm.box
    hypervisor : vagrant
CONFIG:
  type: foss
require 'spec_helper_acceptance'

describe 'supervisord install' do

  context 'default parameters with pip and init install' do
    it 'should work with no errors' do
      pp = <<-EOS
        class { 'supervisord': install_pip  => true, install_init => true}
      EOS

      expect(apply_manifest(pp).exit_code).to_not eq(1)
      expect(apply_manifest(pp).exit_code).to eq(0)
    end

    describe service('supervisord') do
      it { should be_enabled }
      it { should be_running }
      it 'should restart successfully' do
        cmd="service supervisord restart"
        expect(shell(cmd).exit_code).to_not eq(1)
      end
    end
  end
end

describe 'supervisord::program' do
  context 'create a program config' do
    it 'should install a program file' do

      pp = <<-EOS
        include supervisord
        supervisord::program { 'test': 
          command => 'echo', 
          priority => '100', 
          environment => { 
            'HOME' => '/root',
            'PATH' => '/bin',
          }
        }
      EOS

      expect(apply_manifest(pp).exit_code).to_not eq(1)
      expect(apply_manifest(pp).exit_code).to eq(0)
    end

    it 'should contain the correct values' do
      cmd='grep command=echo /etc/supervisor.d/program_test.conf'
      expect(shell(cmd).exit_code).to eq(0)
      cmd='grep priority=100 /etc/supervisor.d/program_test.conf'
      expect(shell(cmd).exit_code).to eq(0)
      cmd='grep "environment=" /etc/supervisor.d/program_test.conf'
      expect(shell(cmd).exit_code).to eq(0)
    end
  end
end 

describe 'supervisord::fcgi-program' do
  context 'create fcgi-program config' do
    it 'should install a fcgi-program file' do

      pp = <<-EOS
        include supervisord
        supervisord::fcgi_program { 'test':
          socket  => 'tcp://localhost:1000',
          command => 'echo',
          priority => '100',
          environment => {
            'HOME' => '/root',
            'PATH' => '/bin',
          }
        }
      EOS

      expect(apply_manifest(pp).exit_code).to_not eq(1)
      expect(apply_manifest(pp).exit_code).to eq(0)
    end

    it 'should contain the correct values' do
      cmd='grep socket=tcp://localhost:1000 /etc/supervisor.d/fcgi-program_test.conf'
      expect(shell(cmd).exit_code).to eq(0)
      cmd="grep command=echo /etc/supervisor.d/fcgi-program_test.conf"
      expect(shell(cmd).exit_code).to eq(0)
      cmd="grep priority=100 /etc/supervisor.d/fcgi-program_test.conf"
      expect(shell(cmd).exit_code).to eq(0)
      cmd='grep "environment=" /etc/supervisor.d/fcgi-program_test.conf'
      expect(shell(cmd).exit_code).to eq(0)
    end
  end
end

describe 'supervisord::group' do
  context 'create group config' do
    it 'should install a group config' do

      pp = <<-EOS
        include supervisord
        supervisord::group { 'test':
          programs => ['test'],
          priority => '100',
        }
      EOS

      expect(apply_manifest(pp).exit_code).to_not eq(1)
      expect(apply_manifest(pp).exit_code).to eq(0)
    end

    it 'should contain the correct values' do
      cmd='grep "programs=test" /etc/supervisor.d/group_test.conf'
      expect(shell(cmd).exit_code).to eq(0)
      cmd="grep priority=100 /etc/supervisor.d/group_test.conf"
      expect(shell(cmd).exit_code).to eq(0)
    end
  end
end
require 'spec_helper'

describe 'supervisord' do

  concatdir = '/var/lib/puppet/concat'
  let(:facts) {{ :concat_basedir => concatdir }}

  it { should contain_class('supervisord') }
  it { should contain_class('supervisord::install') }
  it { should contain_class('supervisord::config') }
  it { should contain_class('supervisord::service') }
  it { should contain_class('supervisord::params') }
  it { should contain_class('supervisord::reload') }
  it { should contain_package('supervisor') }

  describe '#service_name' do
    context 'default' do
      it { should contain_service('supervisord') }
    end

    context 'specified' do
      let(:params) {{ :service_name => 'myservicename' }}
      it { should contain_service('myservicename') }
    end
  end

  describe '#install_pip' do
    context 'default' do
      it { should_not contain_class('supervisord::pip') }
    end

    context 'true' do
      let(:params) {{ :install_pip => true }}
      it { should contain_class('supervisord::pip') }
      it { should contain_exec('install_setuptools') }
      it { should contain_exec('install_pip') }
    end

    context 'true and RedHat' do
      let(:params) {{ :install_pip => true }}
      let(:facts) {{ :osfamily => 'RedHat', :concat_basedir => concatdir }}
      it { should contain_exec('pip_provider_name_fix') }
    end
  end

  describe '#env_var' do
    context 'default' do
      it { should contain_class('supervisord').without_env_hash }
      it { should contain_class('supervisord').without_env_string }
    end
  end

  describe '#environment' do
    context 'default' do
      it { should contain_class('supervisord').without_env_string }
    end
    context 'is specified' do
      let(:params) {{ :environment => { 'key1' => 'value1', 'key2' => 'value2' } }}
      it { should contain_concat__fragment('supervisord_main')\
        .with_content(/environment=key1='value1',key2='value2'/) }
    end
  end

  describe '#install_init' do
    context 'default' do
      it { should_not contain_file('/etc/init.d/supervisord') }
    end

    context 'false' do 
      it { should_not contain_file('/etc/init.d/supervisord') }
    end

    describe 'on supported OS' do
      context 'with Debian' do
        let(:facts) {{ :osfamily => 'Debian', :concat_basedir => concatdir }}
        it { should contain_file('/etc/init.d/supervisord') }
        it { should contain_file('/etc/default/supervisor') }
      end

      context 'with RedHat' do
        let(:facts) {{ :osfamily => 'RedHat', :concat_basedir => concatdir }}
        it { should contain_file('/etc/init.d/supervisord') }
        it { should contain_file('/etc/sysconfig/supervisord') }
      end
    end
  end
      
  describe '#unix_socket' do
    context 'default' do
      it { should contain_concat__fragment('supervisord_unix')}
    end
    context 'false' do
      let(:params) {{ :unix_socket => false }}
      it { should_not contain_concat__fragment('supervisord_unix')}
    end
  end

  describe '#inet_server' do
    context 'default' do
      it { should_not contain_concat__fragment('supervisord_inet')}
    end
    context 'true' do
      let(:params) {{ :inet_server => true }}
      it { should contain_concat__fragment('supervisord_inet')}
    end
  end

  describe '#run_path' do
    context 'default' do
      it { should_not contain_file('/var/run') }
      it { should contain_concat__fragment('supervisord_main') \
        .with_content(/pidfile=\/var\/run\/supervisord.pid$/) }
    end
    context 'is specified' do
      let(:params) {{ :run_path => '/opt/supervisord/run' }}
      it { should contain_file('/opt/supervisord/run') }
      it { should contain_concat__fragment('supervisord_main') \
        .with_content(/pidfile=\/opt\/supervisord\/run\/supervisord.pid$/) }
    end
  end

  describe '#log_path' do
    context 'default' do
      it { should contain_file('/var/log/supervisor') }
      it { should contain_concat__fragment('supervisord_main') \
        .with_content(/logfile=\/var\/log\/supervisor\/supervisord.log$/) }
    end
    context 'is specified' do
      let(:params) {{ :log_path => '/opt/supervisord/logs' }}
      it { should contain_file('/opt/supervisord/logs')}
      it { should contain_concat__fragment('supervisord_main') \
        .with_content(/logfile=\/opt\/supervisord\/logs\/supervisord.log$/) }
    end
  end

  describe '#config_include' do
    context 'default' do
      it { should contain_file('/etc/supervisor.d') }
      it { should contain_concat__fragment('supervisord_main') \
        .with_content(/files=\/etc\/supervisor.d\/\*.conf$/) }
    end
    context 'is specified' do
      let(:params) {{ :config_include => '/opt/supervisord/conf.d' }}
      it { should contain_file('/opt/supervisord/conf.d') }
      it { should contain_concat__fragment('supervisord_main') \
        .with_content(/files=\/opt\/supervisord\/conf.d\/\*.conf$/) }
    end
  end

  describe '#config_dirs' do
    context 'is specified' do
      let(:params) {{ :config_dirs => ['/etc/supervisor.d/*.conf', '/opt/supervisor.d/*', '/usr/share/supervisor.d/*.config'] }}
      it { should contain_concat__fragment('supervisord_main') \
        .with_content(/files=\/etc\/supervisor.d\/\*.conf \/opt\/supervisor.d\/\* \/usr\/share\/supervisor.d\/\*.config$/) }
    end
  end

  describe '#config_file' do
    context 'default' do
      it { should contain_file('/etc/supervisord.conf') }
    end
    context 'is specified' do
      let(:params) {{ :config_file => '/opt/supervisord/supervisor.conf' }}
      it { should contain_file('/opt/supervisord/supervisor.conf') }
    end
  end

  describe '#nodaemon' do
    context 'default' do
      it { should contain_concat__fragment('supervisord_main') \
        .with_content(/nodaemon=false$/) }
    end
    context 'true' do
      let(:params) {{ :nodaemon => true }}
      it { should contain_concat__fragment('supervisord_main') \
        .with_content(/nodaemon=true$/) }
    end
    context 'invalid' do
      let(:params) {{ :nodaemon => 'invalid' }}
      it { expect { raise_error(Puppet::Error, /is not a boolean/) }}
    end
  end

  describe '#minfds' do
    context 'default' do
      it { should contain_concat__fragment('supervisord_main') \
        .with_content(/minfds=1024$/) }
    end
    context 'specified' do
      let(:params) {{ :minfds => 2048 }}
      it { should contain_concat__fragment('supervisord_main') \
        .with_content(/minfds=2048$/) }
    end
    context 'invalid' do
      let(:params) {{ :minfds => 'string' }}
      it { expect { raise_error(Puppet::Error, /invalid minfds/) }}
    end
  end

  describe '#minprocs' do
    context 'default' do
      it { should contain_concat__fragment('supervisord_main') \
        .with_content(/minprocs=200$/) }
    end
    context 'specified' do
      let(:params) {{ :minprocs => 300 }}
      it { should contain_concat__fragment('supervisord_main') \
        .with_content(/minprocs=300$/) }
    end
    context 'invalid' do
      let(:params) {{ :minfds => 'string' }}
      it { expect { raise_error(Puppet::Error, /invalid minprocs/) }}
    end
  end

  describe '#strip_ansi' do
    context 'default' do
      it { should_not contain_concat__fragment('supervisord_main') \
        .with_content(/strip_ansi$/) }
    end
    context 'true' do
      let(:params) {{ :strip_ansi => true }}
      it { should contain_concat__fragment('supervisord_main') \
        .with_content(/strip_ansi=true$/) }
    end
    context 'invalid' do
      let(:params) {{ :strip_ansi => 'string' }}
      it { expect { raise_error(Puppet::Error, /is not a boolean/) }}
    end
  end

  describe '#user' do
    context 'default' do
      it { should_not contain_concat__fragment('supervisord_main') \
        .with_content(/user$/) }
    end
    context 'specified' do
      let(:params) {{ :user => 'myuser' }}
      it { should contain_concat__fragment('supervisord_main') \
        .with_content(/user=myuser$/) }
    end
  end

  describe '#identifier' do
    context 'default' do
      it { should_not contain_concat__fragment('supervisord_main') \
        .with_content(/identifier$/) }
    end
    context 'specified' do
      let(:params) {{ :identifier => 'myidentifier' }}
      it { should contain_concat__fragment('supervisord_main') \
        .with_content(/identifier=myidentifier$/) }
    end
  end

  describe '#directory' do
    context 'default' do
      it { should_not contain_concat__fragment('supervisord_main') \
        .with_content(/directory$/) }
    end
    context 'specified' do
      let(:params) {{ :directory => '/opt/supervisord' }}
      it { should contain_concat__fragment('supervisord_main') \
        .with_content(/directory=\/opt\/supervisord$/) }
    end
  end

  describe '#nocleanup' do
    context 'default' do
      it { should_not contain_concat__fragment('supervisord_main') \
        .with_content(/nocleanup$/) }
    end
    context 'true' do
      let(:params) {{ :nocleanup => true }}
      it { should contain_concat__fragment('supervisord_main') \
        .with_content(/nocleanup=true$/) }
    end
    context 'invalid' do
      let(:params) {{ :nocleanup => 'string' }}
      it { expect { raise_error(Puppet::Error, /is not a boolean/) }}
    end
  end

  describe '#childlogdir' do
    context 'default' do
      it { should_not contain_concat__fragment('supervisord_main') \
        .with_content(/childlogdir$/) }
    end
    context 'specified' do
      let(:params) {{ :childlogdir => '/opt/supervisord/logdir' }}
      it { should contain_concat__fragment('supervisord_main') \
        .with_content(/childlogdir=\/opt\/supervisord\/logdir$/) }
    end
    context 'invalid' do
      let(:params) {{ :childlogdir => 'not_a_path' }}
      it { expect { raise_error(Puppet::Error, /is not an absolute path/) }}
    end
  end
end
require 'spec_helper'

describe 'supervisord::eventlistener', :type => :define do
  let(:title) {'foo'}
  let(:facts) {{ :concat_basedir => '/var/lib/puppet/concat' }}
  let(:default_params) do 
    {
      :command                 => 'bar',
      :process_name            => '%(process_num)s',
      :events                  => ['PROCESS_STATE', 'PROCESS_STATE_STARTING'],
      :buffer_size             => 10,
      :numprocs                => '1',
      :numprocs_start          => '0',
      :priority                => '999',
      :autostart               => true,
      :autorestart             => 'unexpected',
      :startsecs               => '1',
      :startretries            => '3',
      :exitcodes               => '0,2',
      :stopsignal              => 'TERM',
      :stopwaitsecs            => '10',
      :stopasgroup             => true,
      :killasgroup             => true,
      :user                    => 'baz',
      :redirect_stderr         => true,
      :stdout_logfile          => 'eventlistener_foo.log',
      :stdout_logfile_maxbytes => '50MB',
      :stdout_logfile_backups  => '10',
      :stdout_events_enabled   => true,
      :stderr_logfile          => 'eventlistener_foo.error',
      :stderr_logfile_maxbytes => '50MB',
      :stderr_logfile_backups  => '10',
      :stderr_events_enabled   => true,
      :environment             => { 'env1' => 'value1', 'env2' => 'value2' },
      :directory               => '/opt/supervisord/chroot',
      :umask                   => '022',
      :serverurl               => 'AUTO'
    }
  end

  context 'default' do
    let(:params) { default_params }

    it { should contain_supervisord__eventlistener('foo') }
    it { should contain_file('/etc/supervisor.d/eventlistener_foo.conf').with_content(/\[eventlistener:foo\]/) }
    it { should contain_file('/etc/supervisor.d/eventlistener_foo.conf').with_content(/command=bar/) }
    it { should contain_file('/etc/supervisor.d/eventlistener_foo.conf').with_content(/process_name=\%\(process_num\)s/) }
    it { should contain_file('/etc/supervisor.d/eventlistener_foo.conf').with_content(/events=PROCESS_STATE,PROCESS_STATE_STARTING/) }
    it { should contain_file('/etc/supervisor.d/eventlistener_foo.conf').with_content(/buffer_size=10/) }
    it { should contain_file('/etc/supervisor.d/eventlistener_foo.conf').with_content(/numprocs=1/) }
    it { should contain_file('/etc/supervisor.d/eventlistener_foo.conf').with_content(/numprocs_start=0/) }
    it { should contain_file('/etc/supervisor.d/eventlistener_foo.conf').with_content(/priority=999/) }
    it { should contain_file('/etc/supervisor.d/eventlistener_foo.conf').with_content(/autostart=true/) }
    it { should contain_file('/etc/supervisor.d/eventlistener_foo.conf').with_content(/startsecs=1/) }
    it { should contain_file('/etc/supervisor.d/eventlistener_foo.conf').with_content(/startretries=3/) }
    it { should contain_file('/etc/supervisor.d/eventlistener_foo.conf').with_content(/exitcodes=0,2/) }
    it { should contain_file('/etc/supervisor.d/eventlistener_foo.conf').with_content(/stopsignal=TERM/) }
    it { should contain_file('/etc/supervisor.d/eventlistener_foo.conf').with_content(/stopwaitsecs=10/) }
    it { should contain_file('/etc/supervisor.d/eventlistener_foo.conf').with_content(/stopasgroup=true/) }
    it { should contain_file('/etc/supervisor.d/eventlistener_foo.conf').with_content(/killasgroup=true/) }
    it { should contain_file('/etc/supervisor.d/eventlistener_foo.conf').with_content(/user=baz/) }
    it { should contain_file('/etc/supervisor.d/eventlistener_foo.conf').with_content(/redirect_stderr=true/) }
    it { should contain_file('/etc/supervisor.d/eventlistener_foo.conf').with_content(/stdout_logfile=\/var\/log\/supervisor\/eventlistener_foo.log/) }
    it { should contain_file('/etc/supervisor.d/eventlistener_foo.conf').with_content(/stdout_logfile_maxbytes=50MB/) }
    it { should contain_file('/etc/supervisor.d/eventlistener_foo.conf').with_content(/stdout_logfile_backups=10/) }
    it { should contain_file('/etc/supervisor.d/eventlistener_foo.conf').with_content(/stdout_events_enabled=true/) }
    it { should contain_file('/etc/supervisor.d/eventlistener_foo.conf').with_content(/stderr_logfile=\/var\/log\/supervisor\/eventlistener_foo.error/) }
    it { should contain_file('/etc/supervisor.d/eventlistener_foo.conf').with_content(/stderr_logfile_maxbytes=50MB/) }
    it { should contain_file('/etc/supervisor.d/eventlistener_foo.conf').with_content(/stderr_logfile_backups=10/) }
    it { should contain_file('/etc/supervisor.d/eventlistener_foo.conf').with_content(/stderr_events_enabled=true/) }
    it { should contain_file('/etc/supervisor.d/eventlistener_foo.conf').with_content(/environment=env1='value1',env2='value2'/) }
    it { should contain_file('/etc/supervisor.d/eventlistener_foo.conf').with_content(/directory=\/opt\/supervisord\/chroot/) }
    it { should contain_file('/etc/supervisor.d/eventlistener_foo.conf').with_content(/umask=022/) }
    it { should contain_file('/etc/supervisor.d/eventlistener_foo.conf').with_content(/serverurl=AUTO/) }
  end

  context 'ensure_process_stopped' do
    let(:params) { default_params.merge({ :ensure_process => 'stopped' }) }
    it { should contain_supervisord__supervisorctl('stop_foo') }
  end

  context 'ensure_process_removed' do
    let(:params) { default_params.merge({ :ensure_process => 'removed' }) }
    it { should contain_supervisord__supervisorctl('remove_foo') }
  end
end
require 'spec_helper'

describe 'supervisord::fcgi_program', :type => :define do
  let(:title) {'foo'}
  let(:facts) {{ :concat_basedir => '/var/lib/puppet/concat' }}
  let(:default_params) do
    {
      :command                 => 'bar',
      :socket                  => 'tcp://localhost:1000',
      :process_name            => '%(process_num)s',
      :numprocs                => '1',
      :numprocs_start          => '0',
      :priority                => '999',
      :autostart               => true,
      :autorestart             => 'unexpected',
      :startsecs               => '1',
      :startretries            => '3',
      :exitcodes               => '0,2',
      :stopsignal              => 'TERM',
      :stopwaitsecs            => '10',
      :stopasgroup             => true,
      :killasgroup             => true,
      :user                    => 'baz',
      :redirect_stderr         => true,
      :stdout_logfile          => 'fcgi-program_foo.log',
      :stdout_logfile_maxbytes => '50MB',
      :stdout_logfile_backups  => '10',
      :stdout_capture_maxbytes => '0',
      :stdout_events_enabled   => true,
      :stderr_logfile          => 'fcgi-program_foo.error',
      :stderr_logfile_maxbytes => '50MB',
      :stderr_logfile_backups  => '10',
      :stderr_capture_maxbytes => '0',
      :stderr_events_enabled   => true,
      :environment             => { 'env1' => 'value1', 'env2' => 'value2' },
      :directory               => '/opt/supervisord/chroot',
      :umask                   => '022',
      :serverurl               => 'AUTO'
    }
  end

  context 'default' do
    let(:params) { default_params }

    it { should contain_supervisord__fcgi_program('foo') }
    it { should contain_file('/etc/supervisor.d/fcgi-program_foo.conf').with_content(/\[fcgi-program:foo\]/) }
    it { should contain_file('/etc/supervisor.d/fcgi-program_foo.conf').with_content(/socket=tcp:\/\/localhost:1000/) }
    it { should contain_file('/etc/supervisor.d/fcgi-program_foo.conf').with_content(/command=bar/) }
    it { should contain_file('/etc/supervisor.d/fcgi-program_foo.conf').with_content(/process_name=\%\(process_num\)s/) }
    it { should contain_file('/etc/supervisor.d/fcgi-program_foo.conf').with_content(/numprocs=1/) }
    it { should contain_file('/etc/supervisor.d/fcgi-program_foo.conf').with_content(/numprocs_start=0/) }
    it { should contain_file('/etc/supervisor.d/fcgi-program_foo.conf').with_content(/priority=999/) }
    it { should contain_file('/etc/supervisor.d/fcgi-program_foo.conf').with_content(/autostart=true/) }
    it { should contain_file('/etc/supervisor.d/fcgi-program_foo.conf').with_content(/startsecs=1/) }
    it { should contain_file('/etc/supervisor.d/fcgi-program_foo.conf').with_content(/startretries=3/) }
    it { should contain_file('/etc/supervisor.d/fcgi-program_foo.conf').with_content(/exitcodes=0,2/) }
    it { should contain_file('/etc/supervisor.d/fcgi-program_foo.conf').with_content(/stopsignal=TERM/) }
    it { should contain_file('/etc/supervisor.d/fcgi-program_foo.conf').with_content(/stopwaitsecs=10/) }
    it { should contain_file('/etc/supervisor.d/fcgi-program_foo.conf').with_content(/stopasgroup=true/) }
    it { should contain_file('/etc/supervisor.d/fcgi-program_foo.conf').with_content(/killasgroup=true/) }
    it { should contain_file('/etc/supervisor.d/fcgi-program_foo.conf').with_content(/user=baz/) }
    it { should contain_file('/etc/supervisor.d/fcgi-program_foo.conf').with_content(/redirect_stderr=true/) }
    it { should contain_file('/etc/supervisor.d/fcgi-program_foo.conf').with_content(/stdout_logfile=\/var\/log\/supervisor\/fcgi-program_foo.log/) }
    it { should contain_file('/etc/supervisor.d/fcgi-program_foo.conf').with_content(/stdout_logfile_maxbytes=50MB/) }
    it { should contain_file('/etc/supervisor.d/fcgi-program_foo.conf').with_content(/stdout_logfile_backups=10/) }
    it { should contain_file('/etc/supervisor.d/fcgi-program_foo.conf').with_content(/stdout_capture_maxbytes=0/) }
    it { should contain_file('/etc/supervisor.d/fcgi-program_foo.conf').with_content(/stdout_events_enabled=true/) }
    it { should contain_file('/etc/supervisor.d/fcgi-program_foo.conf').with_content(/stderr_logfile=\/var\/log\/supervisor\/fcgi-program_foo.error/) }
    it { should contain_file('/etc/supervisor.d/fcgi-program_foo.conf').with_content(/stderr_logfile_maxbytes=50MB/) }
    it { should contain_file('/etc/supervisor.d/fcgi-program_foo.conf').with_content(/stderr_logfile_backups=10/) }
    it { should contain_file('/etc/supervisor.d/fcgi-program_foo.conf').with_content(/stderr_capture_maxbytes=0/) }
    it { should contain_file('/etc/supervisor.d/fcgi-program_foo.conf').with_content(/stderr_events_enabled=true/) }
    it { should contain_file('/etc/supervisor.d/fcgi-program_foo.conf').with_content(/environment=env1='value1',env2='value2'/) }
    it { should contain_file('/etc/supervisor.d/fcgi-program_foo.conf').with_content(/directory=\/opt\/supervisord\/chroot/) }
    it { should contain_file('/etc/supervisor.d/fcgi-program_foo.conf').with_content(/umask=022/) }
    it { should contain_file('/etc/supervisor.d/fcgi-program_foo.conf').with_content(/serverurl=AUTO/) }
  end

  context 'ensure_process_stopped' do
    let(:params) { default_params.merge({ :ensure_process => 'stopped' }) }
    it { should contain_supervisord__supervisorctl('stop_foo') }
  end

  context 'ensure_process_removed' do
    let(:params) { default_params.merge({ :ensure_process => 'removed' }) }
    it { should contain_supervisord__supervisorctl('remove_foo') }
  end
end
require 'spec_helper'

describe 'supervisord::group', :type => :define do
  let(:title) {'foo'}
  let(:params) {{ :programs => ['bar', 'baz'] }}
  let(:facts) {{ :concat_basedir => '/var/lib/puppet/concat' }}

  it { should contain_supervisord__group('foo').with_program }
  it { should contain_file('/etc/supervisor.d/group_foo.conf').with_content(/programs=bar,baz/) }

  describe '#priority' do
    it 'should default to undef' do
      should_not contain_file('/etc/supervisor.d/group_foo.conf').with_content(/priority/)
      should contain_file('/etc/supervisor.d/group_foo.conf').with_content(/programs=bar,baz/)
    end
    context '100' do
      let(:params) {{ :priority => '100', :programs => ['bar', 'baz'] }}
      it { should contain_file('/etc/supervisor.d/group_foo.conf').with_content(/priority=100/) }
      it { should contain_file('/etc/supervisor.d/group_foo.conf').with_content(/programs=bar,baz/) }
    end
  end
end
require 'spec_helper'

describe 'supervisord::program', :type => :define do
  let(:title) {'foo'}
  let(:facts) {{ :concat_basedir => '/var/lib/puppet/concat' }}
  let(:default_params) do 
    {
      :command                 => 'bar',
      :process_name            => '%(process_num)s',
      :numprocs                => '1',
      :numprocs_start          => '0',
      :priority                => '999',
      :autostart               => true,
      :autorestart             => 'unexpected',
      :startsecs               => '1',
      :startretries            => '3',
      :exitcodes               => '0,2',
      :stopsignal              => 'TERM',
      :stopwaitsecs            => '10',
      :stopasgroup             => true,
      :killasgroup             => true,
      :user                    => 'baz',
      :redirect_stderr         => true,
      :stdout_logfile          => 'program_foo.log',
      :stdout_logfile_maxbytes => '50MB',
      :stdout_logfile_backups  => '10',
      :stdout_capture_maxbytes => '0',
      :stdout_events_enabled   => true,
      :stderr_logfile          => 'program_foo.error',
      :stderr_logfile_maxbytes => '50MB',
      :stderr_logfile_backups  => '10',
      :stderr_capture_maxbytes => '0',
      :stderr_events_enabled   => true,
      :environment             => { 'env1' => 'value1', 'env2' => 'value2' },
      :directory               => '/opt/supervisord/chroot',
      :umask                   => '022',
      :serverurl               => 'AUTO'
    }
  end

  context 'default' do
    let(:params) { default_params }

    it { should contain_supervisord__program('foo') }
    it { should contain_file('/etc/supervisor.d/program_foo.conf').with_content(/\[program:foo\]/) }
    it { should contain_file('/etc/supervisor.d/program_foo.conf').with_content(/command=bar/) }
    it { should contain_file('/etc/supervisor.d/program_foo.conf').with_content(/process_name=\%\(process_num\)s/) }
    it { should contain_file('/etc/supervisor.d/program_foo.conf').with_content(/numprocs=1/) }
    it { should contain_file('/etc/supervisor.d/program_foo.conf').with_content(/numprocs_start=0/) }
    it { should contain_file('/etc/supervisor.d/program_foo.conf').with_content(/priority=999/) }
    it { should contain_file('/etc/supervisor.d/program_foo.conf').with_content(/autostart=true/) }
    it { should contain_file('/etc/supervisor.d/program_foo.conf').with_content(/startsecs=1/) }
    it { should contain_file('/etc/supervisor.d/program_foo.conf').with_content(/startretries=3/) }
    it { should contain_file('/etc/supervisor.d/program_foo.conf').with_content(/exitcodes=0,2/) }
    it { should contain_file('/etc/supervisor.d/program_foo.conf').with_content(/stopsignal=TERM/) }
    it { should contain_file('/etc/supervisor.d/program_foo.conf').with_content(/stopwaitsecs=10/) }
    it { should contain_file('/etc/supervisor.d/program_foo.conf').with_content(/stopasgroup=true/) }
    it { should contain_file('/etc/supervisor.d/program_foo.conf').with_content(/killasgroup=true/) }
    it { should contain_file('/etc/supervisor.d/program_foo.conf').with_content(/user=baz/) }
    it { should contain_file('/etc/supervisor.d/program_foo.conf').with_content(/redirect_stderr=true/) }
    it { should contain_file('/etc/supervisor.d/program_foo.conf').with_content(/stdout_logfile=\/var\/log\/supervisor\/program_foo.log/) }
    it { should contain_file('/etc/supervisor.d/program_foo.conf').with_content(/stdout_logfile_maxbytes=50MB/) }
    it { should contain_file('/etc/supervisor.d/program_foo.conf').with_content(/stdout_logfile_backups=10/) }
    it { should contain_file('/etc/supervisor.d/program_foo.conf').with_content(/stdout_capture_maxbytes=0/) }
    it { should contain_file('/etc/supervisor.d/program_foo.conf').with_content(/stdout_events_enabled=true/) }
    it { should contain_file('/etc/supervisor.d/program_foo.conf').with_content(/stderr_logfile=\/var\/log\/supervisor\/program_foo.error/) }
    it { should contain_file('/etc/supervisor.d/program_foo.conf').with_content(/stderr_logfile_maxbytes=50MB/) }
    it { should contain_file('/etc/supervisor.d/program_foo.conf').with_content(/stderr_logfile_backups=10/) }
    it { should contain_file('/etc/supervisor.d/program_foo.conf').with_content(/stderr_capture_maxbytes=0/) }
    it { should contain_file('/etc/supervisor.d/program_foo.conf').with_content(/stderr_events_enabled=true/) }
    it { should contain_file('/etc/supervisor.d/program_foo.conf').with_content(/environment=env1='value1',env2='value2'/) }
    it { should contain_file('/etc/supervisor.d/program_foo.conf').with_content(/directory=\/opt\/supervisord\/chroot/) }
    it { should contain_file('/etc/supervisor.d/program_foo.conf').with_content(/umask=022/) }
    it { should contain_file('/etc/supervisor.d/program_foo.conf').with_content(/serverurl=AUTO/) }
  end

  context 'ensure_process_stopped' do
    let(:params) { default_params.merge({ :ensure_process => 'stopped' }) }
    it { should contain_supervisord__supervisorctl('stop_foo') }
  end

  context 'ensure_process_removed' do
    let(:params) { default_params.merge({ :ensure_process => 'removed' }) }
    it { should contain_supervisord__supervisorctl('remove_foo') }
  end
end
require 'spec_helper'

describe 'supervisord::supervisorctl', :type => :define do
  let(:title) {'command_foo'}
  let(:default_params) {{ 
    :command => 'command',
    :process => 'foo'
  }}
  let(:params) { default_params }
  let(:facts) {{ :concat_basedir => '/var/lib/puppet/concat' }}

  it { should contain_supervisord__supervisorctl('command_foo') }
end
require 'spec_helper'

describe 'array2csv' do
  it { should run.with_params(['value1']).and_return('value1') }
  it { should run.with_params(['value1', 'value2', 'value3']).and_return('value1,value2,value3') }
  it { should run.with_params('foo').and_raise_error(Puppet::ParseError) }
  it { should run.with_params().and_raise_error(Puppet::ParseError) }
end
require 'spec_helper'

describe 'hash2csv' do
  it { should run.with_params({'key1' => 'value1'}).and_return("key1='value1'") }
  it { should run.with_params({'key1' => 'value1', 'key2' => 'value2'}).and_return("key1='value1',key2='value2'") }
  it { should run.with_params('foo').and_raise_error(Puppet::ParseError) }
  it { should run.with_params().and_raise_error(Puppet::ParseError) }
end
require 'puppetlabs_spec_helper/module_spec_helper'

fixture_path = File.expand_path(File.join(__FILE__, '..', 'fixtures'))

RSpec.configure do |c|
  c.module_path = File.join(fixture_path, 'modules')
  c.manifest_dir = File.join(fixture_path, 'manifests')
end

at_exit { RSpec::Puppet::Coverage.report! }
require 'beaker-rspec'

hosts.each do |host|
  # Install Puppet
  install_puppet
end

RSpec.configure do |c|
  # Project root
  proj_root = File.expand_path(File.join(File.dirname(__FILE__), '..'))

  # Readable test descriptions
  c.formatter = :documentation

  # Configure all nodes in nodeset
  c.before :suite do
    # Install module
    puppet_module_install(:source => proj_root, :module_name => 'supervisord')
    hosts.each do |host|
      on host, puppet('module','install','puppetlabs-stdlib'), { :acceptable_exit_codes => [0,1] }
      on host, puppet('module','install','puppetlabs-concat'), { :acceptable_exit_codes => [0,1] }
    end
  end
end
[eventlistener:<%= @name %>]
command=<%= @command %>
<% if @process_name -%>
process_name=<%= @process_name %>
<% end -%>
<% if @numprocs -%>
numprocs=<%= @numprocs %>
<% end -%>
<% if @numprocs_start -%>
numprocs_start=<%= @numprocs_start %>
<% end -%>
<% if @events_string -%>
events=<%= @events_string %>
<% end -%>
<% if @buffer_size -%>
buffer_size=<%= @buffer_size %>
<% end -%>
<% if @result_handler -%>
result_handler=<%= @result_handler %>
<% end -%>
<% if @priority -%>
priority=<%= @priority %>
<% end -%>
<% if @autostart -%>
autostart=<%= @autostart %>
<% end -%>
<% if @autorestart -%>
autorestart=<%= @autorestart %>
<% end -%>
<% if @startsecs -%>
startsecs=<%= @startsecs %>
<% end -%>
<% if @startretries -%>
startretries=<%= @startretries %>
<% end -%>
<% if @exitcodes -%>
exitcodes=<%= @exitcodes %>
<% end -%>
<% if @stopsignal -%>
stopsignal=<%= @stopsignal %>
<% end -%>
<% if @stopwaitsecs -%>
stopwaitsecs=<%= @stopwaitsecs %>
<% end -%>
<% if @stopasgroup -%>
stopasgroup=<%= @stopasgroup %>
<% end -%>
<% if @killasgroup -%>
killasgroup=<%= @killasgroup %>
<% end -%>
<% if @user -%>
user=<%= @user %>
<% end -%>
<% if @redirect_stderr -%>
redirect_stderr=<%= @redirect_stderr %>
<% end -%>
stdout_logfile=<%= scope.lookupvar('supervisord::log_path') %>/<%= @stdout_logfile %>
<% if @stdout_logfile_maxbytes -%>
stdout_logfile_maxbytes=<%= @stdout_logfile_maxbytes %>
<% end -%>
<% if @stdout_logfile_backups -%>
stdout_logfile_backups=<%= @stdout_logfile_backups %>
<% end -%>
<% if @stdout_events_enabled -%>
stdout_events_enabled=<%= @stdout_events_enabled %>
<% end -%>
stderr_logfile=<%= scope.lookupvar('supervisord::log_path') %>/<%= @stderr_logfile %>
<% if @stderr_logfile_maxbytes -%>
stderr_logfile_maxbytes=<%= @stderr_logfile_maxbytes %>
<% end -%>
<% if @stderr_logfile_backups -%>
stderr_logfile_backups=<%= @stderr_logfile_backups %>
<% end -%>
<% if @stderr_events_enabled -%>
stderr_events_enabled=<%= @stderr_events_enabled %>
<% end -%>
<% if @env_string -%>
environment=<%= @env_string %>
<% end -%>
<% if @directory -%>
directory=<%= @directory %>
<% end -%>
<% if @umask -%>
umask=<%= @umask %>
<% end -%>
<% if @serverurl -%>
serverurl=<%= @serverurl %>
<% end -%>
[fcgi-program:<%= @name %>]
command=<%= @command %>
socket=<%= @socket %>
<% if @socket_owner -%>
socket_owner=<%= @socket_owner %>
<% end -%>
<% if @socket_mode -%>
socket_mode=<%= @socket_mode %>
<% end -%>
<% if @process_name -%>
process_name=<%= @process_name %>
<% end -%>
<% if @numprocs -%>
numprocs=<%= @numprocs %>
<% end -%>
<% if @numprocs_start -%>
numprocs_start=<%= @numprocs_start %>
<% end -%>
<% if @priority -%>
priority=<%= @priority %>
<% end -%>
<% if @autostart -%>
autostart=<%= @autostart %>
<% end -%>
<% if @autorestart -%>
autorestart=<%= @autorestart %>
<% end -%>
<% if @startsecs -%>
startsecs=<%= @startsecs %>
<% end -%>
<% if @startretries -%>
startretries=<%= @startretries %>
<% end -%>
<% if @exitcodes -%>
exitcodes=<%= @exitcodes %>
<% end -%>
<% if @stopsignal -%>
stopsignal=<%= @stopsignal %>
<% end -%>
<% if @stopwaitsecs -%>
stopwaitsecs=<%= @stopwaitsecs %>
<% end -%>
<% if @stopasgroup -%>
stopasgroup=<%= @stopasgroup %>
<% end -%>
<% if @killasgroup -%>
killasgroup=<%= @killasgroup %>
<% end -%>
<% if @user -%>
user=<%= @user %>
<% end -%>
<% if @redirect_stderr -%>
redirect_stderr=<%= @redirect_stderr %>
<% end -%>
<% if @stdout_logfile -%>
stdout_logfile=<%= scope.lookupvar('supervisord::log_path') %>/<%= @stdout_logfile %>
<% end -%>
<% if @stdout_logfile_maxbytes -%>
stdout_logfile_maxbytes=<%= @stdout_logfile_maxbytes %>
<% end -%>
<% if @stdout_logfile_backups -%>
stdout_logfile_backups=<%= @stdout_logfile_backups %>
<% end -%>
<% if @stdout_capture_maxbytes -%>
stdout_capture_maxbytes=<%= @stdout_capture_maxbytes %>
<% end -%>
<% if @stdout_events_enabled -%>
stdout_events_enabled=<%= @stdout_events_enabled %>
<% end -%>
<% if @stderr_logfile -%>
stderr_logfile=<%= scope.lookupvar('supervisord::log_path') %>/<%= @stderr_logfile %>
<% end -%>
<% if @stderr_logfile_maxbytes -%>
stderr_logfile_maxbytes=<%= @stderr_logfile_maxbytes %>
<% end -%>
<% if @stderr_logfile_backups -%>
stderr_logfile_backups=<%= @stderr_logfile_backups %>
<% end -%>
<% if @stderr_capture_maxbytes -%>
stderr_capture_maxbytes=<%= @stderr_capture_maxbytes %>
<% end -%>
<% if @stderr_events_enabled -%>
stderr_events_enabled=<%= @stderr_events_enabled %>
<% end -%>
<% if @env_string -%>
environment=<%= @env_string %>
<% end -%>
<% if @directory -%>
directory=<%= @directory %>
<% end -%>
<% if @umask -%>
umask=<%= @umask %>
<% end -%>
<% if @serverurl -%>
serverurl=<%= @serverurl %>
<% end -%>
[group:<%= @name %>]
programs=<%= @progstring %>
<% if @priority -%>
priority=<%= @priority %>
<% end -%>
[program:<%= @name %>]
command=<%= @command %>
<% if @process_name -%>
process_name=<%= @process_name %>
<% end -%>
<% if @numprocs -%>
numprocs=<%= @numprocs %>
<% end -%>
<% if @numprocs_start -%>
numprocs_start=<%= @numprocs_start %>
<% end -%>
<% if @priority -%>
priority=<%= @priority %>
<% end -%>
<% if @autostart -%>
autostart=<%= @autostart %>
<% end -%>
<% if @autorestart -%>
autorestart=<%= @autorestart %>
<% end -%>
<% if @startsecs -%>
startsecs=<%= @startsecs %>
<% end -%>
<% if @startretries -%>
startretries=<%= @startretries %>
<% end -%>
<% if @exitcodes -%>
exitcodes=<%= @exitcodes %>
<% end -%>
<% if @stopsignal -%>
stopsignal=<%= @stopsignal %>
<% end -%>
<% if @stopwaitsecs -%>
stopwaitsecs=<%= @stopwaitsecs %>
<% end -%>
<% if @stopasgroup -%>
stopasgroup=<%= @stopasgroup %>
<% end -%>
<% if @killasgroup -%>
killasgroup=<%= @killasgroup %>
<% end -%>
<% if @user -%>
user=<%= @user %>
<% end -%>
<% if @redirect_stderr -%>
redirect_stderr=<%= @redirect_stderr %>
<% end -%>
<% if @stdout_logfile -%>
stdout_logfile=<%= scope.lookupvar('supervisord::log_path') %>/<%= @stdout_logfile %>
<% end -%>
<% if @stdout_logfile_maxbytes -%>
stdout_logfile_maxbytes=<%= @stdout_logfile_maxbytes %>
<% end -%>
<% if @stdout_logfile_backups -%>
stdout_logfile_backups=<%= @stdout_logfile_backups %>
<% end -%>
<% if @stdout_capture_maxbytes -%>
stdout_capture_maxbytes=<%= @stdout_capture_maxbytes %>
<% end -%>
<% if @stdout_events_enabled -%>
stdout_events_enabled=<%= @stdout_events_enabled %>
<% end -%>
<% if @stderr_logfile -%>
stderr_logfile=<%= scope.lookupvar('supervisord::log_path') %>/<%= @stderr_logfile %>
<% end -%>
<% if @stderr_logfile_maxbytes -%>
stderr_logfile_maxbytes=<%= @stderr_logfile_maxbytes %>
<% end -%>
<% if @stderr_logfile_backups -%>
stderr_logfile_backups=<%= @stderr_logfile_backups %>
<% end -%>
<% if @stderr_capture_maxbytes -%>
stderr_capture_maxbytes=<%= @stderr_capture_maxbytes %>
<% end -%>
<% if @stderr_events_enabled -%>
stderr_events_enabled=<%= @stderr_events_enabled %>
<% end -%>
<% if @env_string -%>
environment=<%= @env_string %>
<% end -%>
<% if @directory -%>
directory=<%= @directory %>
<% end -%>
<% if @umask -%>
umask=<%= @umask %>
<% end -%>
<% if @serverurl -%>
serverurl=<%= @serverurl %>
<% end -%>
# Defaults for supervisor initscript
# sourced by /etc/init.d/supervisor
# installed at /etc/default/supervisor by the maintainer scripts

#
# This is a POSIX shell fragment
#

# Additional options that are passed to the Daemon.
DAEMON_OPTS="-c <%= @config_file %>"
#! /bin/sh
### BEGIN INIT INFO
# Provides:          supervisor
# Required-Start:    $remote_fs $network $named
# Required-Stop:     $remote_fs $network $named
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Start/stop supervisor
# Description:       Start/stop supervisor daemon and its configured
#                    subprocesses.
### END INIT INFO


PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=<%= @executable %>
NAME=supervisord
DESC=supervisor

# Tests if executable exists
if [ ! -x $DAEMON ] ; then
    echo "Executable not found ${DAEMON}"
    exit 1
fi

LOGDIR=<%= @log_path %>
PIDFILE=<%= @run_path %>/<%= @pid_file %>
DODTIME=5                   # Time to wait for the server to die, in seconds
                            # If this value is set too low you might not
                            # let some servers to die gracefully and
                            # 'restart' will not work

# Include supervisor defaults if available
if [ -f <%= @init_defaults %> ] ; then
        . <%= @init_defaults %>
fi

set -e

running_pid()
{
    # Check if a given process pid's cmdline matches a given name
    pid=$1
    name=$2
    [ -z "$pid" ] && return 1
    [ ! -d /proc/$pid ] &&  return 1
    (cat /proc/$pid/cmdline | tr "\000" "\n"|grep -q $name) || return 1
    return 0
}

running()
{
# Check if the process is running looking at /proc
# (works for all users)

    # No pidfile, probably no daemon present
    [ ! -f "$PIDFILE" ] && return 1
    # Obtain the pid and check it against the binary name
    pid=`cat $PIDFILE`
    running_pid $pid $DAEMON || return 1
    return 0
}

force_stop() {
# Forcefully kill the process
    [ ! -f "$PIDFILE" ] && return
    if running ; then
        kill -15 $pid
        # Is it really dead?
        [ -n "$DODTIME" ] && sleep "$DODTIME"s
        if running ; then
            kill -9 $pid
            [ -n "$DODTIME" ] && sleep "$DODTIME"s
            if running ; then
                echo "Cannot kill $DESC (pid=$pid)!"
                exit 1
            fi
        fi
    fi
    rm -f $PIDFILE
    return 0
}

case "$1" in
  start)
    if [ -e $PIDFILE ]; then
        echo "$DESC already running with pid: `cat $PIDFILE`"
        exit 0
    fi
    echo -n "Starting $DESC: "
    start-stop-daemon --start --quiet --pidfile $PIDFILE \
        --exec $DAEMON -- $DAEMON_OPTS
    test -f $PIDFILE || sleep 1
        if running ; then
            echo "$NAME."
        else
            echo " ERROR."
        fi
    ;;
    stop)
        echo -n "Stopping $DESC: "
        start-stop-daemon --stop --quiet --oknodo --pidfile $PIDFILE 
        echo "$NAME."
    ;;
    force-stop)
        echo -n "Forcefully stopping $DESC: "
        force_stop
        if ! running ; then
            echo "$NAME."
        else
            echo " ERROR."
        fi
    ;;
    restart)
        echo -n "Restarting $DESC: "
        start-stop-daemon --stop --quiet --oknodo --pidfile $PIDFILE
        [ -n "$DODTIME" ] && sleep $DODTIME
        start-stop-daemon --start --quiet --pidfile \
            $PIDFILE --exec $DAEMON -- $DAEMON_OPTS
        echo "$NAME."
    ;;
    status)
        echo -n "$DESC is "
        if running ;  then
            echo "running"
        else
            echo "not running."
            exit 1
        fi
    ;;
    *)
        N=/etc/init.d/$NAME
        echo "Usage: $N {start|stop|restart|status|force-stop}" >&2
        exit 1
    ;;
esac

exit 0
# this is sourced by the supervisord init script
# written by jkoppe

set -a 

# should probably put both of these options as runtime arguments 
OPTIONS="-c <%= @config_file %>"
PIDFILE=<%= @run_path %><%= @pid_file %>
#!/bin/bash
#
# supervisord   This scripts turns supervisord on
#
# Author:       Mike McGrath <mmcgrath@redhat.com> (based off yumupdatesd)
#               Jason Koppe <jkoppe@indeed.com> adjusted to read sysconfig,
#                   use supervisord tools to start/stop, conditionally wait
#                   for child processes to shutdown, and startup later
#
# chkconfig:    345 83 04
#
# description:  supervisor is a process control utility.  It has a web based
#               xmlrpc interface as well as a few other nifty features.
# processname:  supervisord
# config: <%= @config_file %>
# pidfile: <%= @run_path %>/<%= @pid_file %>
#

# source function library
. /etc/rc.d/init.d/functions

# source system settings
[ -e <%= @init_defaults %> ] && . <%= @init_defaults %>

RETVAL=0
DAEMON=<%= @executable %>
CTL=<%= @executable_ctl %>
DESC=supervisord
PIDFILE=<%= @run_path %>/<%= @pid_file %>

# Tests if executable exists
if [ ! -x $DAEMON ] ; then
    echo "Executable not found ${DAEMON}"
    exit 1
fi

running_pid()
{
    # Check if a given process pid's cmdline matches a given name
    pid=$1
    name=$2
    [ -z "$pid" ] && return 1
    [ ! -d /proc/$pid ] &&  return 1
    (cat /proc/$pid/cmdline | tr "\000" "\n"|grep -q $name) || return 1
    return 0
}

running()
{
# Check if the process is running looking at /proc
# (works for all users)

    # No pidfile, probably no daemon present
    [ ! -f "$PIDFILE" ] && return 1
    # Obtain the pid and check it against the binary name
    pid=`cat $PIDFILE`
    running_pid $pid $DAEMON || return 1
    return 0
}

start() {
    echo -n "Starting $DESC: "
    if [ -e $PIDFILE ]; then 
        echo "ALREADY STARTED"
        return 1
    else
        # start supervisord with options from sysconfig (stuff like -c)
        daemon $DAEMON $OPTIONS
        # only create the subsyslock if we created the PIDFILE
        [ -e $PIDFILE ] && touch /var/lock/subsys/supervisord
        return 0
    fi
}

stop() {
    echo -n "Stopping supervisord: "
    killproc -p $PIDFILE $DESC 
    # always remove the subsys.  we might have waited a while, but just remove it at this point.
    rm -f /var/lock/subsys/supervisord
    return 0
}

restart() {
        stop
        start
}

case "$1" in
    start)
        start
        ;;
    stop)
        stop
        ;;
    restart|force-reload)
        restart
        ;;
    reload)
        $CTL $OPTIONS reload
        RETVAL=$?
        ;;
    condrestart)
        [ -f /var/lock/subsys/supervisord ] && restart
        RETVAL=$?
        ;;
    status)
        echo -n "supervisord is "
        if running ;  then
            echo "running"
        else
            echo "not running."
            exit 1
    fi
    ;;
    *)
        echo $"Usage: $0 {start|stop|status|restart|reload|force-reload|condrestart}"
        exit 1
esac

exit $RETVAL
[inet_http_server]
port=<%= @inet_server_hostname %>:<%= @inet_server_port %>
<% if @inet_auth -%>
username=<%= @inet_username %>
password=<%= @inet_password %>
<% end -%>

[supervisorctl]
serverurl=http://<%= @inet_hostname%>:<%= @inet_server_port %>
<% if @inet_auth -%>
username=<%= @inet_username %>
password=<%= @inet_password %>
<% end -%>
[supervisord]
logfile=<%= @log_path %>/<%= @log_file %>
pidfile=<%= @run_path %>/<%= @pid_file %>
nodaemon=<%= @nodaemon %>
minfds=<%= @minfds %>
minprocs=<%= @minprocs %>
umask=<%= @umask %>
<% if @strip_ansi -%>
strip_ansi=<%= @strip_ansi %>
<% end -%>
<% if @user -%>
user=<%= @user %>
<% end -%>
<% if @identifier -%>
identifier=<%= @identifier %>
<% end -%>
<% if @directory -%>
directory=<%= @directory %>
<% end -%>
<% if @nocleanup -%>
nocleanup=true
<% end -%>
<% if @childlogdir -%>
childlogdir=<%= @childlogdir %>
<% end -%>
<% if @env_string -%>
environment=<%= @env_string %>
<% end -%>

[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface

[include]
files=<%= @config_include_string %>
[unix_http_server]
file=<%= @run_path %>/<%= @unix_socket_file %>
chmod=<%= @unix_socket_mode %>
chown=<%= @unix_socket_owner %>:<%= @unix_socket_group %>
<% if @unix_auth -%>
username=<%= @unix_socket_username %>
password=<%= @unix_socket_password %>
<% end -%>

[supervisorctl]
serverurl=unix://<%= @run_path %>/<%= @unix_socket_file %>
<% if @unix_auth -%>
username=<%= @unix_username %>
password=<%= @unix_password %>
<% end -%>
supervisord::group { 'mygroup':
  priority => 100,
  program  => ['program1', 'program2', 'program3']
}
class { 'supervisord':
  install_pip  => true,
  install_init => true,
  nocleanup    => true,
}
supervisord::program { 'myprogram':
  command                 => 'command --args',
  process_name            => '%(process_num)s',
  numprocs                => '1',
  numprocs_start          => '0',
  priority                => '999',
  autostart               => true,
  autorestart             => 'unexpected',
  startsecs               => '1',
  startretries            => '3',
  exitcodes               => '0,2',
  stopsignal              => 'TERM',
  stopwaitsecs            => '10',
  stopasgroup             => false,
  killasgroup             => false,
  redirect_stderr         => false,
  stdout_logfile          => 'program_foo.log',
  stdout_logfile_maxbytes => '50MB',
  stdout_logfile_backups  => '10',
  stdout_capture_maxbytes => '0',
  stdout_events_enabled   => false,
  stderr_logfile          => 'program_foo.error',
  stderr_logfile_maxbytes => '50MB',
  stderr_logfile_backups  => '10',
  stderr_capture_maxbytes => '0',
  stderr_events_enabled   => false,
  environment             => {
    'HOME'   => '/home/myuser',
    'PATH'   => '/bin:/sbin:/usr/bin:/usr/sbin',
    'SECRET' => 'mysecret'
  },
  directory               => undef,
  umask                   => '022',
  serverurl               => 'AUTO'
}
fixtures:
  repositories:
    stdlib: "git://github.com/puppetlabs/puppetlabs-stdlib.git"
  symlinks:
    swap_file: "#{source_dir}"
language: ruby
bundler_args: --without development
before_install: rm Gemfile.lock || true
rvm:
  - 1.8.7
  - 1.9.3
  - 2.0.0
script: bundle exec rake test
env:
  - PUPPET_VERSION="~> 2.7.0"
  - PUPPET_VERSION="~> 3.1.0"
  - PUPPET_VERSION="~> 3.2.0"
  - PUPPET_VERSION="~> 3.3.0"
  - PUPPET_VERSION="~> 3.4.0"
matrix:
  exclude:
  - rvm: 2.0.0
    env: PUPPET_VERSION="~> 2.7.0"
  - rvm: 2.0.0
    env: PUPPET_VERSION="~> 3.1.0"
  - rvm: 1.9.3
    env: PUPPET_VERSION="~> 2.7.0"
## Change Log

### upcoming (2014/02/27 11:12 +00:00)
- [c8cf711](https://github.com/petems/puppet-swap_file/commit/c8cf711bb10f100c0b9ad66a16e7e54a54f776d3) Initial Commit (@petems)
- [02e1a1a](https://github.com/petems/puppet-swap_file/commit/02e1a1ab01886028bf79e7bc870df110a53cf5b7) Rename spec file (@petems)
- [fbaa2e4](https://github.com/petems/puppet-swap_file/commit/fbaa2e46f632142f4dc63c4928c8e9e206920a2c) Update changelog with `github-changes` (@petems)
- [3952796](https://github.com/petems/puppet-swap_file/commit/39527966fac72219a1b938af38b8f3a71e3e428e) Removed old CHANGELOG (@petems)
- [43da89d](https://github.com/petems/puppet-swap_file/commit/43da89d4e4d49b4a08c16d6fa2a38774f59910fc) Update module file with details (@petems)
- [e79df44](https://github.com/petems/puppet-swap_file/commit/e79df44578f4bf1b70168bd8fa9cb3a9620463a0) Removing custom fact for memory size in bytes (@petems)
- [c267e95](https://github.com/petems/puppet-swap_file/commit/c267e959720e1cdb8573a4c44be0e0db2a48d411) Update README (@petems)
- [88095a5](https://github.com/petems/puppet-swap_file/commit/88095a5f9cebdb5499e57dab01fa208f4341d9f9) Change just windows to fail... (@petems)
- [b61645c](https://github.com/petems/puppet-swap_file/commit/b61645c00d8761a0d07ecc0da8a5ffe4bb4bdab7) Fix double quoted string lint issue (@petems)
- [#1](https://github.com/petems/puppet-swap_file/pull/1) Merge pull request #1 from petems/remove_custom_fact (@petems)
This module has grown over time based on a range of contributions from
people using it. If you follow these contributing guidelines your patch
will likely make it into a release a little quicker.


## Contributing

1. Fork the repo.

2. Run the tests. We only take pull requests with passing tests, and
   it's great to know that you have a clean slate

3. Add a test for your change. Only refactoring and documentation
   changes require no new tests. If you are adding functionality
   or fixing a bug, please add a test.

4. Make the test pass.

5. Push to your fork and submit a pull request.


## Dependencies

The testing and development tools have a bunch of dependencies,
all managed by [bundler](http://bundler.io/) according to the
[Puppet support matrix](http://docs.puppetlabs.com/guides/platforms.html#ruby-versions).

By default the tests use a baseline version of Puppet.

If you have Ruby 2.x or want a specific version of Puppet,
you must set an environment variable such as:

    export PUPPET_VERSION="~> 3.2.0"

Install the dependencies like so...

    bundle install

## Syntax and style

The test suite will run [Puppet Lint](http://puppet-lint.com/) and
[Puppet Syntax](https://github.com/gds-operations/puppet-syntax) to
check various syntax and style things. You can run these locally with:

    bundle exec rake lint
    bundle exec rake syntax

## Running the unit tests

The unit test suite covers most of the code, as mentioned above please
add tests if you're adding new functionality. If you've not used
[rspec-puppet](http://rspec-puppet.com/) before then feel free to ask
about how best to test your new feature. Running the test suite is done
with:

    bundle exec rake spec

Note also you can run the syntax, style and unit tests in one go with:

    bundle exec rake test

## Integration tests

The unit tests just check the code runs, not that it does exactly what
we want on a real machine. For that we're using
[beaker](https://github.com/puppetlabs/beaker).

This fires up a new virtual machine (using vagrant) and runs a series of
simple tests against it after applying the module. You can run this
with:

    bundle exec rake acceptance

This will run the tests on an Ubuntu 12.04 virtual machine. You can also
run the integration tests against Centos 6.5 with.

    RS_SET=centos-64-x64 bundle exec rake acceptances

If you don't want to have to recreate the virtual machine every time you
can use `RS_DESTROY=no` and `RS_PROVISION=no`. On the first run you will
at least need `RS_PROVISION` set to yes (the default). The Vagrantfile
for the created virtual machines will be in `.vagrant/beaker_vagrant_fies`.

Peter Souter (@petems)
source "http://rubygems.org"

group :test do
  gem "rake"
  gem "puppet", ENV['PUPPET_VERSION'] || '~> 3.4.0'
  gem "puppet-lint"
  gem "rspec-puppet", :git => 'https://github.com/rodjek/rspec-puppet.git'
  gem "puppet-syntax"
  gem "puppetlabs_spec_helper"
end

group :development do
  gem "travis"
  gem "travis-lint"
  gem "beaker"
  gem "beaker-rspec"
  gem "vagrant-wrapper"
  gem "puppet-blacksmith"
  gem "guard-rake"
end
GIT
  remote: https://github.com/rodjek/rspec-puppet.git
  revision: 03e94422fb9bbdd950d5a0bec6ead5d76e06616b
  specs:
    rspec-puppet (1.0.1)
      rspec

GEM
  remote: http://rubygems.org/
  specs:
    CFPropertyList (2.2.7)
    addressable (2.3.5)
    backports (3.6.0)
    beaker (1.7.0)
      blimpy (~> 0.6)
      fission (~> 0.4)
      inifile (~> 2.0)
      json (~> 1.8)
      mime-types (~> 1.25)
      net-scp (~> 1.1)
      net-ssh (~> 2.6)
      nokogiri (= 1.5.10)
      rbvmomi (= 1.8.1)
      unf (~> 0.1)
    beaker-rspec (2.1.1)
      beaker (~> 1.3)
      rspec (~> 2.14)
      serverspec (~> 0.14)
      specinfra (~> 0.3)
    blimpy (0.6.7)
      fog
      minitar
      thor
    builder (3.2.2)
    celluloid (0.15.2)
      timers (~> 1.1.0)
    celluloid-io (0.15.0)
      celluloid (>= 0.15.0)
      nio4r (>= 0.5.0)
    coderay (1.1.0)
    diff-lcs (1.2.5)
    ethon (0.6.3)
      ffi (>= 1.3.0)
      mime-types (~> 1.18)
    excon (0.31.0)
    facter (1.7.5)
    faraday (0.8.9)
      multipart-post (~> 1.2.0)
    faraday_middleware (0.9.0)
      faraday (>= 0.7.4, < 0.9)
    ffi (1.9.3)
    fission (0.5.0)
      CFPropertyList (~> 2.2)
    fog (1.19.0)
      builder
      excon (~> 0.31.0)
      formatador (~> 0.2.0)
      mime-types
      multi_json (~> 1.0)
      net-scp (~> 1.1)
      net-ssh (>= 2.1.3)
      nokogiri (~> 1.5)
      ruby-hmac
    formatador (0.2.4)
    gh (0.13.2)
      addressable
      backports
      faraday (~> 0.8)
      multi_json (~> 1.0)
      net-http-persistent (>= 2.7)
      net-http-pipeline
    guard (2.5.1)
      formatador (>= 0.2.4)
      listen (~> 2.6)
      lumberjack (~> 1.0)
      pry (>= 0.9.12)
      thor (>= 0.18.1)
    guard-rake (0.0.9)
      guard
      rake
    hashr (0.0.22)
    hiera (1.3.1)
      json_pure
    highline (1.6.20)
    inifile (2.0.2)
    json (1.8.1)
    json_pure (1.8.1)
    launchy (2.4.2)
      addressable (~> 2.3)
    listen (2.6.1)
      celluloid (>= 0.15.2)
      celluloid-io (>= 0.15.0)
      rb-fsevent (>= 0.9.3)
      rb-inotify (>= 0.9)
    lumberjack (1.0.4)
    metaclass (0.0.4)
    method_source (0.8.2)
    mime-types (1.25.1)
    minitar (0.5.4)
    mocha (1.0.0)
      metaclass (~> 0.0.1)
    multi_json (1.8.4)
    multipart-post (1.2.0)
    net-http-persistent (2.9.4)
    net-http-pipeline (1.0.1)
    net-scp (1.1.2)
      net-ssh (>= 2.6.5)
    net-ssh (2.8.0)
    nio4r (1.0.0)
    nokogiri (1.5.10)
    pry (0.9.12.6)
      coderay (~> 1.0)
      method_source (~> 0.8)
      slop (~> 3.4)
    puppet (3.4.3)
      facter (~> 1.6)
      hiera (~> 1.0)
      rgen (~> 0.6.5)
    puppet-blacksmith (2.0.2)
      nokogiri
      puppet (>= 2.7.16)
      rest-client
    puppet-lint (0.3.2)
    puppet-syntax (1.1.0)
      puppet (>= 2.7.0)
      rake
    puppetlabs_spec_helper (0.4.1)
      mocha (>= 0.10.5)
      rake
      rspec (>= 2.9.0)
      rspec-puppet (>= 0.1.1)
    pusher-client (0.4.0)
      websocket (~> 1.0.0)
    rake (10.1.1)
    rb-fsevent (0.9.4)
    rb-inotify (0.9.3)
      ffi (>= 0.5.0)
    rbvmomi (1.8.1)
      builder
      nokogiri (>= 1.4.1)
      trollop
    rest-client (1.6.7)
      mime-types (>= 1.16)
    rgen (0.6.6)
    rspec (2.14.1)
      rspec-core (~> 2.14.0)
      rspec-expectations (~> 2.14.0)
      rspec-mocks (~> 2.14.0)
    rspec-core (2.14.7)
    rspec-expectations (2.14.5)
      diff-lcs (>= 1.1.3, < 2.0)
    rspec-mocks (2.14.6)
    ruby-hmac (0.4.0)
    serverspec (0.15.3)
      highline
      net-ssh
      rspec (>= 2.13.0)
      specinfra (>= 0.5.8)
    slop (3.4.7)
    specinfra (0.7.0)
    thor (0.18.1)
    timers (1.1.0)
    travis (1.6.7)
      addressable (~> 2.3)
      backports
      faraday (~> 0.8.7)
      faraday_middleware (~> 0.9)
      gh (~> 0.13)
      highline (~> 1.6)
      launchy (~> 2.1)
      pry (~> 0.9)
      pusher-client (~> 0.4)
      typhoeus (~> 0.6)
    travis-lint (1.7.0)
      hashr (~> 0.0.22)
    trollop (2.0)
    typhoeus (0.6.7)
      ethon (~> 0.6.2)
    unf (0.1.3)
      unf_ext
    unf_ext (0.0.6)
    vagrant-wrapper (1.2.1.1)
    websocket (1.0.7)

PLATFORMS
  ruby

DEPENDENCIES
  beaker
  beaker-rspec
  guard-rake
  puppet (~> 3.4.0)
  puppet-blacksmith
  puppet-lint
  puppet-syntax
  puppetlabs_spec_helper
  rake
  rspec-puppet!
  travis
  travis-lint
  vagrant-wrapper
notification :off

guard 'rake', :task => 'test' do
  watch(%r{^manifests\/(.+)\.pp$})
end
                              Apache License
                        Version 2.0, January 2004
                     http://www.apache.org/licenses/

TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

1. Definitions.

   "License" shall mean the terms and conditions for use, reproduction,
   and distribution as defined by Sections 1 through 9 of this document.

   "Licensor" shall mean the copyright owner or entity authorized by
   the copyright owner that is granting the License.

   "Legal Entity" shall mean the union of the acting entity and all
   other entities that control, are controlled by, or are under common
   control with that entity. For the purposes of this definition,
   "control" means (i) the power, direct or indirect, to cause the
   direction or management of such entity, whether by contract or
   otherwise, or (ii) ownership of fifty percent (50%) or more of the
   outstanding shares, or (iii) beneficial ownership of such entity.

   "You" (or "Your") shall mean an individual or Legal Entity
   exercising permissions granted by this License.

   "Source" form shall mean the preferred form for making modifications,
   including but not limited to software source code, documentation
   source, and configuration files.

   "Object" form shall mean any form resulting from mechanical
   transformation or translation of a Source form, including but
   not limited to compiled object code, generated documentation,
   and conversions to other media types.

   "Work" shall mean the work of authorship, whether in Source or
   Object form, made available under the License, as indicated by a
   copyright notice that is included in or attached to the work
   (an example is provided in the Appendix below).

   "Derivative Works" shall mean any work, whether in Source or Object
   form, that is based on (or derived from) the Work and for which the
   editorial revisions, annotations, elaborations, or other modifications
   represent, as a whole, an original work of authorship. For the purposes
   of this License, Derivative Works shall not include works that remain
   separable from, or merely link (or bind by name) to the interfaces of,
   the Work and Derivative Works thereof.

   "Contribution" shall mean any work of authorship, including
   the original version of the Work and any modifications or additions
   to that Work or Derivative Works thereof, that is intentionally
   submitted to Licensor for inclusion in the Work by the copyright owner
   or by an individual or Legal Entity authorized to submit on behalf of
   the copyright owner. For the purposes of this definition, "submitted"
   means any form of electronic, verbal, or written communication sent
   to the Licensor or its representatives, including but not limited to
   communication on electronic mailing lists, source code control systems,
   and issue tracking systems that are managed by, or on behalf of, the
   Licensor for the purpose of discussing and improving the Work, but
   excluding communication that is conspicuously marked or otherwise
   designated in writing by the copyright owner as "Not a Contribution."

   "Contributor" shall mean Licensor and any individual or Legal Entity
   on behalf of whom a Contribution has been received by Licensor and
   subsequently incorporated within the Work.

2. Grant of Copyright License. Subject to the terms and conditions of
   this License, each Contributor hereby grants to You a perpetual,
   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
   copyright license to reproduce, prepare Derivative Works of,
   publicly display, publicly perform, sublicense, and distribute the
   Work and such Derivative Works in Source or Object form.

3. Grant of Patent License. Subject to the terms and conditions of
   this License, each Contributor hereby grants to You a perpetual,
   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
   (except as stated in this section) patent license to make, have made,
   use, offer to sell, sell, import, and otherwise transfer the Work,
   where such license applies only to those patent claims licensable
   by such Contributor that are necessarily infringed by their
   Contribution(s) alone or by combination of their Contribution(s)
   with the Work to which such Contribution(s) was submitted. If You
   institute patent litigation against any entity (including a
   cross-claim or counterclaim in a lawsuit) alleging that the Work
   or a Contribution incorporated within the Work constitutes direct
   or contributory patent infringement, then any patent licenses
   granted to You under this License for that Work shall terminate
   as of the date such litigation is filed.

4. Redistribution. You may reproduce and distribute copies of the
   Work or Derivative Works thereof in any medium, with or without
   modifications, and in Source or Object form, provided that You
   meet the following conditions:

   (a) You must give any other recipients of the Work or
       Derivative Works a copy of this License; and

   (b) You must cause any modified files to carry prominent notices
       stating that You changed the files; and

   (c) You must retain, in the Source form of any Derivative Works
       that You distribute, all copyright, patent, trademark, and
       attribution notices from the Source form of the Work,
       excluding those notices that do not pertain to any part of
       the Derivative Works; and

   (d) If the Work includes a "NOTICE" text file as part of its
       distribution, then any Derivative Works that You distribute must
       include a readable copy of the attribution notices contained
       within such NOTICE file, excluding those notices that do not
       pertain to any part of the Derivative Works, in at least one
       of the following places: within a NOTICE text file distributed
       as part of the Derivative Works; within the Source form or
       documentation, if provided along with the Derivative Works; or,
       within a display generated by the Derivative Works, if and
       wherever such third-party notices normally appear. The contents
       of the NOTICE file are for informational purposes only and
       do not modify the License. You may add Your own attribution
       notices within Derivative Works that You distribute, alongside
       or as an addendum to the NOTICE text from the Work, provided
       that such additional attribution notices cannot be construed
       as modifying the License.

   You may add Your own copyright statement to Your modifications and
   may provide additional or different license terms and conditions
   for use, reproduction, or distribution of Your modifications, or
   for any such Derivative Works as a whole, provided Your use,
   reproduction, and distribution of the Work otherwise complies with
   the conditions stated in this License.

5. Submission of Contributions. Unless You explicitly state otherwise,
   any Contribution intentionally submitted for inclusion in the Work
   by You to the Licensor shall be under the terms and conditions of
   this License, without any additional terms or conditions.
   Notwithstanding the above, nothing herein shall supersede or modify
   the terms of any separate license agreement you may have executed
   with Licensor regarding such Contributions.

6. Trademarks. This License does not grant permission to use the trade
   names, trademarks, service marks, or product names of the Licensor,
   except as required for reasonable and customary use in describing the
   origin of the Work and reproducing the content of the NOTICE file.

7. Disclaimer of Warranty. Unless required by applicable law or
   agreed to in writing, Licensor provides the Work (and each
   Contributor provides its Contributions) on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
   implied, including, without limitation, any warranties or conditions
   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
   PARTICULAR PURPOSE. You are solely responsible for determining the
   appropriateness of using or redistributing the Work and assume any
   risks associated with Your exercise of permissions under this License.

8. Limitation of Liability. In no event and under no legal theory,
   whether in tort (including negligence), contract, or otherwise,
   unless required by applicable law (such as deliberate and grossly
   negligent acts) or agreed to in writing, shall any Contributor be
   liable to You for damages, including any direct, indirect, special,
   incidental, or consequential damages of any character arising as a
   result of this License or out of the use or inability to use the
   Work (including but not limited to damages for loss of goodwill,
   work stoppage, computer failure or malfunction, or any and all
   other commercial damages or losses), even if such Contributor
   has been advised of the possibility of such damages.

9. Accepting Warranty or Additional Liability. While redistributing
   the Work or Derivative Works thereof, You may choose to offer,
   and charge a fee for, acceptance of support, warranty, indemnity,
   or other liability obligations and/or rights consistent with this
   License. However, in accepting such obligations, You may act only
   on Your own behalf and on Your sole responsibility, not on behalf
   of any other Contributor, and only if You agree to indemnify,
   defend, and hold each Contributor harmless for any liability
   incurred by, or claims asserted against, such Contributor by reason
   of your accepting any such warranty or additional liability.

END OF TERMS AND CONDITIONS

APPENDIX: How to apply the Apache License to your work.

   To apply the Apache License to your work, attach the following
   boilerplate notice, with the fields enclosed by brackets "[]"
   replaced with your own identifying information. (Don't include
   the brackets!)  The text should be enclosed in the appropriate
   comment syntax for the file format. We also recommend that a
   file or class name and description of purpose be included on the
   same "printed page" as the copyright notice for easier
   identification within third-party archives.

Copyright [yyyy] [name of copyright owner]

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

name          'petems-swap_file'
version '0.1.3'
source        'git://github.com/petems/puppet-swap_file.git'
author        'petems'
license       'Apache License, Version 2.0'
summary       'Swap file management with Puppet'
description   'Create swap files for Linux systems with Puppet'
project_page  'https://github.com/petems/puppet-swap_file'

dependency 'puppetlabs/stdlib', '>= 3.2.0'
####Table of Contents

1. [Overview](#overview)
2. [Module Description ](#module-description)
3. [Setup](#setup)
    * [What swap_file affects](#what-swap_file-affects)
    * [Setup requirements](#setup-requirements)
4. [Usage](#usage)
5. [Reference](#reference)
5. [Limitations](#limitations)
6. [Development](#development)

##Overview

Manage [swap files](http://en.wikipedia.org/wiki/Paging) for your Linux environments. This is based on the gist by @Yggdrasil, with a few changes and added specs.

##Setup

###What swap_file affects

* Swapfiles on the system
* Any mounts of swapfiles

##Usage

The simplest use of the module is this:

```puppet
include swap
```

By default, the module it will create a swap file under `/mnt/swap.1` with the default size taken from the `$::memorysizeinbytes` fact divided by 1000000.

For a custom setup, you can do something like this:

```puppet
swap {
  swapfile     => '/swapfile/swap1',
  swapfilesize => '1000000'
}
```

To remove a prexisting swap, you can use ensure absent:

```puppet
swap {
  ensure   => 'absent'
  swapfile => '/swapfile/swap1',
}
```

##Limitations

Primary support is for Debian and RedHat, but should work on all Linux flavours.

##Development

Follow the CONTRIBUTING guidelines! :)
require 'puppetlabs_spec_helper/rake_tasks'
require 'puppet-lint/tasks/puppet-lint'
require 'puppet-syntax/tasks/puppet-syntax'

# These two gems aren't always present, for instance
# on Travis with --without development
begin
  require 'puppet_blacksmith/rake_tasks'
rescue LoadError
end

PuppetLint.configuration.send("disable_80chars")
PuppetLint.configuration.log_format = "%{path}:%{linenumber}:%{check}:%{KIND}:%{message}"
PuppetLint.configuration.fail_on_warnings = true

# Forsake support for Puppet 2.6.2 for the benefit of cleaner code.
# http://puppet-lint.com/checks/class_parameter_defaults/
PuppetLint.configuration.send('disable_class_parameter_defaults')
# http://puppet-lint.com/checks/class_inherits_from_params_class/
PuppetLint.configuration.send('disable_class_inherits_from_params_class')

exclude_paths = [
  "pkg/**/*",
  "vendor/**/*",
  "spec/**/*",
]
PuppetLint.configuration.ignore_paths = exclude_paths
PuppetSyntax.exclude_paths = exclude_paths

desc "Run acceptance tests"
RSpec::Core::RakeTask.new(:acceptance) do |t|
  t.pattern = 'spec/acceptance'
end

desc "Run syntax, lint, and spec tests."
task :test => [
  :syntax,
  :lint,
  :spec,
]
# Class: swap_file
#
# This class manages swapspace on a node.
#
# == Parameters
# [*ensure*]
#   Allows creation or removal of swapspace and the corresponding file.
# [*swapfile*]
#   Location of swapfile, defaults to /mnt
# [*swapfilesize*]
#   Size of the swapfile as a string (eg. 10 MB, 1.2 GB).
#   Defaults to $::memorysize fact on the node
#
# == Examples
#
#   include swap_file
#
#   class { 'swap_file':
#     ensure => present,
#   }
#
#   class { 'swap_file':
#     swapfile => '/mount/swapfile',
#     swapfilesize => '100 MB',
#   }
#
# == Authors
#    @petems - Peter Souter
#    @Yggdrasil
#
class swap_file (
  $ensure        = 'present',
  $swapfile      = '/mnt/swap.1',
  $swapfilesize  = $::memorysize,
) inherits swap_file::params {
  $swapfilesize_mb = to_bytes($swapfilesize) / 1000000
  if $ensure == 'present' {
      exec { 'Create swap file':
        command => "/bin/dd if=/dev/zero of=${swapfile} bs=1M count=${swapfilesize_mb}",
        creates => $swapfile,
      }
      exec { 'Attach swap file':
        command => "/sbin/mkswap ${swapfile} && /sbin/swapon ${swapfile}",
        require => Exec['Create swap file'],
        unless  => "/sbin/swapon -s | grep ${swapfile}",
      }
    }
  elsif $ensure == 'absent' {
    exec { 'Detach swap file':
      command => "/sbin/swapoff ${swapfile}",
      onlyif  => "/sbin/swapon -s | grep ${swapfile}",
    }
    file { $swapfile:
      ensure  => absent,
      require => Exec['Detach swap file'],
    }
  }
}
# == Class swap_file::params
#
# This class is meant to be called from swap_file
# It sets variables according to platform
#
class swap_file::params {
  case $::osfamily {
    'Debian': {

    }
    'RedHat': {

    }
    'windows': {
      fail('Swap files dont work on windows')
    }
    default: {
      warning("${::operatingsystem} not officially supported, but should work")
    }
  }
}
require 'spec_helper_acceptance'

describe 'swap_file class', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do

  context 'swap_file' do
    context 'ensure => present' do
      it 'should work with no errors' do
        pp = <<-EOS
        class { 'swap_file': }
        EOS

        # Run it twice and test for idempotency
        expect(apply_manifest(pp).exit_code).to_not eq(1)
        expect(apply_manifest(pp).exit_code).to eq(0)
      end
      it 'should contain the default swapfile' do
        shell('/sbin/swapon -s | grep /mnt/swap.1', :acceptable_exit_codes => [0])
      end
    end
    context 'custom parameters' do
      it 'should work with no errors' do
        pp = <<-EOS
        class { 'swap_file':
          swapfile => '/tmp/swapfile',
          swapfilesize => '5 MB',
        }
        EOS

        expect(apply_manifest(pp).exit_code).to_not eq(1)
        expect(apply_manifest(pp).exit_code).to eq(0)
      end
      it 'should contain the given swapfile' do
        shell('/sbin/swapon -s | grep /tmp/swapfile', :acceptable_exit_codes => [0])
        shell('/sbin/swapon -s | grep 5116', :acceptable_exit_codes => [0])
      end
    end
  end
end
HOSTS:
  centos-64-x64:
    roles:
      - master
    platform: el-6-x86_64
    box: centos-64-x64-vbox4210-nocm
    box_url: http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x64-vbox4210-nocm.box
    hypervisor: vagrant
CONFIG:
  log_level: verbose
  type: foss
HOSTS:
  ubuntu-server-12042-x64:
    roles:
      - master
    platform: ubuntu-12.04-amd64
    box: ubuntu-server-12042-x64-vbox4210-nocm
    box_url: http://puppet-vagrant-boxes.puppetlabs.com/ubuntu-server-12042-x64-vbox4210-nocm.box
    hypervisor: vagrant
CONFIG:
  log_level: verbose
  type: foss
HOSTS:
  ubuntu-server-12042-x64:
    roles:
      - master
    platform: ubuntu-12.04-amd64
    box: ubuntu-server-12042-x64-vbox4210-nocm
    box_url: http://puppet-vagrant-boxes.puppetlabs.com/ubuntu-server-12042-x64-vbox4210-nocm.box
    hypervisor: vagrant
CONFIG:
  log_level: verbose
  type: foss
at_exit { RSpec::Puppet::Coverage.report! }
require 'spec_helper'

describe 'swap_file' do

  context 'supported operating systems' do
    ['Debian', 'RedHat'].each do |osfamily|
      describe "swap_file class without any parameters on #{osfamily}" do
        let(:facts) {{
          :osfamily => osfamily, :memorysize => '1 GB',
        }}

        it { should compile.with_all_deps }

        it { should contain_class('Swap_file::Params') }
        it { should contain_class('Swap_file') }

        it {
            should contain_exec('Create swap file').
              with_command('/bin/dd if=/dev/zero of=/mnt/swap.1 bs=1M count=1073')
            }

        it { should contain_exec('Attach swap file') }
      end
      describe "swap_file class with parameters on #{osfamily}" do
        let(:params) {{ :swapfile => '/foo/bar', :swapfilesize => '1 GB' }}
        let(:facts) {{
          :osfamily => osfamily,
        }}

        it { should compile.with_all_deps }

        it { should contain_class('Swap_file::Params') }
        it { should contain_class('Swap_file') }

        it {
            should contain_exec('Create swap file').
              with_command('/bin/dd if=/dev/zero of=/foo/bar bs=1M count=1073')
            }
        it { should contain_exec('Attach swap file') }
      end
    end
  end

  context 'not officially support operating system' do
    describe 'Solaris Nexenta system without any parameters' do
      let(:facts) {{
        :osfamily        => 'Solaris',
        :operatingsystem => 'Nexenta',
        :memorysize      => '1 GB',
      }}

      it { should compile.with_all_deps }

      it { should contain_class('Swap_file::Params') }
      it { should contain_class('Swap_file') }

      it {
          should contain_exec('Create swap file').
            with_command('/bin/dd if=/dev/zero of=/mnt/swap.1 bs=1M count=1073')
          }

      it { should contain_exec('Attach swap file') }
    end
  end

  context 'windows operating system' do
    describe 'swap_file class without any parameters on Windows' do
      let(:facts) {{
        :osfamily        => 'windows',
        :operatingsystem => 'windows',
      }}

      it { expect { should contain_class('swap_file') }.to raise_error(Puppet::Error, /Swap files dont work on windows/) }
    end
  end
end
require 'puppetlabs_spec_helper/module_spec_helper'
require 'beaker-rspec'

unless ENV['RS_PROVISION'] == 'no'
  hosts.each do |host|
    if host.is_pe?
      install_pe
    else
      install_puppet
      on host, "mkdir -p #{host['distmoduledir']}"
    end
  end
end

UNSUPPORTED_PLATFORMS = ['windows']

RSpec.configure do |c|
  # Project root
  proj_root = File.expand_path(File.join(File.dirname(__FILE__), '..'))

  # Readable test descriptions
  c.formatter = :documentation

  # Configure all nodes in nodeset
  c.before :suite do
    # Install module and dependencies
    puppet_module_install(:source => proj_root, :module_name => 'swap_file')
    hosts.each do |host|
      shell('/bin/touch /etc/puppet/hiera.yaml')
      shell('puppet module install puppetlabs-stdlib --version 3.2.0', { :acceptable_exit_codes => [0,1] })
    end
  end
end
# The baseline for module testing used by Puppet Labs is that each manifest
# should have a corresponding test manifest that declares that class or defined
# type.
#
# Tests are then run by using puppet apply --noop (to check for compilation
# errors and view a log of events) or by fully applying the test in a virtual
# environment (to compare the resulting system state to the desired state).
#
# Learn more about module testing here:
# http://docs.puppetlabs.com/guides/tests_smoke.html
#
include swap_file
2014-01-20 - 0.3.0
* Add optional comment inside the sysctl.d file.
* Use sysctl -p with the created/modified file instead of sysctl -w (#3).
* Fix purge and set its default to false (#7, tehmaspc).

2013-10-02 - 0.2.0
* Add optional prefix to the sysctl.d file name, to force ordering.

2013-06-25 - 0.1.1
* Make purge optional, still enabled by default.
* Add rspec tests (Justin Lambert).
* Minor fix for values with spaces (needs more changes to be robust).

2013-03-06 - 0.1.0
* Update README to markdown.
* Change to recommended 2 space indent.

2012-12-18 - 0.0.3
* Add feature to update existing values in /etc/sysctl.conf.
* Apply setting on each run if needed (hakamadare).
* Make sure $ensure => absent still works with the above change.

2012-09-19 - 0.0.2
* Fix deprecation warnings.
* Fix README markup.

2012-07-19 - 0.0.1
* Initial module release.

source :rubygems

puppetversion = ENV['PUPPET_VERSION']
gem 'puppet', puppetversion, :require => false
gem 'puppet-lint'
gem 'rspec-puppet'
gem 'puppetlabs_spec_helper', '>= 0.4.0'

Copyright (C) 2011-2013 Matthias Saou

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

name 'thias-sysctl'
version '0.3.0'
source 'git://github.com/thias/puppet-sysctl'
author 'Matthias Saou'
license 'Apache 2.0'
summary 'Sysctl module'
description "Manage sysctl variable values."
project_page 'https://github.com/thias/puppet-sysctl'
# puppet-sysctl

## Overview

Manage sysctl variable values. All changes are immediately applied, as well as
configured to become persistent. Tested on Red Hat Enterprise Linux 6.

 * `sysctl` : Definition to manage sysctl variables by setting a value.
 * `sysctl::base`: Base class (included from the definition).

For persistence to work, your Operating System needs to support looking for
sysctl configuration inside `/etc/sysctl.d/`.

You may optionally enable purging of the `/etc/sysctl.d/` directory, so that
all files which are not (or no longer) managed by this module will be removed.

Beware that for the purge to work, you need to either have at least one
sysctl definition call left for the node, or include `sysctl::base` manually.

You may also force a value to `ensure => absent`, which will always work.

For the few original settings in the main `/etc/sysct.conf` file, the value is
also replaced so that running `sysctl -p` doesn't revert any change made by
puppet.

## Examples

Enable IP forwarding globally :
```puppet
sysctl { 'net.ipv4.ip_forward': value => '1' }
```

Set a value for maximum number of connections per UNIX socket :
```puppet
sysctl { 'net.core.somaxconn': value => '65536' }
```

Make sure we don't have any explicit value set for swappiness, typically
because it was set at some point but no longer needs to be. The original
value for existing nodes won't be reset until the next reboot :
```puppet
sysctl { 'vm.swappiness': ensure => absent }
```

If the order in which the files get applied is important, you can set it by
using a file name prefix, which could also be set globally from `site.pp` :
```puppet
Sysctl { prefix => '60' }
```

To enable purging of settings, you can use hiera to set the `sysctl::base`
`$purge` parameter :
```yaml
# sysctl
sysctl::base::purge: true
```
 
require 'rubygems'
require 'puppetlabs_spec_helper/rake_tasks'
require 'puppet-lint'
PuppetLint.configuration.send("disable_80chars")
PuppetLint.configuration.send("disable_autoloader_layout")
PuppetLint.configuration.send("disable_quoted_booleans")

# Class: sysctl::base
#
# Common part for the sysctl definition. Not meant to be used on its own.
#
class sysctl::base (
  $purge = false,
) {

  if $purge {
    $recurse = true
  } else {
    $recurse = false
  }

  file { '/etc/sysctl.d':
    ensure  => directory,
    owner   => 'root',
    group   => 'root',
    mode    => '0755',
    # Magic hidden here
    purge   => $purge,
    recurse => $recurse,
  }

}

# Define: sysctl
#
# Manage sysctl variable values.
#
# Parameters:
#  $value:
#    The value for the sysctl parameter. Mandatory, unless $ensure is 'absent'.
#  $prefix:
#    Optional prefix for the sysctl.d file to be created. Default: none.
#  $ensure:
#    Whether the variable's value should be 'present' or 'absent'.
#    Defaults to 'present'.
#
# Sample Usage :
#  sysctl { 'net.ipv6.bindv6only': value => '1' }
#
define sysctl (
  $value   = undef,
  $prefix  = undef,
  $comment = undef,
  $ensure  = undef,
) {

  include sysctl::base

  # If we have a prefix, then add the dash to it
  if $prefix {
    $sysctl_d_file = "${prefix}-${title}.conf"
  } else {
    $sysctl_d_file = "${title}.conf"
  }

  # The permanent change
  file { "/etc/sysctl.d/${sysctl_d_file}":
    ensure  => $ensure,
    owner   => 'root',
    group   => 'root',
    mode    => '0644',
    content => template("${module_name}/sysctl.d-file.erb"),
    notify  => [
      Exec["sysctl-${title}"],
      Exec["update-sysctl.conf-${title}"],
    ],
  }

  if $ensure != 'absent' {

    # The immediate change + re-check on each run "just in case"
    exec { "sysctl-${title}":
      command     => "/sbin/sysctl -p /etc/sysctl.d/${sysctl_d_file}",
      refreshonly => true,
      require     => File["/etc/sysctl.d/${sysctl_d_file}"],
    }

    # For the few original values from the main file
    exec { "update-sysctl.conf-${title}":
      command     => "sed -i -e 's/^${title} *=.*/${title} = ${value}/' /etc/sysctl.conf",
      path        => [ '/usr/sbin', '/sbin', '/usr/bin', '/bin' ],
      refreshonly => true,
      onlyif      => "grep -E '^${title} *=' /etc/sysctl.conf",
    }

  }

}

{
  "project_page": "https://github.com/thias/puppet-sysctl",
  "version": "0.3.0",
  "license": "Apache 2.0",
  "description": "Manage sysctl variable values.",
  "dependencies": [

  ],
  "types": [

  ],
  "name": "thias-sysctl",
  "author": "Matthias Saou",
  "summary": "Sysctl module",
  "source": "git://github.com/thias/puppet-sysctl",
  "checksums": {
    "tests/init.pp": "e70e5327b9840b44699bb7fae71d47cd",
    "spec/spec_helper.rb": "3ea886dd135e120afa31e0aab12e85b0",
    "ChangeLog": "ed8052eb5cb46b92eaa03b882c11779e",
    "LICENSE": "99219472697a01561e7630d63aaecdc1",
    "Modulefile": "3b8a6a0dfff841a31118a5f46fde59da",
    "spec/defines/sysctl_init_spec.rb": "21d524df70961750cb22f6b83349093e",
    "manifests/init.pp": "0f7dd893b08ebbbec8994d14eca6701b",
    "README.md": "ed4837849a1c4790b7178cd99824a204",
    "spec/classes/sysctl_base_spec.rb": "6241cf3e290871c00b1bb3bbd5490108",
    "templates/sysctl.d-file.erb": "0212783df32c499b3e9e343993f608da",
    "manifests/base.pp": "9508015ce74b5ce1420ad8c8ebc7d3af",
    "tests/base.pp": "1ba89838432dbc94339097327c19ae3d",
    "Gemfile": "3ad486d60d90bfe4395b368b95481e01",
    "Rakefile": "ab253b919e7093c2a5eb7adf0e39ffbc"
  }
}
require 'spec_helper'

describe 'sysctl::base', :type => :class do

  it { should create_class('sysctl::base') }
  it { should contain_file('/etc/sysctl.d') }

end

require 'spec_helper'

describe 'sysctl', :type => :define do
  let(:title) { 'net.ipv4.ip_forward'}

  context 'present' do
    let(:params) { { :value => '1' } }

    it { should contain_file('/etc/sysctl.d/net.ipv4.ip_forward.conf').with(
      :content  => "net.ipv4.ip_forward = 1\n",
      :ensure   => nil
    ) }

    it { should contain_exec('sysctl-net.ipv4.ip_forward') }
    it { should contain_exec('update-sysctl.conf-net.ipv4.ip_forward')}
  end

  context 'absent' do
    let(:params) { { :ensure  => 'absent' } }

    it { should contain_file('/etc/sysctl.d/net.ipv4.ip_forward.conf').with_ensure('absent') }
  end

end

require 'rubygems'
require 'puppetlabs_spec_helper/module_spec_helper'
<% if @comment -%>
<% @comment.each do |line| -%>
# <%= line %>
<% end -%>
<% end -%>
<%= @title %> = <%= @value %>
include sysctl::base
sysctl { 'net.ipv4.ip_forward': value => '1' }
sysctl { 'net.core.somaxconn': value => '65536' }
sysctl { 'vm.swappiness': ensure => absent }
branches:
  only:
    - master
language: ruby
bundler_args: --without development
script: "bundle exec rake spec SPEC_OPTS='--format documentation'"
after_success:
  - git clone -q git://github.com/puppetlabs/ghpublisher.git .forge-release
  - .forge-release/publish
rvm:
  - 1.8.7
  - 1.9.3
  - 2.0.0
env:
  matrix:
    - PUPPET_GEM_VERSION="~> 2.7.0"
    - PUPPET_GEM_VERSION="~> 3.3.0"
  global:
  - PUBLISHER_LOGIN=puppetlabs
  - secure: |-
      ZiIkYd9+CdPzpwSjFPnVkCx1FIlipxpbdyD33q94h2Tj5zXjNb1GXizVy0NR
      kVxGhU5Ld8y9z8DTqKRgCI1Yymg3H//OU++PKLOQj/X5juWVR4URBNPeBOzu
      IJBDl1MADKA4i1+jAZPpz4mTvTtKS4pWKErgCSmhSfsY1hs7n6c=
matrix:
  exclude:
    - rvm: 1.9.3
      env: PUPPET_GEM_VERSION="~> 2.7.0"
    - rvm: 2.0.0
      env: PUPPET_GEM_VERSION="~> 2.7.0"
notifications:
  email: false
2013-11-13 - Version 0.2.0

Summary:

This release mainly focuses on a number of bugfixes, which should
significantly improve the reliability of Git and SVN.  Thanks to
our many contributors for all of these fixes!

Features:
- Git:
 - Add autorequire for Package['git']
- HG:
 - Allow user and identity properties.
- Bzr:
 - "ensure => latest" support.
- SVN:
 - Added configuration parameter.
 - Add support for master svn repositories.
- CVS:
 - Allow for setting the CVS_RSH environment variable.

Fixes:
- Handle Puppet::Util[::Execution].withenv for 2.x and 3.x properly.
- Change path_empty? to not do full directory listing.
- Overhaul spec tests to work with rspec2.
- Git:
 - Improve Git SSH usage documentation.
 - Add ssh session timeouts to prevent network issues from blocking runs.
 - Fix git provider checkout of a remote ref on an existing repo.
 - Allow unlimited submodules (thanks to --recursive).
 - Use git checkout --force instead of short -f everywhere.
 - Update git provider to handle checking out into an existing (empty) dir.
- SVN:
 - Handle force property. for svn.
 - Adds support for changing upstream repo url.
 - Check that the URL of the WC matches the URL from the manifest.
 - Changed from using "update" to "switch".
 - Handle revision update without source switch.
 - Fix svn provider to look for '^Revision:' instead of '^Last Changed Rev:'.
- CVS:
 - Documented the "module" attribute.
source 'https://rubygems.org'

group :development, :test do
  gem 'rake',                    :require => false
  gem 'rspec-puppet',            :require => false
  gem 'puppetlabs_spec_helper',  :require => false
  gem 'rspec-system',            :require => false
  gem 'rspec-system-puppet',     :require => false
  gem 'rspec-system-serverspec', :require => false
  gem 'serverspec',              :require => false
  gem 'puppet-lint',             :require => false
  gem 'pry',                     :require => false
  gem 'simplecov',               :require => false
end

if puppetversion = ENV['PUPPET_GEM_VERSION']
  gem 'puppet', puppetversion, :require => false
else
  gem 'puppet', :require => false
end

# vim:ft=ruby
Copyright (C) 2010-2012 Puppet Labs Inc.

Puppet Labs can be contacted at: info@puppetlabs.com

This program and entire repository is free software; you can
redistribute it and/or modify it under the terms of the GNU
General Public License as published by the Free Software
Foundation; either version 2 of the License, or any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
name 'puppetlabs/vcsrepo'
version '0.2.0'
summary 'Manage repositories from various version control systems'
description 'Manage repositories from various version control systems'
Using vcsrepo with Bazaar
=========================

To create a blank repository

Define a `vcsrepo` without a `source` or `revision`:

    vcsrepo { "/path/to/repo":
      ensure   => present,
      provider => bzr
    }

To branch from an existing repository

Provide the `source` location:

    vcsrepo { "/path/to/repo":
        ensure   => present,
        provider => bzr,
        source   => 'lp:myproj'
    }

For a specific revision, use `revision` with a valid revisionspec
(see `bzr help revisionspec` for more information on formatting a revision):

    vcsrepo { "/path/to/repo":
        ensure   => present,
        provider => bzr,
        source   => 'lp:myproj',
        revision => 'menesis@pov.lt-20100309191856-4wmfqzc803fj300x'
    }

For sources that use SSH (eg, `bzr+ssh://...`, `sftp://...`)

Manage your SSH keys with Puppet and use `require` in your `vcsrepo`
to ensure they are present.  For more information, see the `require`
metaparameter documentation[1].

More Examples

For examples you can run, see `examples/bzr/`

[1]: http://docs.puppetlabs.com/references/stable/metaparameter.html#require
Using vcsrepo with CVS
======================

To create a blank repository

Define a `vcsrepo` without a `source` or `revision`:

    vcsrepo { "/path/to/repo":
      ensure => present,
      provider => cvs
    }

To checkout/update from a repository

To get the current mainline:

    vcsrepo { "/path/to/workspace":
        ensure => present,
        provider => cvs,
        source => ":pserver:anonymous@example.com:/sources/myproj"
    }
    
To get a specific module on the current mainline:

    vcsrepo {"/vagrant/lockss-daemon-source":
        ensure   => present,
        provider => cvs,
        source   => ":pserver:anonymous@lockss.cvs.sourceforge.net:/cvsroot/lockss",
        module   => "lockss-daemon",
    }


You can use the `compression` parameter (it works like CVS `-z`):

    vcsrepo { "/path/to/workspace":
        ensure => present,
        provider => cvs,
        compression => 3,
        source => ":pserver:anonymous@example.com:/sources/myproj"
    }

For a specific tag, use `revision`:

    vcsrepo { "/path/to/workspace":
        ensure => present,
        provider => cvs,
        compression => 3,
        source => ":pserver:anonymous@example.com:/sources/myproj",
        revision => "SOMETAG"
    }

For sources that use SSH

Manage your SSH keys with Puppet and use `require` in your `vcsrepo`
to ensure they are present.  For more information, see the `require`
metaparameter documentation[1].

More Examples

For examples you can run, see `examples/cvs/`

[1]: http://docs.puppetlabs.com/references/stable/metaparameter.html#require
Using vcsrepo with Git
======================

To create a blank repository

Define a `vcsrepo` without a `source` or `revision`:

    vcsrepo { "/path/to/repo":
      ensure => present,
      provider => git
    }

If you're defining this for a central/"official" repository, you'll
probably want to make it a "bare" repository.  Do this by setting
`ensure` to `bare` instead of `present`:

    vcsrepo { "/path/to/repo":
        ensure => bare,
        provider => git
    }

To clone/pull a repository

To get the current [master] HEAD:

    vcsrepo { "/path/to/repo":
        ensure => present,
        provider => git,
        source => "git://example.com/repo.git"
    }

For a specific revision or branch (can be a commit SHA, tag or branch name):

    vcsrepo { "/path/to/repo":
        ensure => present,
        provider => git,
        source => 'git://example.com/repo.git',
        revision => '0c466b8a5a45f6cd7de82c08df2fb4ce1e920a31'
    }

    vcsrepo { "/path/to/repo":
        ensure => present,
        provider => git,
        source => 'git://example.com/repo.git',
        revision => '1.1.2rc1'
    }

    vcsrepo { "/path/to/repo":
        ensure => present,
        provider => git,
        source => 'git://example.com/repo.git',
        revision => 'development'
    }

Check out as a user:

    vcsrepo { "/path/to/repo":
        ensure => present,
        provider => git,
        source => 'git://example.com/repo.git',
        revision => '0c466b8a5a45f6cd7de82c08df2fb4ce1e920a31',
        user => 'someUser'
    }

Keep the repository at the latest revision (note: this will always overwrite local changes to the repository):

    vcsrepo { "/path/to/repo":
        ensure => latest,
        provider => git,
        source => 'git://example.com/repo.git',
        revision => 'master',
    }

For sources that use SSH (eg, `username@server:...`)

If your SSH key is associated with a user, simply fill the `user` parameter to use his keys.

Example:

    user => 'toto'  # will use toto's $HOME/.ssh setup


Otherwise, manage your SSH keys with Puppet and use `require` in your `vcsrepo` to ensure they are present.
For more information, see the `require` metaparameter documentation[1].

More Examples

For examples you can run, see `examples/git/`

[1]: http://docs.puppetlabs.com/references/stable/metaparameter.html#require

Using vcsrepo with Mercurial
============================

To create a blank repository

Define a `vcsrepo` without a `source` or `revision`:

    vcsrepo { "/path/to/repo":
      ensure   => present,
      provider => hg
    }

To clone/pull & update a repository

To get the default branch tip:

    vcsrepo { "/path/to/repo":
        ensure   => present,
        provider => hg,
        source   => "http://hg.example.com/myrepo"
    }

For a specific changeset, use `revision`:

    vcsrepo { "/path/to/repo":
        ensure   => present,
        provider => hg,
        source   => "http://hg.example.com/myrepo",
        revision => '21ea4598c962'
    }

You can also set `revision` to a tag:

    vcsrepo { "/path/to/repo":
        ensure   => present,
        provider => hg,
        source   => "http://hg.example.com/myrepo",
        revision => '1.1.2'
    }

Check out as a user:

    vcsrepo { "/path/to/repo":
        ensure   => present,
        provider => hg,
        source   => "http://hg.example.com/myrepo",
        user     => 'user'
    }

Specify an SSH identity key:

    vcsrepo { "/path/to/repo":
        ensure   => present,
        provider => hg,
        source   => "ssh://hg@hg.example.com/myrepo",
        identity => "/home/user/.ssh/id_dsa,
    }

For sources that use SSH (eg, `ssh://...`)

Manage your SSH keys with Puppet and use `require` in your `vcsrepo`
to ensure they are present.  For more information, see the `require`
metaparameter documentation[1].

More Examples

For examples you can run, see `examples/hg/`

[1]: http://docs.puppetlabs.com/references/stable/metaparameter.html#require
Using vcsrepo with Subversion
=============================

To create a blank repository

To create a blank repository suitable for use as a central repository,
define a `vcsrepo` without a `source` or `revision`:

    vcsrepo { "/path/to/repo":
      ensure   => present,
      provider => svn
    }

To checkout from a repository

Provide a `source` qualified to the branch/tag you want:

    vcsrepo { "/path/to/repo":
        ensure   => present,
        provider => svn,
        source   => "svn://svnrepo/hello/branches/foo"
    }

You can provide a specific `revision`:

    vcsrepo { "/path/to/repo":
        ensure   => present,
        provider => svn,
        source   => "svn://svnrepo/hello/branches/foo",
        revision => '1234'
    }


Using a specified Subversion configuration directory 

Provide a `configuration` parameter which should be a directory path on the local system where your svn configuration
files are.  Typically, it is /path/to/.subversion:

    vcsrepo { "/path/to/repo":
        ensure        => present,
        provider      => svn,
        source        => "svn://svnrepo/hello/branches/foo",
        configuration => "/path/to/.subversion"
    }


For sources that use SSH (eg, `svn+ssh://...`)

Manage your SSH keys with Puppet and use `require` in your `vcsrepo`
to ensure they are present.  For more information, see the `require`
metaparameter documentation[1].

More Examples

For examples you can run, see `examples/svn/`

[1]: http://docs.puppetlabs.com/references/stable/metaparameter.html#require
vcsrepo
=======

[![Build Status](https://travis-ci.org/puppetlabs/puppetlabs-vcsrepo.png?branch=master)](https://travis-ci.org/puppetlabs/puppetlabs-vcsrepo)

Purpose

This provides a single type, `vcsrepo`.

This type can be used to describe:

* A working copy checked out from a (remote or local) source, at an
  arbitrary revision
* A "blank" working copy not associated with a source (when it makes
  sense for the VCS being used)
* A "blank" central repository (when the distinction makes sense for the VCS
  being used)

Supported Version Control Systems

This module supports a wide range of VCS types, each represented by a
separate provider.

For information on how to use this module with a specific VCS, see
`README.<VCS>.markdown`.

License

See LICENSE.
require 'puppetlabs_spec_helper/rake_tasks'
vcsrepo { '/tmp/vcstest-bzr-branch':
  ensure   => present,
  provider => bzr,
  source   => 'lp:do',
  revision => '1312',
}
vcsrepo { '/tmp/vcstest-bzr-init':
  ensure   => present,
  provider => bzr,
}
vcsrepo { '/tmp/vcstest-cvs-repo':
  ensure   => present,
  provider => cvs,
}

vcsrepo { '/tmp/vcstest-cvs-workspace-local':
  ensure   => present,
  provider => cvs,
  source   => '/tmp/vcstest-cvs-repo',
  require  => Vcsrepo['/tmp/vcstest-cvs-repo'],
}
vcsrepo { '/tmp/vcstest-cvs-workspace-remote':
  ensure   => present,
  provider => cvs,
  source   => ':pserver:anonymous@cvs.sv.gnu.org:/sources/leetcvrt',
}
vcsrepo { '/tmp/vcstest-git-bare':
  ensure   => bare,
  provider => git,
}
vcsrepo { '/tmp/vcstest-git-clone':
  ensure   => present,
  provider => git,
  source   => 'git://github.com/bruce/rtex.git',
}
vcsrepo { '/tmp/vcstest-git-wc':
  ensure   => present,
  provider => git,
}
vcsrepo { '/tmp/vcstest-hg-clone':
  ensure   => present,
  provider => hg,
  source   => 'http://hg.basho.com/riak',
  revision => 'riak-0.5.3',
}
vcsrepo { '/tmp/vcstest-hg-init':
  ensure   => present,
  provider => hg,
}
vcsrepo { '/tmp/vcstest-svn-checkout':
  ensure   => present,
  provider => svn,
  source   => 'http://svn.edgewall.org/repos/babel/trunk',
}
vcsrepo { '/tmp/vcstest-svn-server':
  ensure   => present,
  provider => svn,
}
require 'tmpdir'
require 'digest/md5'
require 'fileutils'

# Abstract
class Puppet::Provider::Vcsrepo < Puppet::Provider

  private

  def set_ownership
    owner = @resource.value(:owner) || nil
    group = @resource.value(:group) || nil
    FileUtils.chown_R(owner, group, @resource.value(:path))
  end

  def path_exists?
    File.directory?(@resource.value(:path))
  end

  def path_empty?
    # Path is empty if the only entries are '.' and '..'
    d = Dir.new(@resource.value(:path))
    d.read # should return '.'
    d.read # should return '..'
    d.read.nil?
  end

  # Note: We don't rely on Dir.chdir's behavior of automatically returning the
  # value of the last statement -- for easier stubbing.
  def at_path(&block) #:nodoc:
    value = nil
    Dir.chdir(@resource.value(:path)) do
      value = yield
    end
    value
  end

  def tempdir
    @tempdir ||= File.join(Dir.tmpdir, 'vcsrepo-' + Digest::MD5.hexdigest(@resource.value(:path)))
  end

end
require File.join(File.dirname(__FILE__), '..', 'vcsrepo')

Puppet::Type.type(:vcsrepo).provide(:bzr, :parent => Puppet::Provider::Vcsrepo) do
  desc "Supports Bazaar repositories"

  optional_commands   :bzr => 'bzr'
  has_features :reference_tracking

  def create
    if !@resource.value(:source)
      create_repository(@resource.value(:path))
    else
      clone_repository(@resource.value(:revision))
    end
  end

  def working_copy_exists?
    File.directory?(File.join(@resource.value(:path), '.bzr'))
  end

  def exists?
    working_copy_exists?
  end

  def destroy
    FileUtils.rm_rf(@resource.value(:path))
  end

  def revision
    at_path do
      current_revid = bzr('version-info')[/^revision-id:\s+(\S+)/, 1]
      desired = @resource.value(:revision)
      begin
        desired_revid = bzr('revision-info', desired).strip.split(/\s+/).last
      rescue Puppet::ExecutionFailure
        # Possible revid available during update (but definitely not current)
        desired_revid = nil
      end
      if current_revid == desired_revid
        desired
      else
        current_revid
      end
    end
  end

  def revision=(desired)
    at_path do
      begin
        bzr('update', '-r', desired)
      rescue Puppet::ExecutionFailure
        bzr('update', '-r', desired, ':parent')
      end
    end
  end

  def latest
    at_path do
      bzr('version-info', ':parent')[/^revision-id:\s+(\S+)/, 1]
    end
  end

  def latest?
    at_path do
      return self.revision == self.latest
    end
  end

  private

  def create_repository(path)
    bzr('init', path)
  end

  def clone_repository(revision)
    args = ['branch']
    if revision
      args.push('-r', revision)
    end
    args.push(@resource.value(:source),
              @resource.value(:path))
    bzr(*args)
  end

end
require File.join(File.dirname(__FILE__), '..', 'vcsrepo')

Puppet::Type.type(:vcsrepo).provide(:cvs, :parent => Puppet::Provider::Vcsrepo) do
  desc "Supports CVS repositories/workspaces"

  optional_commands   :cvs => 'cvs'
  has_features :gzip_compression, :reference_tracking, :modules, :cvs_rsh

  def create
    if !@resource.value(:source)
      create_repository(@resource.value(:path))
    else
      checkout_repository
    end
    update_owner
  end

  def exists?
    if @resource.value(:source)
      directory = File.join(@resource.value(:path), 'CVS')
    else
      directory = File.join(@resource.value(:path), 'CVSROOT')
    end
    File.directory?(directory)
  end

  def working_copy_exists?
    File.directory?(File.join(@resource.value(:path), 'CVS'))
  end

  def destroy
    FileUtils.rm_rf(@resource.value(:path))
  end

  def latest?
    debug "Checking for updates because 'ensure => latest'"
    at_path do
      # We cannot use -P to prune empty dirs, otherwise
      # CVS would report those as "missing", regardless
      # if they have contents or updates.
      is_current = (runcvs('-nq', 'update', '-d').strip == "")
      if (!is_current) then debug "There are updates available on the checkout's current branch/tag." end
      return is_current
    end
  end

  def latest
    # CVS does not have a conecpt like commit-IDs or change
    # sets, so we can only have the current branch name (or the
    # requested one, if that differs) as the "latest" revision.
    should = @resource.value(:revision)
    current = self.revision
    return should != current ? should : current
  end

  def revision
    if !@rev
      if File.exist?(tag_file)
        contents = File.read(tag_file).strip
        # Note: Doesn't differentiate between N and T entries
        @rev = contents[1..-1]
      else
        @rev = 'HEAD'
      end
      debug "Checkout is on branch/tag '#{@rev}'"
    end
    return @rev
  end

  def revision=(desired)
    at_path do
      runcvs('update', '-dr', desired, '.')
      update_owner
      @rev = desired
    end
  end

  private

  def tag_file
    File.join(@resource.value(:path), 'CVS', 'Tag')
  end

  def checkout_repository
    dirname, basename = File.split(@resource.value(:path))
    Dir.chdir(dirname) do
      args = ['-d', @resource.value(:source)]
      if @resource.value(:compression)
        args.push('-z', @resource.value(:compression))
      end
      args.push('checkout')
      if @resource.value(:revision)
        args.push('-r', @resource.value(:revision))
      end
      args.push('-d', basename, module_name)
      runcvs(*args)
    end
  end

  # When the source:
  # * Starts with ':' (eg, :pserver:...)
  def module_name
    if (m = @resource.value(:module))
      m
    elsif (source = @resource.value(:source))
      source[0, 1] == ':' ? File.basename(source) : '.'
    end
  end

  def create_repository(path)
    runcvs('-d', path, 'init')
  end

  def update_owner
    if @resource.value(:owner) or @resource.value(:group)
      set_ownership
    end
  end

  def runcvs(*args)
    if @resource.value(:cvs_rsh)
      debug "Using CVS_RSH = " + @resource.value(:cvs_rsh)
      e = { :CVS_RSH => @resource.value(:cvs_rsh) }
    else
      e = {}
    end

    # The location of withenv changed from Puppet 2.x to 3.x
    withenv = Puppet::Util.method(:withenv) if Puppet::Util.respond_to?(:withenv)
    withenv = Puppet::Util::Execution.method(:withenv) if Puppet::Util::Execution.respond_to?(:withenv)
    fail("Cannot set custom environment #{e}") if e && !withenv

    withenv.call e do
      Puppet.debug cvs *args
    end
  end
end
require File.join(File.dirname(__FILE__), '..', 'vcsrepo')

Puppet::Type.type(:vcsrepo).provide(:dummy, :parent => Puppet::Provider::Vcsrepo) do
  desc "Dummy default provider"

  defaultfor :vcsrepo => :dummy

  def working_copy_exists?
    providers = @resource.class.providers.map{|x| x.to_s}.sort.reject{|x| x == "dummy"}.join(", ") rescue "none"
    raise("vcsrepo resource must have a provider, available: #{providers}")
  end
end
require File.join(File.dirname(__FILE__), '..', 'vcsrepo')

Puppet::Type.type(:vcsrepo).provide(:git, :parent => Puppet::Provider::Vcsrepo) do
  desc "Supports Git repositories"

  ##TODO modify the commands below so that the su - is included
  optional_commands :git => 'git',
                    :su  => 'su'
  has_features :bare_repositories, :reference_tracking, :ssh_identity, :multiple_remotes, :user

  def create
    if !@resource.value(:source)
      init_repository(@resource.value(:path))
    else
      clone_repository(@resource.value(:source), @resource.value(:path))
      if @resource.value(:revision)
        if @resource.value(:ensure) == :bare
          notice "Ignoring revision for bare repository"
        else
          checkout
        end
      end
      if @resource.value(:ensure) != :bare
        update_submodules
      end
    end
    update_owner_and_excludes
  end

  def destroy
    FileUtils.rm_rf(@resource.value(:path))
  end

  def latest?
    at_path do
      return self.revision == self.latest
    end
  end

  def latest
    branch = on_branch?
    if branch == 'master'
      return get_revision("#{@resource.value(:remote)}/HEAD")
    elsif branch == '(no branch)'
      return get_revision('HEAD')
    else
      return get_revision("#{@resource.value(:remote)}/%s" % branch)
    end
  end

  def revision
    update_references
    current = at_path { git_with_identity('rev-parse', 'HEAD').chomp }
    return current unless @resource.value(:revision)

    if tag_revision?(@resource.value(:revision))
      canonical = at_path { git_with_identity('show', @resource.value(:revision)).scan(/^commit (.*)/).to_s }
    else
      # if it's not a tag, look for it as a local ref
      canonical = at_path { git_with_identity('rev-parse', '--revs-only', @resource.value(:revision)).chomp }
      if canonical.empty?
        # git rev-parse executed properly but didn't find the ref;
        # look for it in the remote
        remote_ref = at_path { git_with_identity('ls-remote', '--heads', '--tags', @resource.value(:remote), @resource.value(:revision)).chomp }
        if remote_ref.empty?
          fail("#{@resource.value(:revision)} is not a local or remote ref")
        end

        # $ git ls-remote --heads --tags origin feature/cvs
        # 7d4244b35e72904e30130cad6d2258f901c16f1a	refs/heads/feature/cvs
        canonical = remote_ref.split.first
      end
    end

    if current == canonical
      @resource.value(:revision)
    else
      current
    end
  end

  def revision=(desired)
    checkout(desired)
    if local_branch_revision?(desired)
      # reset instead of pull to avoid merge conflicts. assuming remote is
      # authoritative.
      # might be worthwhile to have an allow_local_changes param to decide
      # whether to reset or pull when we're ensuring latest.
      at_path { git_with_identity('reset', '--hard', "#{@resource.value(:remote)}/#{desired}") }
    end
    if @resource.value(:ensure) != :bare
      update_submodules
    end
    update_owner_and_excludes
  end

  def bare_exists?
    bare_git_config_exists? && !working_copy_exists?
  end

  def working_copy_exists?
    File.directory?(File.join(@resource.value(:path), '.git'))
  end

  def exists?
    working_copy_exists? || bare_exists?
  end

  def update_remote_origin_url
    current = git_with_identity('config', 'remote.origin.url')
    unless @resource.value(:source).nil?
      if current.nil? or current.strip != @resource.value(:source)
        git_with_identity('config', 'remote.origin.url', @resource.value(:source))
      end
    end
  end

  def update_references
    at_path do
      update_remote_origin_url
      git_with_identity('fetch', @resource.value(:remote))
      git_with_identity('fetch', '--tags', @resource.value(:remote))
      update_owner_and_excludes
    end
  end

  private

  def bare_git_config_exists?
    File.exist?(File.join(@resource.value(:path), 'config'))
  end

  def clone_repository(source, path)
    check_force
    args = ['clone']
    if @resource.value(:ensure) == :bare
      args << '--bare'
    end
    if !File.exist?(File.join(@resource.value(:path), '.git'))
      args.push(source, path)
      Dir.chdir("/") do
        git_with_identity(*args)
      end
    else
      notice "Repo has already been cloned"
    end
  end

  def check_force
    if path_exists? and not path_empty?
      if @resource.value(:force)
        notice "Removing %s to replace with vcsrepo." % @resource.value(:path)
        destroy
      else
        raise Puppet::Error, "Could not create repository (non-repository at path)"
      end
    end
  end

  def init_repository(path)
    check_force
    if @resource.value(:ensure) == :bare && working_copy_exists?
      convert_working_copy_to_bare
    elsif @resource.value(:ensure) == :present && bare_exists?
      convert_bare_to_working_copy
    else
      # normal init
      FileUtils.mkdir(@resource.value(:path))
      FileUtils.chown(@resource.value(:user), nil, @resource.value(:path)) if @resource.value(:user)
      args = ['init']
      if @resource.value(:ensure) == :bare
        args << '--bare'
      end
      at_path do
        git_with_identity(*args)
      end
    end
  end

  # Convert working copy to bare
  #
  # Moves:
  #   <path>/.git
  # to:
  #   <path>/
  def convert_working_copy_to_bare
    notice "Converting working copy repository to bare repository"
    FileUtils.mv(File.join(@resource.value(:path), '.git'), tempdir)
    FileUtils.rm_rf(@resource.value(:path))
    FileUtils.mv(tempdir, @resource.value(:path))
  end

  # Convert bare to working copy
  #
  # Moves:
  #   <path>/
  # to:
  #   <path>/.git
  def convert_bare_to_working_copy
    notice "Converting bare repository to working copy repository"
    FileUtils.mv(@resource.value(:path), tempdir)
    FileUtils.mkdir(@resource.value(:path))
    FileUtils.mv(tempdir, File.join(@resource.value(:path), '.git'))
    if commits_in?(File.join(@resource.value(:path), '.git'))
      reset('HEAD')
      git_with_identity('checkout', '--force')
      update_owner_and_excludes
    end
  end

  def commits_in?(dot_git)
    Dir.glob(File.join(dot_git, 'objects/info/*'), File::FNM_DOTMATCH) do |e|
      return true unless %w(. ..).include?(File::basename(e))
    end
    false
  end

  def checkout(revision = @resource.value(:revision))
    if !local_branch_revision? && remote_branch_revision?
      at_path { git_with_identity('checkout', '-b', revision, '--track', "#{@resource.value(:remote)}/#{revision}") }
    else
      at_path { git_with_identity('checkout', '--force', revision) }
    end
  end

  def reset(desired)
    at_path do
      git_with_identity('reset', '--hard', desired)
    end
  end

  def update_submodules
    at_path do
      git_with_identity('submodule', 'update', '--init', '--recursive')
    end
  end

  def remote_branch_revision?(revision = @resource.value(:revision))
    # git < 1.6 returns '#{@resource.value(:remote)}/#{revision}'
    # git 1.6+ returns 'remotes/#{@resource.value(:remote)}/#{revision}'
    branch = at_path { branches.grep /(remotes\/)?#{@resource.value(:remote)}\/#{revision}/ }
    branch unless branch.empty?
  end

  def local_branch_revision?(revision = @resource.value(:revision))
    at_path { branches.include?(revision) }
  end

  def tag_revision?(revision = @resource.value(:revision))
    at_path { tags.include?(revision) }
  end

  def branches
    at_path { git_with_identity('branch', '-a') }.gsub('*', ' ').split(/\n/).map { |line| line.strip }
  end

  def on_branch?
    at_path { git_with_identity('branch', '-a') }.split(/\n/).grep(/\*/).first.to_s.gsub('*', '').strip
  end

  def tags
    at_path { git_with_identity('tag', '-l') }.split(/\n/).map { |line| line.strip }
  end

  def set_excludes
    at_path { open('.git/info/exclude', 'w') { |f| @resource.value(:excludes).each { |ex| f.write(ex + "\n") }}}
  end

  def get_revision(rev)
    if !working_copy_exists?
      create
    end
    at_path do
      update_remote_origin_url
      git_with_identity('fetch', @resource.value(:remote))
      git_with_identity('fetch', '--tags', @resource.value(:remote))
    end
    current = at_path { git_with_identity('rev-parse', rev).strip }
    if @resource.value(:revision)
      if local_branch_revision?
        canonical = at_path { git_with_identity('rev-parse', @resource.value(:revision)).strip }
      elsif remote_branch_revision?
        canonical = at_path { git_with_identity('rev-parse', "#{@resource.value(:remote)}/" + @resource.value(:revision)).strip }
      end
      current = @resource.value(:revision) if current == canonical
    end
    update_owner_and_excludes
    return current
  end

  def update_owner_and_excludes
    if @resource.value(:owner) or @resource.value(:group)
      set_ownership
    end
    if @resource.value(:excludes)
      set_excludes
    end
  end

  def git_with_identity(*args)
    if @resource.value(:identity)
      Tempfile.open('git-helper') do |f|
        f.puts '#!/bin/sh'
        f.puts "exec ssh -oStrictHostKeyChecking=no -oPasswordAuthentication=no -oKbdInteractiveAuthentication=no -oChallengeResponseAuthentication=no -oConnectTimeout=120 -i #{@resource.value(:identity)} $*"
        f.close

        FileUtils.chmod(0755, f.path)
        env_save = ENV['GIT_SSH']
        ENV['GIT_SSH'] = f.path

        ret = git(*args)

        ENV['GIT_SSH'] = env_save

        return ret
      end
    elsif @resource.value(:user)
      su(@resource.value(:user), '-c', "git #{args.join(' ')}" )
    else
      git(*args)
    end
  end
end
require File.join(File.dirname(__FILE__), '..', 'vcsrepo')

Puppet::Type.type(:vcsrepo).provide(:hg, :parent => Puppet::Provider::Vcsrepo) do
  desc "Supports Mercurial repositories"

  optional_commands :hg => 'hg',
                    :su => 'su'
  has_features :reference_tracking, :ssh_identity, :user

  def create
    if !@resource.value(:source)
      create_repository(@resource.value(:path))
    else
      clone_repository(@resource.value(:revision))
    end
    update_owner
  end

  def working_copy_exists?
    File.directory?(File.join(@resource.value(:path), '.hg'))
  end

  def exists?
    working_copy_exists?
  end

  def destroy
    FileUtils.rm_rf(@resource.value(:path))
  end

  def latest?
    at_path do
      return self.revision == self.latest
    end
  end

  def latest
    at_path do
      begin
        hg_wrapper('incoming', '--branch', '.', '--newest-first', '--limit', '1')[/^changeset:\s+(?:-?\d+):(\S+)/m, 1]
      rescue Puppet::ExecutionFailure
        # If there are no new changesets, return the current nodeid
        self.revision
      end
    end
  end

  def revision
    at_path do
      current = hg_wrapper('parents')[/^changeset:\s+(?:-?\d+):(\S+)/m, 1]
      desired = @resource.value(:revision)
      if desired
        # Return the tag name if it maps to the current nodeid
        mapped = hg_wrapper('tags')[/^#{Regexp.quote(desired)}\s+\d+:(\S+)/m, 1]
        if current == mapped
          desired
        else
          current
        end
      else
        current
      end
    end
  end

  def revision=(desired)
    at_path do
      begin
        hg_wrapper('pull')
      rescue
      end
      begin
        hg_wrapper('merge')
      rescue Puppet::ExecutionFailure
        # If there's nothing to merge, just skip
      end
      hg_wrapper('update', '--clean', '-r', desired)
    end
    update_owner
  end

  private

  def create_repository(path)
    hg_wrapper('init', path)
  end

  def clone_repository(revision)
    args = ['clone']
    if revision
      args.push('-u', revision)
    end
    args.push(@resource.value(:source),
              @resource.value(:path))
    hg_wrapper(*args)
  end

  def update_owner
    if @resource.value(:owner) or @resource.value(:group)
      set_ownership
    end
  end

  def hg_wrapper(*args)
    if @resource.value(:identity)
      args += ["--ssh", "ssh -oStrictHostKeyChecking=no -oPasswordAuthentication=no -oKbdInteractiveAuthentication=no -oChallengeResponseAuthentication=no -i #{@resource.value(:identity)}"]
    end
    if @resource.value(:user)
      args.map! { |a| if a =~ /\s/ then "'#{a}'" else a end }  # Adds quotes to arguments with whitespaces.
      su(@resource.value(:user), '-c', "hg #{args.join(' ')}")
    else
      hg(*args)
    end
  end
end
require File.join(File.dirname(__FILE__), '..', 'vcsrepo')

Puppet::Type.type(:vcsrepo).provide(:svn, :parent => Puppet::Provider::Vcsrepo) do
  desc "Supports Subversion repositories"

  optional_commands :svn      => 'svn',
                    :svnadmin => 'svnadmin',
                    :svnlook  => 'svnlook'

  has_features :filesystem_types, :reference_tracking, :basic_auth, :configuration

  def create
    if !@resource.value(:source)
      create_repository(@resource.value(:path))
    else
      checkout_repository(@resource.value(:source),
                          @resource.value(:path),
                          @resource.value(:revision))
    end
    update_owner
  end

  def working_copy_exists?
    if File.directory?(@resource.value(:path))
      # :path is an svn checkout
      return true if File.directory?(File.join(@resource.value(:path), '.svn'))
      # :path is an svn server
      return true if svnlook('uuid', @resource.value(:path))
    end
    false
  end

  def exists?
    working_copy_exists?
  end

  def destroy
    FileUtils.rm_rf(@resource.value(:path))
  end

  def latest?
    at_path do
      (self.revision >= self.latest) and (@resource.value(:source) == self.sourceurl)
    end
  end

  def buildargs
    args = ['--non-interactive']
    if @resource.value(:basic_auth_username) && @resource.value(:basic_auth_password)
      args.push('--username', @resource.value(:basic_auth_username))
      args.push('--password', @resource.value(:basic_auth_password))
      args.push('--no-auth-cache')
    end

    if @resource.value(:force)
      args.push('--force')
    end

    if @resource.value(:configuration)
      args.push('--config-dir', @resource.value(:configuration))
    end

    args
  end

  def latest
    args = buildargs.push('info', '-r', 'HEAD')
    at_path do
      svn(*args)[/^Revision:\s+(\d+)/m, 1]
    end
  end

  def sourceurl
    args = buildargs.push('info')
    at_path do
      svn(*args)[/^URL:\s+(\S+)/m, 1]
    end
  end

  def revision
    args = buildargs.push('info')
    at_path do
      svn(*args)[/^Revision:\s+(\d+)/m, 1]
    end
  end

  def revision=(desired)
    args = if @resource.value(:source)
             buildargs.push('switch', '-r', desired, @resource.value(:source))
           else
             buildargs.push('update', '-r', desired)
           end
    at_path do
      svn(*args)
    end
    update_owner
  end

  private

  def checkout_repository(source, path, revision)
    args = buildargs.push('checkout')
    if revision
      args.push('-r', revision)
    end
    args.push(source, path)
    svn(*args)
  end

  def create_repository(path)
    args = ['create']
    if @resource.value(:fstype)
      args.push('--fs-type', @resource.value(:fstype))
    end
    args << path
    svnadmin(*args)
  end

  def update_owner
    if @resource.value(:owner) or @resource.value(:group)
      set_ownership
    end
  end
end
require 'pathname'

Puppet::Type.newtype(:vcsrepo) do
  desc "A local version control repository"

  feature :gzip_compression,
          "The provider supports explicit GZip compression levels"
  feature :basic_auth,
          "The provider supports HTTP Basic Authentication"
  feature :bare_repositories,
          "The provider differentiates between bare repositories
          and those with working copies",
          :methods => [:bare_exists?, :working_copy_exists?]

  feature :filesystem_types,
          "The provider supports different filesystem types"

  feature :reference_tracking,
          "The provider supports tracking revision references that can change
           over time (eg, some VCS tags and branch names)"

  feature :ssh_identity,
          "The provider supports a configurable SSH identity file"

  feature :user,
          "The provider can run as a different user"

  feature :modules,
          "The repository contains modules that can be chosen of"

  feature :multiple_remotes,
          "The repository tracks multiple remote repositories"

  feature :configuration,
          "The configuration directory to use"

  feature :cvs_rsh,
          "The provider understands the CVS_RSH environment variable"

  ensurable do
    attr_accessor :latest

    def insync?(is)
      @should ||= []

      case should
      when :present
        return true unless [:absent, :purged, :held].include?(is)
      when :latest
        if is == :latest
          return true
        else
          return false
        end
      when :bare
        return is == :bare
      end
    end

    newvalue :present do
      notice "Creating repository from present"
      provider.create
    end

    newvalue :bare, :required_features => [:bare_repositories] do
      if !provider.exists?
        provider.create
      end
    end

    newvalue :absent do
      provider.destroy
    end

    newvalue :latest, :required_features => [:reference_tracking] do
      if provider.exists?
        if provider.respond_to?(:update_references)
          provider.update_references
        end
        if provider.respond_to?(:latest?)
            reference = provider.latest || provider.revision
        else
          reference = resource.value(:revision) || provider.revision
        end
        notice "Updating to latest '#{reference}' revision"
        provider.revision = reference
      else
        notice "Creating repository from latest"
        provider.create
      end
    end

    def retrieve
      prov = @resource.provider
      if prov
        if prov.working_copy_exists?
          (@should.include?(:latest) && prov.latest?) ? :latest : :present
        elsif prov.class.feature?(:bare_repositories) and prov.bare_exists?
          :bare
        else
          :absent
        end
      else
        raise Puppet::Error, "Could not find provider"
      end
    end

  end

  newparam :path do
    desc "Absolute path to repository"
    isnamevar
    validate do |value|
      path = Pathname.new(value)
      unless path.absolute?
        raise ArgumentError, "Path must be absolute: #{path}"
      end
    end
  end

  newparam :source do
    desc "The source URI for the repository"
  end

  newparam :fstype, :required_features => [:filesystem_types] do
    desc "Filesystem type"
  end

  newproperty :revision do
    desc "The revision of the repository"
    newvalue(/^\S+$/)
  end

  newparam :owner do
    desc "The user/uid that owns the repository files"
  end

  newparam :group do
    desc "The group/gid that owns the repository files"
  end

  newparam :user do
    desc "The user to run for repository operations"
  end

  newparam :excludes do
    desc "Files to be excluded from the repository"
  end

  newparam :force do
    desc "Force repository creation, destroying any files on the path in the process."
    newvalues(:true, :false)
    defaultto false
  end

  newparam :compression, :required_features => [:gzip_compression] do
    desc "Compression level"
    validate do |amount|
      unless Integer(amount).between?(0, 6)
        raise ArgumentError, "Unsupported compression level: #{amount} (expected 0-6)"
      end
    end
  end

  newparam :basic_auth_username, :required_features => [:basic_auth] do
    desc "HTTP Basic Auth username"
  end

  newparam :basic_auth_password, :required_features => [:basic_auth] do
    desc "HTTP Basic Auth password"
  end

  newparam :identity, :required_features => [:ssh_identity] do
    desc "SSH identity file"
  end

  newparam :module, :required_features => [:modules] do
    desc "The repository module to manage"
  end

  newparam :remote, :required_features => [:multiple_remotes] do
    desc "The remote repository to track"
    defaultto "origin"
  end

  newparam :configuration, :required_features => [:configuration]  do
    desc "The configuration directory to use"
  end

  newparam :cvs_rsh, :required_features => [:cvs_rsh] do
    desc "The value to be used for the CVS_RSH environment variable."
  end

  autorequire(:package) do
    ['git', 'git-core']
  end

end
revision-id: menesis@pov.lt-20100309191856-4wmfqzc803fj300x
date: 2010-03-09 21:18:56 +0200
build-date: 2010-03-14 00:42:43 -0800
revno: 2634
branch-nick: mytest
  feature/foo
  feature/bar
  feature/baz
  feature/quux
  only/local
* master
  refactor/foo
  origin/HEAD
  origin/feature/foo
  origin/feature/bar
  origin/feature/baz
  origin/feature/quux
  origin/only/remote
  origin/master
  feature/foo
* feature/bar
  feature/baz
  feature/quux
  only/local
  master
  refactor/foo
  origin/HEAD
  origin/feature/foo
  origin/feature/bar
  origin/feature/baz
  origin/feature/quux
  origin/only/remote
  origin/master
  feature/foo
  feature/bar
  feature/baz
  feature/quux
  only/local
  master
* (no branch)  
  refactor/foo
  origin/HEAD
  origin/feature/foo
  origin/feature/bar
  origin/feature/baz
  origin/feature/quux
  origin/only/remote
  origin/master
changeset:   3:34e6012c783a
parent:      2:21ea4598c962
parent:      1:9d0ff0028458
user:        Test User <test.user@example.com>
date:        Fri Aug 07 13:13:02 2009 -0400
summary:     merge
tip                             1019:bca3f20b249b
0.9.1                           1017:76ce7cca95d8
0.9                             1001:dbaa6f4ec585
0.8                              839:65b66ac0fc83
0.7.1                            702:e1357f00129f
0.7                              561:7b2af3b4c968
0.6.3                            486:e38077f4e4aa
0.6.2                            405:07bb099b7b10
0.6.1                            389:93750f3fbbe2
0.6                              369:34e6012c783a
0.5.3                            321:5ffa6ae7e699
0.5.2                            318:fdc2c2e4cebe
0.5.1                            315:33a5ea0cbe7a
0.5                              313:47490716f4c9
0.4                              240:47fa3a14cc63
0.3.1                            132:bc231db18e1c
0.3                              130:661615e510dd
0.2                               81:f98d13b442f6
Path: .
URL: http://example.com/svn/trunk
Repository Root: http://example.com/svn
Repository UUID: 75246ace-e253-0410-96dd-a7613ca8dc81
Revision: 4
Node Kind: directory
Schedule: normal
Last Changed Author: jon
Last Changed Rev: 3
Last Changed Date: 2008-08-07 11:34:25 -0700 (Thu, 07 Aug 2008)
s
mtime
require 'puppetlabs_spec_helper/module_spec_helper'
require 'simplecov'
require 'support/filesystem_helpers'
require 'support/fixture_helpers'

SimpleCov.start do
    add_filter "/spec/"
end

RSpec.configure do |c|
  c.include FilesystemHelpers
  c.include FixtureHelpers
end
module FilesystemHelpers

  def expects_chdir(path = resource.value(:path))
    Dir.expects(:chdir).with(path).at_least_once.yields
  end

  def expects_mkdir(path = resource.value(:path))
    Dir.expects(:mkdir).with(path).at_least_once
  end

  def expects_rm_rf(path = resource.value(:path))
    FileUtils.expects(:rm_rf).with(path)
  end

  def expects_directory?(returns = true, path = resource.value(:path))
    File.expects(:directory?).with(path).returns(returns)
  end
end
module FixtureHelpers

  def fixture(name, ext = '.txt')
    File.read(File.join(File.dirname(__FILE__), '..', 'fixtures', name.to_s + ext))
  end

end
require 'spec_helper'

describe Puppet::Type.type(:vcsrepo).provider(:bzr_provider) do

  let(:resource) { Puppet::Type.type(:vcsrepo).new({
    :name     => 'test',
    :ensure   => :present,
    :provider => :bzr,
    :revision => '2634',
    :source   => 'lp:do',
    :path     => '/tmp/test',
  })}

  let(:provider) { resource.provider }

  before :each do
    Puppet::Util.stubs(:which).with('bzr').returns('/usr/bin/bzr')
  end

  describe 'creating' do
    context 'with defaults' do
      it "should execute 'bzr clone -r' with the revision" do
        provider.expects(:bzr).with('branch', '-r', resource.value(:revision), resource.value(:source), resource.value(:path))
        provider.create
      end
    end

    context 'without revision' do
      it "should just execute 'bzr clone' without a revision" do
        resource.delete(:revision)
        provider.expects(:bzr).with('branch', resource.value(:source), resource.value(:path))
        provider.create
      end
    end

    context 'without source' do
      it "should execute 'bzr init'" do
        resource.delete(:source)
        provider.expects(:bzr).with('init', resource.value(:path))
        provider.create
      end
    end
  end

  describe 'destroying' do
    it "it should remove the directory" do
      provider.destroy
    end
  end

  describe "checking existence" do
    it "should check for the directory" do
      File.expects(:directory?).with(File.join(resource.value(:path), '.bzr')).returns(true)
      provider.exists?
    end
  end

  describe "checking the revision property" do
    before do
      expects_chdir
      provider.expects(:bzr).with('version-info').returns(File.read(fixtures('bzr_version_info.txt')))
      @current_revid = 'menesis@pov.lt-20100309191856-4wmfqzc803fj300x'
    end

    context "when given a non-revid as the resource revision" do
      context "when its revid is not different than the current revid" do
        it "should return the ref" do
          resource[:revision] = '2634'
          provider.expects(:bzr).with('revision-info', '2634').returns("2634 menesis@pov.lt-20100309191856-4wmfqzc803fj300x\n")
          provider.revision.should == resource.value(:revision)
        end
      end
      context "when its revid is different than the current revid" do
        it "should return the current revid" do
          resource[:revision] = '2636'
          provider.expects(:bzr).with('revision-info', resource.value(:revision)).returns("2635 foo\n")
          provider.revision.should == @current_revid
        end
      end
    end

    context "when given a revid as the resource revision" do
      context "when it is the same as the current revid" do
        it "should return it" do
          resource[:revision] = 'menesis@pov.lt-20100309191856-4wmfqzc803fj300x'
          provider.expects(:bzr).with('revision-info', resource.value(:revision)).returns("1234 #{resource.value(:revision)}\n")
          provider.revision.should == resource.value(:revision)
        end
      end
      context "when it is not the same as the current revid" do
        it "should return the current revid" do
          resource[:revision] = 'menesis@pov.lt-20100309191856-4wmfqzc803fj300y'
          provider.expects(:bzr).with('revision-info', resource.value(:revision)).returns("2636 foo\n")
          provider.revision.should == @current_revid
        end
      end

    end
  end

  describe "setting the revision property" do
    it "should use 'bzr update -r' with the revision" do
      Dir.expects(:chdir).with('/tmp/test').at_least_once.yields
      provider.expects(:bzr).with('update', '-r', 'somerev')
      provider.revision = 'somerev'
    end
  end

end
require 'spec_helper'

describe Puppet::Type.type(:vcsrepo).provider(:cvs_provider) do

  let(:resource) { Puppet::Type.type(:vcsrepo).new({
    :name     => 'test',
    :ensure   => :present,
    :provider => :cvs,
    :revision => '2634',
    :source   => 'lp:do',
    :path     => '/tmp/test',
  })}

  let(:provider) { resource.provider }

  before :each do
    Puppet::Util.stubs(:which).with('cvs').returns('/usr/bin/cvs')
  end

  describe 'creating' do
    context "with a source" do
      it "should execute 'cvs checkout'" do
        resource[:source] = ':ext:source@example.com:/foo/bar'
        resource[:revision] = 'an-unimportant-value'
        expects_chdir('/tmp')
        provider.expects(:cvs).with('-d', resource.value(:source), 'checkout', '-r', 'an-unimportant-value', '-d', 'test', 'bar')
        provider.create
      end

      it "should just execute 'cvs checkout' without a revision" do
        resource[:source] = ':ext:source@example.com:/foo/bar'
        resource.delete(:revision)
        provider.expects(:cvs).with('-d', resource.value(:source), 'checkout', '-d', File.basename(resource.value(:path)), File.basename(resource.value(:source)))
        provider.create
      end

      context "with a compression" do
        it "should just execute 'cvs checkout' without a revision" do
          resource[:source] = ':ext:source@example.com:/foo/bar'
          resource[:compression] = '3'
          resource.delete(:revision)
          provider.expects(:cvs).with('-d', resource.value(:source), '-z', '3', 'checkout', '-d', File.basename(resource.value(:path)), File.basename(resource.value(:source)))
          provider.create
        end
      end
    end

    context "when a source is not given" do
      it "should execute 'cvs init'" do
        resource.delete(:source)
        provider.expects(:cvs).with('-d', resource.value(:path), 'init')
        provider.create
      end
    end
  end

  describe 'destroying' do
    it "it should remove the directory" do
      provider.destroy
    end
  end

  describe "checking existence" do
    it "should check for the CVS directory with source" do
      resource[:source] = ':ext:source@example.com:/foo/bar'
      File.expects(:directory?).with(File.join(resource.value(:path), 'CVS'))
      provider.exists?
    end

    it "should check for the CVSROOT directory without source" do
      resource.delete(:source)
      File.expects(:directory?).with(File.join(resource.value(:path), 'CVSROOT'))
      provider.exists?
    end
  end

  describe "checking the revision property" do
    before do
      @tag_file = File.join(resource.value(:path), 'CVS', 'Tag')
    end

    context "when CVS/Tag exists" do
      before do
        @tag = 'TAG'
        File.expects(:exist?).with(@tag_file).returns(true)
      end
      it "should read CVS/Tag" do
        File.expects(:read).with(@tag_file).returns("T#{@tag}")
        provider.revision.should == @tag
      end
    end

    context "when CVS/Tag does not exist" do
      before do
        File.expects(:exist?).with(@tag_file).returns(false)
      end
      it "assumes HEAD" do
        provider.revision.should == 'HEAD'
      end
    end
  end

  describe "when setting the revision property" do
    before do
      @tag = 'SOMETAG'
    end

    it "should use 'cvs update -dr'" do
      expects_chdir
      provider.expects(:cvs).with('update', '-dr', @tag, '.')
      provider.revision = @tag
    end
  end

end
require 'spec_helper'

describe Puppet::Type.type(:vcsrepo).provider(:git_provider) do

  let(:resource) { Puppet::Type.type(:vcsrepo).new({
    :name     => 'test',
    :ensure   => :present,
    :provider => :git,
    :revision => '2634',
    :source   => 'git@repo',
    :path     => '/tmp/test',
  })}

  let(:provider) { resource.provider }

  before :each do
    Puppet::Util.stubs(:which).with('git').returns('/usr/bin/git')
  end

  context 'creating' do
    context "with a revision that is a remote branch" do
      it "should execute 'git clone' and 'git checkout -b'" do
        resource[:revision] = 'only/remote'
        Dir.expects(:chdir).with('/').at_least_once.yields
        Dir.expects(:chdir).with('/tmp/test').at_least_once.yields
        provider.expects(:git).with('clone', resource.value(:source), resource.value(:path))
        provider.expects(:update_submodules)
        provider.expects(:git).with('branch', '-a').returns(resource.value(:revision))
        provider.expects(:git).with('checkout', '--force', resource.value(:revision))
        provider.create
      end
    end

    context "with a revision that is not a remote branch" do
      it "should execute 'git clone' and 'git reset --hard'" do
        resource[:revision] = 'a-commit-or-tag'
        Dir.expects(:chdir).with('/').at_least_once.yields
        Dir.expects(:chdir).with('/tmp/test').at_least_once.yields
        provider.expects(:git).with('clone', resource.value(:source), resource.value(:path))
        provider.expects(:update_submodules)
        provider.expects(:git).with('branch', '-a').returns(resource.value(:revision))
        provider.expects(:git).with('checkout', '--force', resource.value(:revision))
        provider.create
      end

      it "should execute 'git clone' and submodule commands" do
        resource.delete(:revision)
        provider.expects(:git).with('clone', resource.value(:source), resource.value(:path))
        provider.expects(:update_submodules)
        provider.create
      end
    end

    context "with an ensure of bare" do
      context "with revision" do
        it "should just execute 'git clone --bare'" do
          resource[:ensure] = :bare
          provider.expects(:git).with('clone', '--bare', resource.value(:source), resource.value(:path))
          provider.create
        end
      end
      context "without revision" do
        it "should just execute 'git clone --bare'" do
          resource[:ensure] = :bare
          resource.delete(:revision)
          provider.expects(:git).with('clone', '--bare', resource.value(:source), resource.value(:path))
          provider.create
        end
      end
    end

    context "when a source is not given" do
      context "when the path does not exist" do
        it "should execute 'git init'" do
          resource[:ensure] = :present
          resource.delete(:source)
          expects_mkdir
          expects_chdir
          expects_directory?(false)

          provider.expects(:bare_exists?).returns(false)
          provider.expects(:git).with('init')
          provider.create
        end
      end

      context "when the path is a bare repository" do
        it "should convert it to a working copy" do
          resource[:ensure] = :present
          resource.delete(:source)
          provider.expects(:bare_exists?).returns(true)
          provider.expects(:convert_bare_to_working_copy)
          provider.create
        end
      end

      context "when the path is not empty and not a repository" do
        it "should raise an exception" do
          provider.expects(:path_exists?).returns(true)
          provider.expects(:path_empty?).returns(false)
          proc { provider.create }.should raise_error(Puppet::Error)
        end
      end
    end

    context "when the path does not exist" do
      it "should execute 'git init --bare'" do
        resource[:ensure] = :bare
        resource.delete(:source)
        expects_chdir
        expects_mkdir
        expects_directory?(false)
        provider.expects(:working_copy_exists?).returns(false)
        provider.expects(:git).with('init', '--bare')
        provider.create
      end
    end

    context "when the path is a working copy repository" do
      it "should convert it to a bare repository" do
        resource[:ensure] = :bare
        resource.delete(:source)
        provider.expects(:working_copy_exists?).returns(true)
        provider.expects(:convert_working_copy_to_bare)
        provider.create
      end
    end

    context "when the path is not empty and not a repository" do
      it "should raise an exception" do
        expects_directory?(true)
        provider.expects(:path_empty?).returns(false)
        proc { provider.create }.should raise_error(Puppet::Error)
      end
    end
  end


  context 'destroying' do
    it "it should remove the directory" do
      #expects_rm_rf
      provider.destroy
    end
  end

  context "checking the revision property" do
    before do
      expects_chdir('/tmp/test')
      resource[:revision] = 'currentsha'
      resource.delete(:source)
      provider.expects(:git).with('rev-parse', 'HEAD').returns('currentsha')
    end

    context "when its SHA is not different than the current SHA" do
      it "should return the ref" do
        provider.expects(:git).with('config', 'remote.origin.url').returns('')
        provider.expects(:git).with('fetch', 'origin') # FIXME
        provider.expects(:git).with('fetch', '--tags', 'origin')
        provider.expects(:git).with('rev-parse', '--revs-only', resource.value(:revision)).returns('currentsha')
        provider.expects(:git).with('tag', '-l').returns("Hello")
        provider.revision.should == resource.value(:revision)
      end
    end

    context "when its SHA is different than the current SHA" do
      it "should return the current SHA" do
        provider.expects(:git).with('config', 'remote.origin.url').returns('')
        provider.expects(:git).with('fetch', 'origin') # FIXME
        provider.expects(:git).with('fetch', '--tags', 'origin')
        provider.expects(:git).with('rev-parse', '--revs-only', resource.value(:revision)).returns('othersha')
        provider.expects(:git).with('tag', '-l').returns("Hello")
        provider.revision.should == 'currentsha'
      end
    end

    context "when its a ref to a remote head" do
      it "should return the revision" do
        provider.expects(:git).with('config', 'remote.origin.url').returns('')
        provider.expects(:git).with('fetch', 'origin') # FIXME
        provider.expects(:git).with('fetch', '--tags', 'origin')
        provider.expects(:git).with('tag', '-l').returns("Hello")
        provider.expects(:git).with('rev-parse', '--revs-only', resource.value(:revision)).returns('')
        provider.expects(:git).with('ls-remote', '--heads', '--tags', 'origin', resource.value(:revision)).returns("newsha refs/heads/#{resource.value(:revision)}")
        provider.revision.should == 'currentsha'
      end
    end

    context "when its a ref to non existant remote head" do
      it "should fail" do
        provider.expects(:git).with('config', 'remote.origin.url').returns('')
        provider.expects(:git).with('fetch', 'origin') # FIXME
        provider.expects(:git).with('fetch', '--tags', 'origin')
        provider.expects(:git).with('tag', '-l').returns("Hello")
        provider.expects(:git).with('rev-parse', '--revs-only', resource.value(:revision)).returns('')
        provider.expects(:git).with('ls-remote', '--heads', '--tags', 'origin', resource.value(:revision)).returns('')
        expect { provider.revision }.to raise_error(Puppet::Error, /not a local or remote ref$/)
      end
    end

    context "when the source is modified" do
      it "should update the origin url" do
        resource[:source] = 'git://git@foo.com/bar.git'
        provider.expects(:git).with('config', 'remote.origin.url').returns('old')
        provider.expects(:git).with('config', 'remote.origin.url', 'git://git@foo.com/bar.git')
        provider.expects(:git).with('fetch', 'origin') # FIXME
        provider.expects(:git).with('fetch', '--tags', 'origin')
        provider.expects(:git).with('rev-parse', '--revs-only', resource.value(:revision)).returns('currentsha')
        provider.expects(:git).with('tag', '-l').returns("Hello")
        provider.revision.should == resource.value(:revision)
      end
    end
  end

  context "setting the revision property" do
    before do
      expects_chdir
    end
    context "when it's an existing local branch" do
      it "should use 'git fetch' and 'git reset'" do
        resource[:revision] = 'feature/foo'
        provider.expects(:update_submodules)
        provider.expects(:git).with('branch', '-a').returns(resource.value(:revision))
        provider.expects(:git).with('checkout', '--force', resource.value(:revision))
        provider.expects(:git).with('branch', '-a').returns(resource.value(:revision))
        provider.expects(:git).with('reset', '--hard', "origin/#{resource.value(:revision)}")
        provider.revision = resource.value(:revision)
      end
    end
    context "when it's a remote branch" do
      it "should use 'git fetch' and 'git reset'" do
        resource[:revision] = 'only/remote'
        provider.expects(:update_submodules)
        provider.expects(:git).with('branch', '-a').returns(resource.value(:revision))
        provider.expects(:git).with('checkout', '--force', resource.value(:revision))
        provider.expects(:git).with('branch', '-a').returns(resource.value(:revision))
        provider.expects(:git).with('reset', '--hard', "origin/#{resource.value(:revision)}")
        provider.revision = resource.value(:revision)
      end
    end
    context "when it's a commit or tag" do
      it "should use 'git fetch' and 'git reset'" do
        resource[:revision] = 'a-commit-or-tag'
        provider.expects(:git).with('branch', '-a').returns(fixture(:git_branch_a))
        provider.expects(:git).with('checkout', '--force', resource.value(:revision))
        provider.expects(:git).with('branch', '-a').returns(fixture(:git_branch_a))
        provider.expects(:git).with('branch', '-a').returns(fixture(:git_branch_a))
        provider.expects(:git).with('submodule', 'update', '--init', '--recursive')
        provider.revision = resource.value(:revision)
      end
    end
  end

  context "updating references" do
    it "should use 'git fetch --tags'" do
      resource.delete(:source)
      expects_chdir
      provider.expects(:git).with('config', 'remote.origin.url').returns('')
      provider.expects(:git).with('fetch', 'origin')
      provider.expects(:git).with('fetch', '--tags', 'origin')
      provider.update_references
    end
  end

  context "checking if revision" do
    before do
      expects_chdir
      provider.expects(:git).with('branch', '-a').returns(fixture(:git_branch_a))
    end
    context "is a local branch" do
      context "when it's listed in 'git branch -a'" do
        it "should return true" do
          resource[:revision] = 'feature/foo'
          provider.should be_local_branch_revision
        end
      end
      context "when it's not listed in 'git branch -a'" do
        it "should return false" do
          resource[:revision] = 'feature/notexist'
          provider.should_not be_local_branch_revision
        end
      end
    end
    context "is a remote branch" do
      context "when it's listed in 'git branch -a' with an 'origin/' prefix" do
        it "should return true" do
          resource[:revision] = 'only/remote'
          provider.should be_remote_branch_revision
        end
      end
      context "when it's not listed in 'git branch -a' with an 'origin/' prefix" do
        it "should return false" do
          resource[:revision] = 'only/local'
          provider.should_not be_remote_branch_revision
        end
      end
    end
  end

  describe 'latest?' do
    before do
      expects_chdir('/tmp/test')
    end
    context 'when true' do
      it do
        provider.expects(:revision).returns('testrev')
        provider.expects(:latest).returns('testrev')
        provider.latest?.should be_true
      end
    end
    context 'when false' do
      it do
        provider.expects(:revision).returns('master')
        provider.expects(:latest).returns('testrev')
        provider.latest?.should be_false
      end
    end
  end

  describe 'latest' do
    before do
      provider.expects(:get_revision).returns('master')
      expects_chdir
    end
    context 'on master' do
      it do
        provider.expects(:git).with('branch', '-a').returns(fixture(:git_branch_a))
        provider.latest.should == 'master'
      end
    end
    context 'no branch' do
      it do
        provider.expects(:git).with('branch', '-a').returns(fixture(:git_branch_none))
        provider.latest.should == 'master'
      end
    end
    context 'feature/bar' do
      it do
        provider.expects(:git).with('branch', '-a').returns(fixture(:git_branch_feature_bar))
        provider.latest.should == 'master'
      end
    end
  end

  describe 'convert_working_copy_to_bare' do
    it do
      FileUtils.expects(:mv).returns(true)
      FileUtils.expects(:rm_rf).returns(true)
      FileUtils.expects(:mv).returns(true)

      provider.instance_eval { convert_working_copy_to_bare }
    end
  end

  describe 'convert_bare_to_working_copy' do
    it do
      FileUtils.expects(:mv).returns(true)
      FileUtils.expects(:mkdir).returns(true)
      FileUtils.expects(:mv).returns(true)
      provider.expects(:commits_in?).returns(true)
      # If you forget to stub these out you lose 3 hours of rspec work.
      provider.expects(:reset).with('HEAD').returns(true)
      provider.expects(:git_with_identity).returns(true)
      provider.expects(:update_owner_and_excludes).returns(true)

      provider.instance_eval { convert_bare_to_working_copy }
    end
  end

end
require 'spec_helper'

describe Puppet::Type.type(:vcsrepo).provider(:hg) do

  let(:resource) { Puppet::Type.type(:vcsrepo).new({
    :name     => 'test',
    :ensure   => :present,
    :provider => :hg,
    :path     => '/tmp/vcsrepo',
  })}

  let(:provider) { resource.provider }

  before :each do
    Puppet::Util.stubs(:which).with('hg').returns('/usr/bin/hg')
  end

  describe 'creating' do
    context 'with source and revision' do
      it "should execute 'hg clone -u' with the revision" do
        resource[:source] = 'something'
        resource[:revision] = '1'
        provider.expects(:hg).with('clone', '-u',
          resource.value(:revision),
          resource.value(:source),
          resource.value(:path))
        provider.create
      end
    end

    context 'without revision' do
      it "should just execute 'hg clone' without a revision" do
        resource[:source] = 'something'
        provider.expects(:hg).with('clone', resource.value(:source), resource.value(:path))
        provider.create
      end
    end

    context "when a source is not given" do
      it "should execute 'hg init'" do
        provider.expects(:hg).with('init', resource.value(:path))
        provider.create
      end
    end
  end

  describe 'destroying' do
    it "it should remove the directory" do
      expects_rm_rf
      provider.destroy
    end
  end

  describe "checking existence" do
    it "should check for the directory" do
      expects_directory?(true, File.join(resource.value(:path), '.hg'))
      provider.exists?
    end
  end

  describe "checking the revision property" do
    before do
      expects_chdir
    end

    context "when given a non-SHA as the resource revision" do
      before do
        provider.expects(:hg).with('parents').returns(fixture(:hg_parents))
        provider.expects(:hg).with('tags').returns(fixture(:hg_tags))
      end

      context "when its SHA is not different than the current SHA" do
        it "should return the ref" do
          resource[:revision] = '0.6'
          provider.revision.should == '0.6'
        end
      end

      context "when its SHA is different than the current SHA" do
        it "should return the current SHA" do
          resource[:revision] = '0.5.3'
          provider.revision.should == '34e6012c783a'
        end
      end
    end
    context "when given a SHA as the resource revision" do
      before do
        provider.expects(:hg).with('parents').returns(fixture(:hg_parents))
      end

      context "when it is the same as the current SHA", :resource => {:revision => '34e6012c783a'} do
        it "should return it" do
          resource[:revision] = '34e6012c783a'
          provider.expects(:hg).with('tags').returns(fixture(:hg_tags))
          provider.revision.should == resource.value(:revision)
        end
      end

      context "when it is not the same as the current SHA", :resource => {:revision => 'not-the-same'} do
        it "should return the current SHA" do
          resource[:revision] = 'not-the-same'
          provider.expects(:hg).with('tags').returns(fixture(:hg_tags))
          provider.revision.should == '34e6012c783a'
        end
      end
    end
  end

  describe "setting the revision property" do
    before do
      @revision = '6aa99e9b3ab1'
    end
    it "should use 'hg update ---clean -r'" do
      expects_chdir
      provider.expects(:hg).with('pull')
      provider.expects(:hg).with('merge')
      provider.expects(:hg).with('update', '--clean', '-r', @revision)
      provider.revision = @revision
    end
  end

end
require 'spec_helper'

describe Puppet::Type.type(:vcsrepo).provider(:svn) do

  let(:resource) { Puppet::Type.type(:vcsrepo).new({
    :name     => 'test',
    :ensure   => :present,
    :provider => :svn,
    :path     => '/tmp/vcsrepo',
  })}

  let(:provider) { resource.provider }

  before :each do
    Puppet::Util.stubs(:which).with('git').returns('/usr/bin/git')
  end

  describe 'creating' do
    context 'with source and revision' do
      it "should execute 'svn checkout' with a revision" do
        resource[:source] = 'exists'
        resource[:revision] = '1'
        provider.expects(:svn).with('--non-interactive', 'checkout', '-r',
          resource.value(:revision),
          resource.value(:source),
          resource.value(:path))
        provider.create
      end
    end
    context 'with source' do
      it "should just execute 'svn checkout' without a revision" do
        resource[:source] = 'exists'
        provider.expects(:svn).with('--non-interactive', 'checkout',
          resource.value(:source),
          resource.value(:path))
        provider.create
      end
    end

    context 'with fstype' do
      it "should execute 'svnadmin create' with an '--fs-type' option" do
        resource[:fstype] = 'ext4'
        provider.expects(:svnadmin).with('create', '--fs-type',
                                          resource.value(:fstype),
                                          resource.value(:path))
        provider.create
      end
    end
    context 'without fstype' do
      it "should execute 'svnadmin create' without an '--fs-type' option" do
        provider.expects(:svnadmin).with('create', resource.value(:path))
        provider.create
      end
    end
  end

  describe 'destroying' do
    it "it should remove the directory" do
      expects_rm_rf
      provider.destroy
    end
  end

  describe "checking existence" do
    it "should check for the directory" do
      expects_directory?(true, resource.value(:path))
      expects_directory?(true, File.join(resource.value(:path), '.svn'))
      provider.exists?
    end
  end

  describe "checking the revision property" do
    before do
      provider.expects(:svn).with('--non-interactive', 'info').returns(fixture(:svn_info))
    end
    it "should use 'svn info'" do
      expects_chdir
      provider.revision.should == '4' # From 'Revision', not 'Last Changed Rev'
    end
  end

  describe "setting the revision property" do
    before do
      @revision = '30'
    end
    it "should use 'svn update'" do
      expects_chdir
      provider.expects(:svn).with('--non-interactive', 'update', '-r', @revision)
      provider.revision = @revision
    end
  end

  describe "setting the revision property and repo source" do
    before do
      @revision = '30'
    end
    it "should use 'svn switch'" do
      resource[:source] = 'an-unimportant-value'
      expects_chdir
      provider.expects(:svn).with('--non-interactive', 'switch', '-r', @revision, 'an-unimportant-value')
      provider.revision = @revision
    end
  end

end
Resource Type Specs
===================

Define specs for your resource types in this directory.
fixtures:
  repositories:
    "puppi": "git://github.com/example42/puppi.git"
    "monitor": "git://github.com/example42/puppet-monitor.git"
    "firewall": "git://github.com/example42/puppet-firewall.git"
    "iptables": "git://github.com/example42/puppet-iptables.git"
    "concat": "git://github.com/example42/puppet-concat.git"
  symlinks:
    "yum": "#{source_dir}"

source :rubygems

puppetversion = ENV['PUPPET_VERSION']
gem 'puppet', puppetversion, :require => false
gem 'puppet-lint'
gem 'puppetlabs_spec_helper', '>= 0.1.0'
gem 'rspec-puppet', '0.1.6'
language: ruby
rvm:
  - 1.8.7
  - 1.9.3
script:
  - "rake spec SPEC_OPTS='--format documentation'"
env:
  - PUPPET_VERSION="~> 2.6.0"
  - PUPPET_VERSION="~> 2.7.0"
  - PUPPET_VERSION="~> 3.0.0"
  - PUPPET_VERSION="~> 3.1.0"
matrix:
  exclude:
    - rvm: 1.9.3
      env: PUPPET_VERSION="~> 2.6.0"
      gemfile: .gemfile

gemfile: .gemfile
notifications:
  email:
    - al@lab42.it
Copyright (C) 2013 Alessandro Franceschi / Lab42

for the relevant commits Copyright (C) by the respective authors.

Contact Lab42 at: info@lab42.it

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
name    'example42-yum'
version '2.1.9'
author  'Alessandro Franceschi'
license 'Apache2'
project_page 'http://www.example42.com'
source  'https://github.com/example42/puppet-yum'
summary 'Puppet module for nagios'
description 'This module installs and manages yum and yum repositories'
dependency 'example42/puppi', '>= 2.0.0'
# Puppet module: yum

This is a Puppet module that manages Yum repositories for Centos RedHat and Scientific Linux

Made by Alessandro Franceschi / Lab42

Inspired by the Yum Immerda module: https://git.puppet.immerda.ch

Official site: http://www.example42.com

Official git repository: http://github.com/example42/puppet-yum

Released under the terms of Apache 2 License.

This module requires functions provided by the Example42 Puppi module.

## USAGE 

* Just leave the default options: Automatic detection of Operating System (RedHat, Centos, Scientific supported) Epel repo installation, keeping of local yum files, automatic updates disabled.

        class { 'yum':
        }

* Enable automatic updates via cron (updatesd is supported only on 5)

        class { 'yum':
          update => 'cron',
        }


* Purge local /etc/yum.repos.d/ and enforce its contents only via a custom source

        class { 'yum':
          source_repo_dir => 'puppet:///modules/example42/yum/conf/',
          clean_repos     => true,
        }

* Enable EPEL and PuppetLabs repos

        class { 'yum':
          extrarepo => [ 'epel' , 'puppetlabs' ],
        }


* Do not include any extra repo (By default EPEL is added)

        class { 'yum':
          extrarepo => '' ,
        }

* Automatically copy in /etc/pki/rpm-gpg  all the rpm-gpg keys known by the yum module (this was the "old" and intrusive behaviour, now each rpm-gpg key may be individually provided by the yum::manages_repos' gpgkey_source parameter)

        class { 'yum':
          install_all_keys => true ,
        }

* Include a selected extra repo

        include yum::repo::puppetlabs


## USAGE - Overrides and Customizations
* Enable auditing without without making changes on existing yum configuration files

        class { 'yum':
          audit_only => true
        }


* Use custom sources for main config file

        class { 'yum':
          source => [ "puppet:///modules/lab42/yum/yum.conf-${hostname}" , "puppet:///modules/lab42/yum/yum.conf" ],
        }


* Use custom source directory for the whole configuration dir

        class { 'yum':
          source_dir       => 'puppet:///modules/lab42/yum/conf/',
          source_dir_purge => false, # Set to true to purge any existing file not present in $source_dir
        }

* Use custom template for main config file. Note that template and source arguments are alternative.

        class { 'yum':
          template => 'example42/yum/yum.conf.erb',
        }

* Automatically include a custom subclass

        class { 'yum':
          my_class => 'yum::example42',
        }


## USAGE - Example42 extensions management
* Activate puppi (recommended, but disabled by default)

        class { 'yum':
          puppi    => true,
        }

* Activate puppi and use a custom puppi_helper template (to be provided separately with a puppi::helper define ) to customize the output of puppi commands

        class { 'yum':
          puppi        => true,
          puppi_helper => 'myhelper',
        }


## OPERATING SYSTEMS SUPPORT

REDHAT 6 - Full

REDHAT 5 - Full

REDHAT 4 - Partial

CENTOS 6 - Full

CENTOS 5 - Full

CENTOS 4 - Partial

SCIENTIFIC 6 - Full

SCIENTIFIC 5 - Full

AMAZON LINUX 3 (Sigh) - Partial

[![Build Status](https://travis-ci.org/example42/puppet-yum.png?branch=master)](https://travis-ci.org/example42/puppet-yum)
require 'rubygems'
require 'puppetlabs_spec_helper/rake_tasks'
require 'puppet-lint/tasks/puppet-lint'
PuppetLint.configuration.send('disable_80chars')
PuppetLint.configuration.send('disable_class_parameter_defaults')
Version: GnuPG v1.4.5 (GNU/Linux)

mQINBE4P06MBEACqn48FZgYkG2QrtUAVDV58H6LpDYEcTcv4CIFSkgs6dJ9TavCW
NyPBZRpM2R+Rg5eVqlborp7TmktBP/sSsxc8eJ+3P2aQWSWc5ol74Y0OznJUCrBr
bIdypJllsD9Fe+h7gLBXTh3vdBEWr2lR+xA+Oou8UlO2gFbVFQqMafUgU1s0vqaE
/hHH0TzwD0/tJ6eqIbHwVR/Bu6kHFK4PwePovhfvyYD9Y+C0vOYd5Ict2vbLHz1f
QBDZObv4M6KN3j7nzme47hKtdMd+LwFqxM5cXfM6b5doDulWPmuGV78VoX6OR7el
x1tlfpuiFeuXYnImm5nTawArcQ1UkXUSYcTUKShJebRDLR3BycxR39Q9jtbOQ29R
FumHginovEhdUcinRr22eRXgcmzpR00zFIWoFCwHh/OCtG14nFhefuZ8Z80qbVhW
2J9+/O4tksv9HtQBmQNOK5S8C4HNF2M8AfOWNTr8esFSDc0YA5/cxzdfOOtWam/w
lBpNcUUSSgddRsBwijPuWhVA3NmA/uQlJtAo4Ji5vo8cj5MTPG3+U+rfNqRxu1Yc
ioXRo4LzggPscaTZX6V24n0fzw0J2k7TT4sX007k+7YXwEMqmHpcMYbDNzdCzUer
Zilh5hihJwvGfdi234W3GofttoO+jaAZjic7a3p6cO1ICMgfVqrbZCUQVQARAQAB
tEZDZW50T1MtNiBLZXkgKENlbnRPUyA2IE9mZmljaWFsIFNpZ25pbmcgS2V5KSA8
Y2VudG9zLTYta2V5QGNlbnRvcy5vcmc+iQI8BBMBAgAmBQJOD9OjAhsDBQkSzAMA
BgsJCAcDAgQVAggDBBYCAwECHgECF4AACgkQCUb8osEFud6ajRAAnb6d+w6Y/v/d
MSy7UEy4rNquArix8xhqBwwjoGXpa37OqTvvcJrftZ1XgtzmTbkqXc+9EFch0C+w
ST10f+H0SPTUGuPwqLkg27snUkDAv1B8laub+l2L9erzCaRriH8MnFyxt5v1rqWA
mVlRymzgXK+EQDr+XOgMm1CvxVY3OwdjdoHNox4TdVQWlZl83xdLXBxkd5IRciNm
sg5fJAzAMeg8YsoDee3m4khg9gEm+/Rj5io8Gfk0nhQpgGGeS1HEXl5jzTb44zQW
qudkfcLEdUMOECbu7IC5Z1wrcj559qcp9C94IwQQO+LxLwg4kHffvZjCaOXDRiya
h8KGsEDuiqwjU9HgGq9fa0Ceo3OyUazUi+WnOxBLVIQ8cUZJJ2Ia5PDnEsz59kCp
JmBZaYPxUEteMtG3yDTa8c8jUnJtMPpkwpSkeMBeNr/rEH4YcBoxuFjppHzQpJ7G
hZRbOfY8w97TgJbfDElwTX0/xX9ypsmBezgGoOvOkzP9iCy9YUBc9q/SNnflRWPO
sMVrjec0vc6ffthu2xBdigBXhL7x2bphWzTXf2T067k+JOdoh5EGney6LhQzcp8m
YCTENStCR+L/5XwrvNgRBnoXe4e0ZHet1CcCuBCBvSmsPHp5ml21ahsephnHx+rl
JNGtzulnNP07RyfzQcpCNFH7W4lXzqM=
=jrWY
Version: GnuPG v1.4.5 (GNU/Linux)

mQINBEvSKUIBEADLGnUj24ZVKW7liFN/JA5CgtzlNnKs7sBg7fVbNWryiE3URbn1
JXvrdwHtkKyY96/ifZ1Ld3lE2gOF61bGZ2CWwJNee76Sp9Z+isP8RQXbG5jwj/4B
M9HK7phktqFVJ8VbY2jfTjcfxRvGM8YBwXF8hx0CDZURAjvf1xRSQJ7iAo58qcHn
XtxOAvQmAbR9z6Q/h/D+Y/PhoIJp1OV4VNHCbCs9M7HUVBpgC53PDcTUQuwcgeY6
pQgo9eT1eLNSZVrJ5Bctivl1UcD6P6CIGkkeT2gNhqindRPngUXGXW7Qzoefe+fV
QqJSm7Tq2q9oqVZ46J964waCRItRySpuW5dxZO34WM6wsw2BP2MlACbH4l3luqtp
Xo3Bvfnk+HAFH3HcMuwdaulxv7zYKXCfNoSfgrpEfo2Ex4Im/I3WdtwME/Gbnwdq
3VJzgAxLVFhczDHwNkjmIdPAlNJ9/ixRjip4dgZtW8VcBCrNoL+LhDrIfjvnLdRu
vBHy9P3sCF7FZycaHlMWP6RiLtHnEMGcbZ8QpQHi2dReU1wyr9QgguGU+jqSXYar
1yEcsdRGasppNIZ8+Qawbm/a4doT10TEtPArhSoHlwbvqTDYjtfV92lC/2iwgO6g
YgG9XrO4V8dV39Ffm7oLFfvTbg5mv4Q/E6AWo/gkjmtxkculbyAvjFtYAQARAQAB
tCFFUEVMICg2KSA8ZXBlbEBmZWRvcmFwcm9qZWN0Lm9yZz6JAjYEEwECACAFAkvS
KUICGw8GCwkIBwMCBBUCCAMEFgIDAQIeAQIXgAAKCRA7Sd8qBgi4lR/GD/wLGPv9
qO39eyb9NlrwfKdUEo1tHxKdrhNz+XYrO4yVDTBZRPSuvL2yaoeSIhQOKhNPfEgT
9mdsbsgcfmoHxmGVcn+lbheWsSvcgrXuz0gLt8TGGKGGROAoLXpuUsb1HNtKEOwP
Q4z1uQ2nOz5hLRyDOV0I2LwYV8BjGIjBKUMFEUxFTsL7XOZkrAg/WbTH2PW3hrfS
WtcRA7EYonI3B80d39ffws7SmyKbS5PmZjqOPuTvV2F0tMhKIhncBwoojWZPExft
HpKhzKVh8fdDO/3P1y1Fk3Cin8UbCO9MWMFNR27fVzCANlEPljsHA+3Ez4F7uboF
p0OOEov4Yyi4BEbgqZnthTG4ub9nyiupIZ3ckPHr3nVcDUGcL6lQD/nkmNVIeLYP
x1uHPOSlWfuojAYgzRH6LL7Idg4FHHBA0to7FW8dQXFIOyNiJFAOT2j8P5+tVdq8
wB0PDSH8yRpn4HdJ9RYquau4OkjluxOWf0uRaS//SUcCZh+1/KBEOmcvBHYRZA5J
l/nakCgxGb2paQOzqqpOcHKvlyLuzO5uybMXaipLExTGJXBlXrbbASfXa/yGYSAG
iVrGz9CE6676dMlm8F+s3XXE13QZrXmjloc6jwOljnfAkjTGXjiB7OULESed96MR
XtfLk0W5Ab9pd7tKDR6QHI7rgHXfCopRnZ2VVQ==
=V/6I
Version: GnuPG v2.0.14 (GNU/Linux)

mQGiBEZ6qawRBAC2gDuA1sZioGh1VP/U0l+9RmzOdkWBGB3NfWqezAwt1Up+cP5o
h+UNkghOKbJVQ/zLyY/edYOppQ78yxT1X/J1RHNhs5bjqzWlQxMbT5/tt1N4PExu
gvO38RGFTV0DqIy3lQw5YIwp2le+G8MktYh2NKI4lG0AJoXZicNlI7+mEwCgmfw+
CnsB/kb/xUD1dq6Mo3dYXVcEAKSFfqt+6jvJNxcIYfpQqjEslQsQmPKpXzK9CPyV
UCjUEOirbhPxV86u3Ge/yuy5USMvTTs+ztImabbH6UHBEP+tEw3LiuPUpfh+nEna
3Hz+U81PvUwGEwUMzCr+OemBXqGW7jl66NqKqm8YM3Pkvc4NlS/7slky9A/s6i8S
hToWA/9kP55aSbIXte5TbC88lx6YuLx7qW541ni38DmJfPN5hHywLGnM82MMQMbk
hg1v49+7TTNv44LJpGT7t8gsW9F4Z4rWoChhsldypeeqbDOIv4kFiXt/8122Ud9J
nE67CR9XUuS5Jp+gP6xxNr9/vbvqsOGMJAQkVgkBPVuKYv25gLQ3U2VyZ2lvIFJ1
YmlvIChGcmFtZU9TIERldmVsb3BlcnMpIDxydWJpb2pyQGZyYW1lb3Mub3JnPohr
BBMRAgArAhsDBQkGE0x0BgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAUCTBs76AIZ
AQAKCRCOw9dP80W+dFhjAJ0dKy761iPcG+ALwEAuAgxDpUVBzgCdFxGCAZ7ELYvf
3uFc0Ou2ihDzvyy0IFNlcmdpbyBSdWJpbyA8c2VyZ2lvQHJ1YmlvLm5hbWU+iGYE
ExECACYCGwMGCwkIBwMCBBUCCAMEFgIDAQIeAQIXgAUJBhNMdAUCTBs7XgAKCRCO
w9dP80W+dDdtAJ9NYoW1ChfMyES7nQUlesEQ4aWXjQCeIoGxoOuIGyg6+AKr/2Wr
6fE1zt2IaQQTEQIAKQIbAwYLCQgHAwIEFQIIAwQWAgMBAh4BAheAAhkBBQJIHsGo
BQkCuHFEAAoJEI7D10/zRb50KjgAnRTzzNIODKqrHnrHaUG8dWDCwmYjAJ48Hbcn
ZC6E8LGTeM8vPN0mMI9ijLkCDQRGeqm2EAgAh720kjA9bNDms+6agb6CirD9RkmZ
3G+OHd5iia3KbaUiBtC3PECg4UE8N54JuBNKdjgJQfdYSg2J0EZHyhZHdAVWjykE
tj/IKZKnAfUqKh44uT9OUPW8PChPo/gioLn+DexSAW7n19h7VIa1P3shYqYR/gz8
zgfrXkFFpkpKnOLsXuF20JEEBIBdwrfYRJIBrUTYrfS/2GKLJjyutENkb9uI3JgQ
LfR6DckTaar4eeArjgvOxZRHiU0vRezetlbG8ZM9mSYrcMM3Xa5vLpFlDj6vYzat
RWEuZUfLgXWUVoVyFiNVXhpff/w7/bAb3WpXqjZd6sK8CCJJPNtnbLE7CwADBQf9
EQjT9iiEZis35V9HqeLsxXVjPOGNuLiwjIpacI7CM3aGV1q7NXiCE4oWS/PvpHmu
W+XdXMPH4Bt2VmjZSarlAipTeNnOuiEXipUFIjAlNn1xNVRRd7T35zIvXLtmNtUe
nN1/mqZljKPbCbW1AgktH417t/vJfTnRWr9IgS3Am+o4q200i+1FjrQ/UI3s9+vg
5B+KASFP6HspNttl0kwzQ6SFIHAebd4DKHOj6ShxXPNl18W4R8qPqayrAFqdkgMJ
Jn8j2E8rmGYnssSfjck2kLtvNdTEAMjFnhg+oUapUzJAVeterudiWZFNrtn9ewnf
8SUiiYJlxb+nz545zo0gQIhJBBgRAgAJBQJGeqm2AhsMAAoJEI7D10/zRb50PJEA
mwTA+Sp3wvzwDr8sk7W7U4bBfw26AKCVoYw3mfTime+j3mFk1yk1yxjE2Q==
=iyOs

Version: GnuPG v1.2.6 (GNU/Linux)

mQGiBEWfBuERBACrwDH+6QvpyaOgzhXiemsIX+q4HlhX/HDmrmZOUd7i9VmZNogP
6LRRiTygn2+UphaGV3NDA36ZB/1JRpgvgpzbpZNeAoFvsljIbxGIwkH2JgRF6oNo
eGB3QYzDQJvYVIejk79M0ed3oor4w8OiNVcdxLyVIthFrjrrCqwRP3bLZwCgtY9t
Ezf5WL63Ue45vdht7A2GH+0D/iNAnWKsU7FUMFZrcwMaMbyP7YG8z0+zXUOgtgyP
tbgJG5yikNT3vJypb42gbKfcriUUDC5AeiRmkR8QPvYuOm34rM90+wx2LGqXWnHM
IyLAyl8TS3MQmePem8bfTGTNYxtt3Q7iadez2WYTLBSlmM6hbxZfdwm1hhyM0AJU
YyFUA/9kHH+CUBxKb1UgG7TSp53Po/5p/Yyuty+RJ7zIGv6SiN/JK4/ntWfm5WS5
ZprSdE5ODoFQ/Gs3/VB/eolg2fBW1DcftH6lKHT3GKEOaicGX+T9eOMerZZedm5U
vDA9mFvWnOdOxK8LuRgVqip4jCnWICchpatmdP0whJQHQ6MGLLRMQ2VudE9TLTUg
QmV0YSBLZXkgKENlbnRPUyA1IEJldGEgU2lnbmluZyBLZXkpIDxjZW50b3MtNS1i
ZXRhLWtleUBjZW50b3Mub3JnPohkBBMRAgAkBQJFnwbhAhsDBQkSzAMABgsJCAcD
AgMVAgMDFgIBAh4BAheAAAoJEM/aaIEJLXsrWDkAoKcqa+AAdAWvp5qlJkGQiRy8
aNFDAJ4qRfIxMiLinmjbqcuygWMp61wY5ohMBBMRAgAMBQJFnwhtBYMSzAF0AAoJ
EDjCFhY5bKCkG/wAn14LDlJqjZv1Wz0WNfhr80+qJrf6AKCaIZExwo4ApQpESk/F
SApLd/pEILkBDQRFnwbrEAQAwKzjI2aTB/sS9HuQ4CHCwrj4vr0HxMMwQikYBIvy
MYTtek04KDTKoJL5g3411DsfDW9VRGJdFCHvldgam/5UVfO6nywLkdwAA5TQA5dv
8YE8jTtwdy5Y1QKFc8LaIBZK0+ZbhEvdNfv67egvfcxZc5PvpBZ3C03n+iQ3wPcg
PhcAAwUD/iYkq4LG/je43Qa5rTz5kF5rIiX7Bk5vXT7XSFOFKwHy8V+PGEoVM1W8
+EHIlmTycwIlsVp3by6qCDkMYu4V6VukxZNzJyeoMICiYIXUPh6NKHRoqaYlu6ZO
eFN1TQNXmodPk+iNtdbcby/zAklNqoO/dWSwd8NAo8s6WAHq3VPpiE8EGBECAA8F
AkWfBusCGwwFCRLMAwAACgkQz9pogQkteysXkACgoraCU0EBC+W8TuxrsePO20ma
D0IAoLRRQLTEXL0p3K0WE+LfyTr9EVG5
=mH0S

Version: GnuPG v1.2.6 (GNU/Linux)

mQGiBEIu6hwRBACOz2JFa1nW+seAKlVGOu0ykhdFVNI9E4/Abp2+8nsJIZyUwLAp
ei76rPD8WdptgIjtYOCsqz1TbP+eqeEG0LLihOdFRLUuAjQX4X7LLf5Qm+nvUB73
uLbSf9Ptps2CMUEtu7+0wVoTbuC19HXUhUr5sRdCnJbPJBH6aAHG7Pl9ZwCguN9o
V7IKTnIQiZg0nxSjZ4V9e6UD/R7KoMwH3NPQQF7T7rJaBjSZcVHUPhAcNPNn+ms/
Tw9mzHZ0mnQnOzSEW0ZUj9TkLN52VQ3WmGZKAv9yeVr0/230YIgmtH863lSystmk
LNO9brK0+3vKg5GRpV0/MSWSmf39WPAS1hXNXIFfYp1eGHUfed4FVNxrMTWHQozr
8JosA/wP+zGfM51bSAazLUqP/MEm7F9OFkuD7Sw97w55FyYlrPp1FQWrWczoiKHr
wS5NRCQbCGEEM/+j9id6CukxPLXxwMYCfeg5K0HxMaQT6hxbwjOzAzN3PBFytNel
09qdrdoSDa35twT0SAt+rzM+zvRI8ycizFG3lIih4UItWWve2bQ6S2FyYW5iaXIg
U2luZ2ggKGh0dHA6Ly93d3cua2FyYW4ub3JnLykgPGtic2luZ2hAa2FyYW4ub3Jn
PoheBBMRAgAeBQJCLuocAhsDBgsJCAcDAgMVAgMDFgIBAh4BAheAAAoJEDANvZ4+
E89b/P4AnjufrDCS+TAEL0KpkYDURePbDCHBAJ4+0iI1Td4YrcnLwmQ1+XDCJ3Zr
a7kBDQRCLuocEAQAjAl48FM9eGtP6M9FgswlSPAuCcJct6wOHmd/qZ923HckJPAD
zIFRMlM6H8P0bKoaIluv7agZM7Gsf8NeTg3NEeMKqnibIAyvjYeSkceRIwvBCQ3A
YwWk+B2zLUAFMxnE31oA10zjCKUo7Dc6XDUxSY/qdLymZzyG/Ndav+vMOVsAAwUD
/RCFDuW/GSM/s3DO7XxrOBRTGQmf9v9tCYdZZD615+s8ghaa5oZTvp1cbTTWiSq8
ybncfjVHz9HezDgQjJsFZtrYd4w2JD+7K0+8sZ+BUGo1dDSv4UgN8ACtaGJnShiq
s8pQWRZFqFa3waay8oUSTKHiTHdpxLi3x4HhK/8MTsxniEkEGBECAAkFAkIu6hwC
GwwACgkQMA29nj4Tz1tHSgCcDgKL4swEu7ShvI8nZt2JLmTKB5QAn0qZi2zbexbi
DX+bbalHM+xVnXZN
=rZT6
Version: GnuPG v1.4.7 (GNU/Linux)

mQGiBEJny1wRBACRnbQgZ6qLmJSuGvi/EwrRL6aW610BbdpLQRL3dnwy5wI5t9T3
/JEiEJ7GTvAwfiisEHifMfk2sRlWRf2EDQFttHyrrYXfY5L6UAF2IxixK5FL7PWA
/2a7tkw1IbCbt4IGG0aZJ6/xgQejrOLi4ewniqWuXCc+tLuWBZrGpE2QfwCggZ+L
0e6KPTHMP97T4xV81e3Ba5MD/3NwOQh0pVvZlW66Em8IJnBgM+eQh7pl4xq7nVOh
dEMJwVU0wDRKkXqQVghOxALOSAMapj5mDppEDzGLZHZNSRcvGEs2iPwo9vmY+Qhp
AyEBzE4blNR8pwPtAwL0W3cBKUx7ZhqmHr2FbNGYNO/hP4tO2ochCn5CxSwAfN1B
Qs5pBACOkTZMNC7CLsSUT5P4+64t04x/STlAFczEBcJBLF1T16oItDITJmAsPxbY
iee6JRfXmZKqmDP04fRdboWMcRjfDfCciSdIeGqP7vMcO25bDZB6x6++fOcmQpyD
1Fag3ZUq2yojgXWqVrgFHs/HB3QE7UQkykNp1fjQGbKK+5mWTrQkUmVtaSBDb2xs
ZXQgPFJQTVNARmFtaWxsZUNvbGxldC5jb20+iGAEExECACAFAkZ+MYoCGwMGCwkI
BwMCBBUCCAMEFgIDAQIeAQIXgAAKCRAATm9HAPl/Vv/UAJ9EL8ioMTsz/2EPbNuQ
MP5Xx/qPLACeK5rk2hb8VFubnEsbVxnxfxatGZ25AQ0EQmfLXRAEANwGvY+mIZzj
C1L5Nm2LbSGZNTN3NMbPFoqlMfmym8XFDXbdqjAHutGYEZH/PxRI6GC8YW5YK4E0
HoBAH0b0F97JQEkKquahCakj0P5mGuH6Q8gDOfi6pHimnsSAGf+D+6ZwAn8bHnAa
o+HVmEITYi6s+Csrs+saYUcjhu9zhyBfAAMFA/9Rmfj9/URdHfD1u0RXuvFCaeOw
CYfH2/nvkx+bAcSIcbVm+tShA66ybdZ/gNnkFQKyGD9O8unSXqiELGcP8pcHTHsv
JzdD1k8DhdFNhux/WPRwbo/es6QcpIPa2JPjBCzfOTn9GXVdT4pn5tLG2gHayudK
8Sj1OI2vqGLMQzhxw4hJBBgRAgAJBQJCZ8tdAhsMAAoJEABOb0cA+X9WcSAAn11i
gC5ns/82kSprzBOU0BNwUeXZAJ0cvNmY7rvbyiJydyLsSxh/la6HKw==
=6Rbg
The following public key can be used to verify RPM packages
downloaded from  http://dag.wieers.com/apt/  using 'rpm -K'
if you have the GNU GPG package.
Questions about this key should be sent to:
Dag Wieers <dag@wieers.com>

Version: GnuPG v1.2.1 (GNU/Linux)

mQGiBD9JMT0RBAC9Q2B0AloUMTxaK73sD0cOu1MMdD8yuDagbMlDtUYA1aGeJVO6
TV02JLGr67OBY+UkYuC1c3PUwmb3+jakZd5bW1L8E2L705wS0129xQOZPz6J+alF
5rTzVkiefg8ch1yEcMayK20NdyOmhDGXQXNQS8OJFLTIC6bJs+7MZL83/wCg3cG3
3q7MWHm3IpJb+6QKpB9YH58D/2WjPDK+7YIky/JbFBT4JPgTSBy611+bLqHA6PXq
39tzY6un8KDznAMNtm+NAsr6FEG8PHe406+tbgd7tBkecz3HPX8nR5v0JtDT+gzN
8fM3kAiAzjCHUAFWVAMAZLr5TXuoq4lGTTxvZbwTjZfyjCm7gIieCu8+qnPWh6hm
30NgA/0ZyEHG6I4rOWqPks4vZuD+wlp5XL8moBXEKfEVOMh2MCNDRGnvVHu1P3eD
oHOooVMt9sWrGcgxpYuupPNL4Uf6B6smiLlH6D4tEg+qCxC17zABI5572XJTJ170
JklZJrPGtnkPrrKMamnN9MU4RjGmjh9JZPa7rKjZHyWP/z/CBrQ1RGFnIFdpZWVy
cyAoRGFnIEFwdCBSZXBvc2l0b3J5IHYxLjApIDxkYWdAd2llZXJzLmNvbT6IWQQT
EQIAGQUCP0kxPQQLBwMCAxUCAwMWAgECHgECF4AACgkQog5SFGuNeeYvDQCeKHST
hIq/WzFBXtJOnQkJGSqAoHoAnRtsJVWYmzYKHqzkRx1qAzL18Sd0iEYEEBECAAYF
Aj9JMWAACgkQoj2iXPqnmevnOACfRQaageMcESHVE1+RSuP3txPUvoEAoJAtOHon
g+3SzVNSZLn/g7/Ljfw+uQENBD9JMT8QBACj1QzRptL6hbpWl5DdQ2T+3ekEjJGt
llCwt4Mwt/yOHDhzLe8SzUNyYxTXUL4TPfFvVW9/j8WOkNGvffbs7g84k7a5h/+l
IJTTlP9V9NruDt1dlrBe+mWF6eCY55OFHjb6nOIkcJwKxRd3nGlWnLsz0ce9Hjrg
6lMrn0lPsMV6swADBQP9H42sss6mlqnJEFA97Fl3V9s+7UVJoAIA5uSVXxEOwVoh
Vq7uECQRvWzif6tzOY+vHkUxOBRvD6oIU6tlmuG3WByKyA1d0MTqMr3eWieSYf/L
n5VA9NuD7NwjFA1kLkoDwfSbsF51LppTMkUggzwgvwE46MB6yyuqAVI1kReAWw+I
RgQYEQIABgUCP0kxPwAKCRCiDlIUa4155oktAKDAzm9QYbDpk6SrQhkSFy016BjE
BACeJU1hpElFnUZCL4yKj4EuLnlo8kc=
=mqUt
Version: GnuPG v1.4.5 (GNU/Linux)

mQGiBE1e+1MRBAD8j+KyOIpGNRN39gNy2E/1HG4ZoLFuxIOxI5/1FEuZB/GjYF5m
DvJerZukd0QCqCs72J6J+uWnfD/52t2XWTw4IHPpCWeyr9TWex3uOYmrYzY+0l0l
qsCsrhT0XGkAE0+/20oEP2+t/d+1q0yRcYZRwWK/ME2rUUX0jOa/B3Bc6wCg3blw
XdZNrv1wVNd1PCOUI79k0V0D+wfbybos8Cmdv2f8dD746fSR/hmp4SzpBDmPRRQu
0gtJAKI6ycTdotGq5zHfZj76kDQBudeIgdbWtqfckP2lK47i8lIENAyC4MK8dxh9
Ts+b1LqXlbcPyixzImf4qoT5DT1lSEUPwoMRX8W/29GAcvnZpOwQ8g7DNmRBpFFY
8U2GBADz6uEeP3YwJAuL7pi77AalxR0WQAADMR59pGltQdXaZvANXoioU0W519Pb
nl3gKWDiTuwUDrwaSPoBbNLyX4s0AE7/0HSG02/eRjLB8toQpAH9xkK/u2WPe/do
erZg5yg1qhoCbEM7kJ2I/GBl6VbPedt2ORdsC4ZTWTnZJh6tYLQhQW5keSBUaG9t
cHNvbiA8YW5keUB3ZWJ0YXRpYy5jb20+iGAEExECACAFAk1e+1MCGwMGCwkIBwMC
BBUCCAMEFgIDAQIeAQIXgAAKCRC3Q0sGz0xP+TA0AJwJf5ZPeub8v+5CtZwdcZhV
LU0sjgCgrP3y54heBjF1vhZQ3rJywTmRLHe5Ag0ETV77UxAIAIQPLVFbqheJ90Kf
NF8TYt3ZIMpP5chw25OYq4tuZMzVJxKjUlM7KPQxUKquY/F9WpjH980LmICTb4Fz
txzn2bshIsGyg8pDUSnVK0NPY5uaq9bK4oht8wkr3FNFT2FpeqDIJyn+phIuEpIi
qt1LJyzzjobh9csaaGmNHvtrlkIggBj2n/ZQuGNhcYnKUZ/WGmkItCTSOfA++G+C
dCo1aPEymfbnJvaLB/mLyzA+r/r7LQM10cZEtqh5JdclJEh3CzZmx9HsRxCDZF8W
X/C4MmCwmIxmuU4vkVNhHFTQimQEUR8vg9ltiz8+xBjyE1Iav4MxfOYh3xjdJk1d
zlovyUcAAwUH/2KPgf0UQ1o+4IjOYinEEbNlrD1pKw5anUKwaaeQi0vm/oRG0E2F
ZCJ73OHxW/0hMrwbrGwXcm4NBARnAppg+/CecOVpkBgD5hrM+11DPhxdd1bjjfza
Pq8GmPp8SSsiTPUCoSlzojxL3Z05RNbvKVzxzxbYdx5h5XOTflI7bAHTY4AzGSDf
WaFljjCucht/d7u5empAd02haldUXWjT9RvY5RwnRZ+hjI47e+wUA0FMLHYtA1/0
cwEIvpp2xwF/jpH3ODmnIGEeNoLyzAV7X0KAlSN8VRsh7igZRB9TRGI67aTjRgk8
ayf/QNxAzwEk1MeDv67IFKNYVolxHCt4CtqISQQYEQIACQUCTV77UwIbDAAKCRC3
Q0sGz0xP+dPiAKDUNJ5rkB9CRoMH9BC35d0fqXXeugCgwl/HYv52dWgatbyEGLet
etv5Qeg=
=nIAo
Version: GnuPG v1.4.6 (GNU/Linux)

mQGiBD5gtCgRBACKIvjMF+20r9k/Uw2Hq6Y/qn1nM0AZEFalhglXP5pMm5bMgkcI
1vCWqJxSbhQhk8hSEenoszes8hyUxHj4hFFUDiRtAxOpCpGCsCnUddgQtHAQd+tm
aQsM6J3Jm/EZPtwR0lvwvRGvz2x6Rr95G8+42KK9x+mBYhLk0y3gAbBzhwCgnkDH
a97MGBT7gRLrmtFqiHrWlPkD/2tBaH6IEuoJhcAbNj9MukbhDOYJ6ic9Nzf6sR3t
ZG+XgQLLS2DNy8+HWcYJOjpJDEe8zWFDdUv3cL1D0U2f2e85FuJaMucHn+816iw8
mNjZXJEoDE4LJ8Vv53fkevNZpdWmO2VtRwI+woDnIHYHukDLj2sWhVt+5W+uOKAE
OippA/9OzuWrwBtTR+Np8ApZGkxhxU1z0iEStV+kQNqJE7YoR4SGMuzEa3bFzrPx
k4qIU+rw4YgFgHrs1x08lXxNOZkq6avvbl60HqN2qF2UQL/YdU+5X3ixaJVaYYk8
yuK+hp0Hx2DdBWmVhq6rEzIfpnFhF4qspwMWEiiBGjYDL62W7LQ0QVRycG1zLm5l
dCAocnBtIHNpZ25pbmcga2V5KSA8QXhlbC5UaGltbUBBVHJwbXMubmV0PohnBBMR
AgAnAhsDBgsJCAcDAgMVAgMDFgIBAh4BAheAAhkBBQJFfF9PBQkJGI4nAAoJEFCM
5eZmU0wrJ0IAnA0BdyRlq2S8ess55R8YMFnWAWXEAJ9Fa7cEHku4j4B83shCODps
+DYUZohnBBMRAgAnAhsDBQkDdMLsBgsJCAcDAgMVAgMDFgIBAh4BAheABQJAKteu
AhkBAAoJEFCM5eZmU0wrMMUAnRjS2PXQp0tsC/69IGMMxqU+8xeAAJ9XQjVAo+mU
kg/3AeBlMBIlFe5hDQ==
=23Fz
Version: GnuPG v1.2.6 (GNU/Linux)

mQGiBEY5QQ0RBACfC1NbAdGFMOS/Y7P9hmNph2Wh3TJTh6IZpL+lTJBuZSEa6rp0
CghS/yU3gGXUPaxAy91M7PXMv5p7S3U/SusZHATLhFdU5J4LuWMf4IiBy9FOB/aj
Q1s5vZ/i3YFaqolXsRP8TgIu4Lzp/j3+KAxFb3gF7lz64J/Et2Jil0OQzwCgkn9i
SoPEM6d9SCFOidhUuTHUhM0D/3UXl/FKPVFrFzjslFpaN9NgArRrmXKTOBWEqMLy
12pbTzOtv+p17Ot51q4h0ebEWrmVJ/h/7Is6QT6AKHuOIW+1/88fcSrmef//0Scz
wtEwVudkYA+kOGt1pwhapVYf1lWE9Z6L3V/MVdxXUesylGO6jJjOjpUB+ZBItwl7
exkhA/4iemhq4D5Jp6r1Kv3aKSPNENdhTORyfZz4UfyOsUfYncaprP5IZja0j+rd
tQLIsH8hXvCT2kSAUY6nMGmzPgpgGamtHI6gH1ZmoNX2gEF7tzGNgKMbbUmwO89B
N56U7wm68AreXE8XviRjGjAtZWnouqe5X+EiUurdJkzRwU0c2rQpVGhvdWdodFdv
cmtzIDxydWJ5d29ya3NAdGhvdWdodHdvcmtzLmNvbT6IYAQTEQIAIAUCRjlBDQIb
AwYLCQgHAwIEFQIIAwQWAgMBAh4BAheAAAoJEHM/KlUQbeB0SSYAn0sgAx5ZK975
wZiChkIqOCyFZ9PLAJ9laivkzqT2y+Kh9FGe3TP/CAhRTbkCDQRGOUEVEAgAqxJI
MFrYV3JKyeXHVKXHNd5Nf1WdqKi37VOdSTBftiehzZdR9hxkGEknYxnbBLGJR9YD
/uJ2+DRwNBcw2RrrEmb0DCZxcLQLZ3xYa7+WvcR4/Nir/3858SGJ+wmGCHKyX2So
M2TurmKu5bqyUUaBgf+IhKfwOr9zeK3rIRhUq/aiYkw8sWA8ruUvxXwLnbkK1aP9
hfvSqScwjkfUVk6CQ6GFUD+4N4mNRtRcZz3gYa+0jSNeEJZQOJxRuE/gBHav3eyN
dm4VAFPF20BobvBVEcMhO0KaR/X4jW1G1eFAKLxI7cdx3+vLeNPaFwHiSMSknsNs
UiucI9oV+I5S/50ZrwADBwf/StYTK9KvPnY9ZqmirBpSh0Zl0xylMtAiMblG7pKv
qKTPNr9zXooheQBpAbnhOfju0DB/OtE4V21HqnbMws2aFvHecEbO5EmjwT7ZTltH
5vlbiPrXOc7SpP22FdkOYdunM2+nsA6398mpYFEiFFNAzX6pReN2tbbmXf6zxS9n
nHjMAgl5nMuOASLZrTrUX/7yu6ySS1hy0ZVfEoAFeILy4MV8y0lVjBQa2kNOCNpO
Cc+y1+4EHLS3fuN0x+tho3rhjKAzj8KOt4XnALn8OouRMx9G7ItC2U8kNzHHFRg5
adT/+nEthVd9q9pYLrUaze7aMQyl+7cD1KzmSe34X9B6W4hJBBgRAgAJBQJGOUEV
AhsMAAoJEHM/KlUQbeB0O7QAn09h4qrKPhWD9eaiyMRS5YeARTYgAJ9WxLcQEvkA
yOSLb33CweehCrlTnQ==
=scSy
Version: GnuPG v1.2.6 (GNU/Linux)

mQGiBEXopTIRBACZDBMOoFOakAjaxw1LXjeSvh/kmE35fU1rXfM7T0AV31NATCLF
l5CQiNDA4oWreDThg2Bf6+LIVTsGQb1V+XXuLak4Em5yTYwMTVB//4/nMxQEbpl/
QB2XwlJ7EQ0vW+kiPDz/7pHJz1p1jADzd9sQQicMtzysS4qT2i5A23j0VwCg1PB/
lpYqo0ZhWTrevxKMa1n34FcD/REavj0hSLQFTaKNLHRotRTF8V0BajjSaTkUT4uk
/RTaZ8Kr1mTosVtosqmdIAA2XHxi8ZLiVPPSezJjfElsSqOAxEKPL0djfpp2wrTm
l/1iVnX+PZH5DRKCbjdCMLDJhYap7YUhcPsMGSeUKrwmBCBJUPc6DhjFvyhA9IMl
1T0+A/9SKTv94ToP/JYoCTHTgnG5MoVNafisfe0wojP2mWU4gRk8X4dNGKMj6lic
vM6gne3hESyjcqZSmr7yELPPGhI9MNauJ6Ob8cTR2T12Fmv9w03DD3MnBstR6vhP
QcqZKhc5SJYYY7oVfxlSOfF4xfwcHQKoD5TOKwIAQ6T8jyFpKbQkRmVkb3JhIEVQ
RUwgPGVwZWxAZmVkb3JhcHJvamVjdC5vcmc+iGQEExECACQFAkXopTICGwMFCRLM
AwAGCwkIBwMCAxUCAwMWAgECHgECF4AACgkQEZzANiF1IfabmQCgzvE60MnHSOBa
ZXXF7uU2Vzu8EOkAoKg9h+j0NuNom6WUYZyJQt4zc5seuQINBEXopTYQCADapnR/
blrJ8FhlgNPl0X9S3JE/kygPbNXIqne4XBVYisVp0uzNCRUxNZq30MpY027JCs2J
nL2fMpwvx33f0phU029vrIZKA3CmnnwVsjcWfMJOVPBmVN7m5bGU68F+PdRIcDsl
PMOWRLkTBZOGolLgIbM4719fqA8etewILrX6uPvRDwywV7/sPCFpRcfNNBUY+Zx3
5bf4fnkaCKxgXgQS3AT+hGYhlzIqQVTkGNveHTnt4SSzgAqR9sSwQwqvEfVtYNeS
w5rDguLG41HQm1Hojv59HNYjH6F/S1rClZi21bLgZbKpCFX76qPt8CTw+iQLBPPd
yoOGHfzyp7nsfhUrAAMFB/9/H9Gpk822ZpBexQW4y3LGFo9ZSnmu+ueOZPU3SqDA
DW1ovZdYzGuJTGGM9oMl6bL8eZrcUBBOFaWge5wZczIE3hx2exEOkDdvq+MUDVD1
axmN45q/7h1NYRp5GQL2ZsoV4g9U2gMdzHOFtZCER6PP9ErVlfJpgBUCdSL93V4H
Sgpkk7znmTOklbCM6l/G/A6q4sCRqfzHwVSTiruyTBiU9lfROsAl8fjIq2OzWJ2T
P9sadBe1llUYaow7txYSUxssW+89avct35gIyrBbof5M+CBXyAOUaSWmpM2eub24
0qbqiSr/Y6Om0t6vSzR8gRk7g+1H6IE0Tt1IJCvCAMimiE8EGBECAA8FAkXopTYC
GwwFCRLMAwAACgkQEZzANiF1IfZQYgCgiZHCv4xb+sTHCn/otc1Ovvi/OgMAnRXY
bbsLFWOfmzAnNIGvFRWy+YHi
=MMNL
Version: GnuPG v1.2.6 (GNU/Linux)

mQGiBEWfB6MRBACrnYW6yKMT+MwJlCIhoyTxGf3mAxmnAiDEy6HcYN8rivssVTJk
CFtQBlBOpLV/OW2YtKrCO2xHn46eNfnMri8FGT8g+9JF3MUVi7kiV1He4iJynHXB
+F2ZqIvHf3IaUj1ys+p8TK64FDFxDQDrGQfIsD/+pkSGx53/877IrvdwjwCguQcr
Ioip5TH0Fj0OLUY4asYVZH8EAIqFHEqsY+9ziP+2R3/FyxSllKkjwcMLrBug+cYO
LYDD6eQXE9Mq8XKGFDj9ZB/0+JzK/XQeStheeFG75q3noq5oCPVFO4czuKErIRAB
qKbDBhaTj3JhOgM12XsUYn+rI6NeMV2ZogoQCC2tWmDETfRpYp2moo53NuFWHbAy
XjETA/sHEeQT9huHzdi/lebNBj0L8nBGfLN1nSRP1GtvagBvkR4RZ6DTQyl0UzOJ
RA3ywWlrL9IV9mrpb1Fmn60l2jTMMCc7J6LacmPK906N+FcN/Docj1M4s/4CNanQ
NhzcFhAFtQL56SNyLTCk1XzhssGZ/jwGnNbU/aaj4wOj0Uef5LRGQ2VudE9TLTUg
S2V5IChDZW50T1MgNSBPZmZpY2lhbCBTaWduaW5nIEtleSkgPGNlbnRvcy01LWtl
eUBjZW50b3Mub3JnPohkBBMRAgAkBQJFnwekAhsDBQkSzAMABgsJCAcDAgMVAgMD
FgIBAh4BAheAAAoJEKikR9zoViiXKlEAmwSoZDvZo+WChcg3s/SpNoWCKhMAAJwI
E2aXpZVrpsQnInUQWwkdrTiL5YhMBBMRAgAMBQJFnwiSBYMSzAIRAAoJEDjCFhY5
bKCk0hAAn134bIx3wSbq58E6P6U5RT7Z2Zx4AJ9VxnVkoGHkVIgSdsxHUgRjo27N
F7kBDQRFnwezEAQA/HnJ5yiozwgtf6jt+kii8iua+WnjqBKomPHOQ8moxbWdv5Ks
4e1DPhzRqxhshjmub4SuJ93sgMSAF2ayC9t51mSJV33KfzPF2gIahcMqfABe/2hJ
aMzcQZHrGJCEX6ek8l8SFKou7vICzyajRSIK8gxWKBuQknP/9LKsoczV+xsAAwUD
/idXPkk4vRRHsCwc6I23fdI0ur52bzEqHiAIswNfO521YgLk2W1xyCLc2aYjc8Ni
nrMX1tCnEx0/gK7ICyJoWH1Vc7//79sWFtX2EaTO+Q07xjFX4E66WxJlCo9lOjos
Vk5qc7R+xzLDoLGFtbzaTRQFzf6yr7QTu+BebWLoPwNTiE8EGBECAA8FAkWfB7MC
GwwFCRLMAwAACgkQqKRH3OhWKJfvvACfbsF1WK193zM7vSc4uq51XsceLwgAoI0/
9GxdNhGQEAweSlQfhPa3yYXH
=o/Mx

Version: GnuPG v1.2.6 (GNU/Linux)

mQGiBEXopTIRBACZDBMOoFOakAjaxw1LXjeSvh/kmE35fU1rXfM7T0AV31NATCLF
l5CQiNDA4oWreDThg2Bf6+LIVTsGQb1V+XXuLak4Em5yTYwMTVB//4/nMxQEbpl/
QB2XwlJ7EQ0vW+kiPDz/7pHJz1p1jADzd9sQQicMtzysS4qT2i5A23j0VwCg1PB/
lpYqo0ZhWTrevxKMa1n34FcD/REavj0hSLQFTaKNLHRotRTF8V0BajjSaTkUT4uk
/RTaZ8Kr1mTosVtosqmdIAA2XHxi8ZLiVPPSezJjfElsSqOAxEKPL0djfpp2wrTm
l/1iVnX+PZH5DRKCbjdCMLDJhYap7YUhcPsMGSeUKrwmBCBJUPc6DhjFvyhA9IMl
1T0+A/9SKTv94ToP/JYoCTHTgnG5MoVNafisfe0wojP2mWU4gRk8X4dNGKMj6lic
vM6gne3hESyjcqZSmr7yELPPGhI9MNauJ6Ob8cTR2T12Fmv9w03DD3MnBstR6vhP
QcqZKhc5SJYYY7oVfxlSOfF4xfwcHQKoD5TOKwIAQ6T8jyFpKbQkRmVkb3JhIEVQ
RUwgPGVwZWxAZmVkb3JhcHJvamVjdC5vcmc+iGQEExECACQFAkXopTICGwMFCRLM
AwAGCwkIBwMCAxUCAwMWAgECHgECF4AACgkQEZzANiF1IfabmQCgzvE60MnHSOBa
ZXXF7uU2Vzu8EOkAoKg9h+j0NuNom6WUYZyJQt4zc5seuQINBEXopTYQCADapnR/
blrJ8FhlgNPl0X9S3JE/kygPbNXIqne4XBVYisVp0uzNCRUxNZq30MpY027JCs2J
nL2fMpwvx33f0phU029vrIZKA3CmnnwVsjcWfMJOVPBmVN7m5bGU68F+PdRIcDsl
PMOWRLkTBZOGolLgIbM4719fqA8etewILrX6uPvRDwywV7/sPCFpRcfNNBUY+Zx3
5bf4fnkaCKxgXgQS3AT+hGYhlzIqQVTkGNveHTnt4SSzgAqR9sSwQwqvEfVtYNeS
w5rDguLG41HQm1Hojv59HNYjH6F/S1rClZi21bLgZbKpCFX76qPt8CTw+iQLBPPd
yoOGHfzyp7nsfhUrAAMFB/9/H9Gpk822ZpBexQW4y3LGFo9ZSnmu+ueOZPU3SqDA
DW1ovZdYzGuJTGGM9oMl6bL8eZrcUBBOFaWge5wZczIE3hx2exEOkDdvq+MUDVD1
axmN45q/7h1NYRp5GQL2ZsoV4g9U2gMdzHOFtZCER6PP9ErVlfJpgBUCdSL93V4H
Sgpkk7znmTOklbCM6l/G/A6q4sCRqfzHwVSTiruyTBiU9lfROsAl8fjIq2OzWJ2T
P9sadBe1llUYaow7txYSUxssW+89avct35gIyrBbof5M+CBXyAOUaSWmpM2eub24
0qbqiSr/Y6Om0t6vSzR8gRk7g+1H6IE0Tt1IJCvCAMimiE8EGBECAA8FAkXopTYC
GwwFCRLMAwAACgkQEZzANiF1IfZQYgCgiZHCv4xb+sTHCn/otc1Ovvi/OgMAnRXY
bbsLFWOfmzAnNIGvFRWy+YHi
=MMNL
Version: GnuPG v2.0.14 (GNU/Linux)

mQGiBEZ6qawRBAC2gDuA1sZioGh1VP/U0l+9RmzOdkWBGB3NfWqezAwt1Up+cP5o
h+UNkghOKbJVQ/zLyY/edYOppQ78yxT1X/J1RHNhs5bjqzWlQxMbT5/tt1N4PExu
gvO38RGFTV0DqIy3lQw5YIwp2le+G8MktYh2NKI4lG0AJoXZicNlI7+mEwCgmfw+
CnsB/kb/xUD1dq6Mo3dYXVcEAKSFfqt+6jvJNxcIYfpQqjEslQsQmPKpXzK9CPyV
UCjUEOirbhPxV86u3Ge/yuy5USMvTTs+ztImabbH6UHBEP+tEw3LiuPUpfh+nEna
3Hz+U81PvUwGEwUMzCr+OemBXqGW7jl66NqKqm8YM3Pkvc4NlS/7slky9A/s6i8S
hToWA/9kP55aSbIXte5TbC88lx6YuLx7qW541ni38DmJfPN5hHywLGnM82MMQMbk
hg1v49+7TTNv44LJpGT7t8gsW9F4Z4rWoChhsldypeeqbDOIv4kFiXt/8122Ud9J
nE67CR9XUuS5Jp+gP6xxNr9/vbvqsOGMJAQkVgkBPVuKYv25gLQ3U2VyZ2lvIFJ1
YmlvIChGcmFtZU9TIERldmVsb3BlcnMpIDxydWJpb2pyQGZyYW1lb3Mub3JnPohr
BBMRAgArAhsDBQkGE0x0BgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAUCTBs76AIZ
AQAKCRCOw9dP80W+dFhjAJ0dKy761iPcG+ALwEAuAgxDpUVBzgCdFxGCAZ7ELYvf
3uFc0Ou2ihDzvyy0IFNlcmdpbyBSdWJpbyA8c2VyZ2lvQHJ1YmlvLm5hbWU+iGYE
ExECACYCGwMGCwkIBwMCBBUCCAMEFgIDAQIeAQIXgAUJBhNMdAUCTBs7XgAKCRCO
w9dP80W+dDdtAJ9NYoW1ChfMyES7nQUlesEQ4aWXjQCeIoGxoOuIGyg6+AKr/2Wr
6fE1zt2IaQQTEQIAKQIbAwYLCQgHAwIEFQIIAwQWAgMBAh4BAheAAhkBBQJIHsGo
BQkCuHFEAAoJEI7D10/zRb50KjgAnRTzzNIODKqrHnrHaUG8dWDCwmYjAJ48Hbcn
ZC6E8LGTeM8vPN0mMI9ijLkCDQRGeqm2EAgAh720kjA9bNDms+6agb6CirD9RkmZ
3G+OHd5iia3KbaUiBtC3PECg4UE8N54JuBNKdjgJQfdYSg2J0EZHyhZHdAVWjykE
tj/IKZKnAfUqKh44uT9OUPW8PChPo/gioLn+DexSAW7n19h7VIa1P3shYqYR/gz8
zgfrXkFFpkpKnOLsXuF20JEEBIBdwrfYRJIBrUTYrfS/2GKLJjyutENkb9uI3JgQ
LfR6DckTaar4eeArjgvOxZRHiU0vRezetlbG8ZM9mSYrcMM3Xa5vLpFlDj6vYzat
RWEuZUfLgXWUVoVyFiNVXhpff/w7/bAb3WpXqjZd6sK8CCJJPNtnbLE7CwADBQf9
EQjT9iiEZis35V9HqeLsxXVjPOGNuLiwjIpacI7CM3aGV1q7NXiCE4oWS/PvpHmu
W+XdXMPH4Bt2VmjZSarlAipTeNnOuiEXipUFIjAlNn1xNVRRd7T35zIvXLtmNtUe
nN1/mqZljKPbCbW1AgktH417t/vJfTnRWr9IgS3Am+o4q200i+1FjrQ/UI3s9+vg
5B+KASFP6HspNttl0kwzQ6SFIHAebd4DKHOj6ShxXPNl18W4R8qPqayrAFqdkgMJ
Jn8j2E8rmGYnssSfjck2kLtvNdTEAMjFnhg+oUapUzJAVeterudiWZFNrtn9ewnf
8SUiiYJlxb+nz545zo0gQIhJBBgRAgAJBQJGeqm2AhsMAAoJEI7D10/zRb50PJEA
mwTA+Sp3wvzwDr8sk7W7U4bBfw26AKCVoYw3mfTime+j3mFk1yk1yxjE2Q==
=iyOs

Version: GnuPG v1.2.6 (GNU/Linux)

mQGiBEWfBuERBACrwDH+6QvpyaOgzhXiemsIX+q4HlhX/HDmrmZOUd7i9VmZNogP
6LRRiTygn2+UphaGV3NDA36ZB/1JRpgvgpzbpZNeAoFvsljIbxGIwkH2JgRF6oNo
eGB3QYzDQJvYVIejk79M0ed3oor4w8OiNVcdxLyVIthFrjrrCqwRP3bLZwCgtY9t
Ezf5WL63Ue45vdht7A2GH+0D/iNAnWKsU7FUMFZrcwMaMbyP7YG8z0+zXUOgtgyP
tbgJG5yikNT3vJypb42gbKfcriUUDC5AeiRmkR8QPvYuOm34rM90+wx2LGqXWnHM
IyLAyl8TS3MQmePem8bfTGTNYxtt3Q7iadez2WYTLBSlmM6hbxZfdwm1hhyM0AJU
YyFUA/9kHH+CUBxKb1UgG7TSp53Po/5p/Yyuty+RJ7zIGv6SiN/JK4/ntWfm5WS5
ZprSdE5ODoFQ/Gs3/VB/eolg2fBW1DcftH6lKHT3GKEOaicGX+T9eOMerZZedm5U
vDA9mFvWnOdOxK8LuRgVqip4jCnWICchpatmdP0whJQHQ6MGLLRMQ2VudE9TLTUg
QmV0YSBLZXkgKENlbnRPUyA1IEJldGEgU2lnbmluZyBLZXkpIDxjZW50b3MtNS1i
ZXRhLWtleUBjZW50b3Mub3JnPohkBBMRAgAkBQJFnwbhAhsDBQkSzAMABgsJCAcD
AgMVAgMDFgIBAh4BAheAAAoJEM/aaIEJLXsrWDkAoKcqa+AAdAWvp5qlJkGQiRy8
aNFDAJ4qRfIxMiLinmjbqcuygWMp61wY5ohMBBMRAgAMBQJFnwhtBYMSzAF0AAoJ
EDjCFhY5bKCkG/wAn14LDlJqjZv1Wz0WNfhr80+qJrf6AKCaIZExwo4ApQpESk/F
SApLd/pEILkBDQRFnwbrEAQAwKzjI2aTB/sS9HuQ4CHCwrj4vr0HxMMwQikYBIvy
MYTtek04KDTKoJL5g3411DsfDW9VRGJdFCHvldgam/5UVfO6nywLkdwAA5TQA5dv
8YE8jTtwdy5Y1QKFc8LaIBZK0+ZbhEvdNfv67egvfcxZc5PvpBZ3C03n+iQ3wPcg
PhcAAwUD/iYkq4LG/je43Qa5rTz5kF5rIiX7Bk5vXT7XSFOFKwHy8V+PGEoVM1W8
+EHIlmTycwIlsVp3by6qCDkMYu4V6VukxZNzJyeoMICiYIXUPh6NKHRoqaYlu6ZO
eFN1TQNXmodPk+iNtdbcby/zAklNqoO/dWSwd8NAo8s6WAHq3VPpiE8EGBECAA8F
AkWfBusCGwwFCRLMAwAACgkQz9pogQkteysXkACgoraCU0EBC+W8TuxrsePO20ma
D0IAoLRRQLTEXL0p3K0WE+LfyTr9EVG5
=mH0S

Version: GnuPG v1.2.6 (GNU/Linux)

mQGiBEIu6hwRBACOz2JFa1nW+seAKlVGOu0ykhdFVNI9E4/Abp2+8nsJIZyUwLAp
ei76rPD8WdptgIjtYOCsqz1TbP+eqeEG0LLihOdFRLUuAjQX4X7LLf5Qm+nvUB73
uLbSf9Ptps2CMUEtu7+0wVoTbuC19HXUhUr5sRdCnJbPJBH6aAHG7Pl9ZwCguN9o
V7IKTnIQiZg0nxSjZ4V9e6UD/R7KoMwH3NPQQF7T7rJaBjSZcVHUPhAcNPNn+ms/
Tw9mzHZ0mnQnOzSEW0ZUj9TkLN52VQ3WmGZKAv9yeVr0/230YIgmtH863lSystmk
LNO9brK0+3vKg5GRpV0/MSWSmf39WPAS1hXNXIFfYp1eGHUfed4FVNxrMTWHQozr
8JosA/wP+zGfM51bSAazLUqP/MEm7F9OFkuD7Sw97w55FyYlrPp1FQWrWczoiKHr
wS5NRCQbCGEEM/+j9id6CukxPLXxwMYCfeg5K0HxMaQT6hxbwjOzAzN3PBFytNel
09qdrdoSDa35twT0SAt+rzM+zvRI8ycizFG3lIih4UItWWve2bQ6S2FyYW5iaXIg
U2luZ2ggKGh0dHA6Ly93d3cua2FyYW4ub3JnLykgPGtic2luZ2hAa2FyYW4ub3Jn
PoheBBMRAgAeBQJCLuocAhsDBgsJCAcDAgMVAgMDFgIBAh4BAheAAAoJEDANvZ4+
E89b/P4AnjufrDCS+TAEL0KpkYDURePbDCHBAJ4+0iI1Td4YrcnLwmQ1+XDCJ3Zr
a7kBDQRCLuocEAQAjAl48FM9eGtP6M9FgswlSPAuCcJct6wOHmd/qZ923HckJPAD
zIFRMlM6H8P0bKoaIluv7agZM7Gsf8NeTg3NEeMKqnibIAyvjYeSkceRIwvBCQ3A
YwWk+B2zLUAFMxnE31oA10zjCKUo7Dc6XDUxSY/qdLymZzyG/Ndav+vMOVsAAwUD
/RCFDuW/GSM/s3DO7XxrOBRTGQmf9v9tCYdZZD615+s8ghaa5oZTvp1cbTTWiSq8
ybncfjVHz9HezDgQjJsFZtrYd4w2JD+7K0+8sZ+BUGo1dDSv4UgN8ACtaGJnShiq
s8pQWRZFqFa3waay8oUSTKHiTHdpxLi3x4HhK/8MTsxniEkEGBECAAkFAkIu6hwC
GwwACgkQMA29nj4Tz1tHSgCcDgKL4swEu7ShvI8nZt2JLmTKB5QAn0qZi2zbexbi
DX+bbalHM+xVnXZN
=rZT6
Version: GnuPG v1.4.7 (GNU/Linux)

mQGiBEJny1wRBACRnbQgZ6qLmJSuGvi/EwrRL6aW610BbdpLQRL3dnwy5wI5t9T3
/JEiEJ7GTvAwfiisEHifMfk2sRlWRf2EDQFttHyrrYXfY5L6UAF2IxixK5FL7PWA
/2a7tkw1IbCbt4IGG0aZJ6/xgQejrOLi4ewniqWuXCc+tLuWBZrGpE2QfwCggZ+L
0e6KPTHMP97T4xV81e3Ba5MD/3NwOQh0pVvZlW66Em8IJnBgM+eQh7pl4xq7nVOh
dEMJwVU0wDRKkXqQVghOxALOSAMapj5mDppEDzGLZHZNSRcvGEs2iPwo9vmY+Qhp
AyEBzE4blNR8pwPtAwL0W3cBKUx7ZhqmHr2FbNGYNO/hP4tO2ochCn5CxSwAfN1B
Qs5pBACOkTZMNC7CLsSUT5P4+64t04x/STlAFczEBcJBLF1T16oItDITJmAsPxbY
iee6JRfXmZKqmDP04fRdboWMcRjfDfCciSdIeGqP7vMcO25bDZB6x6++fOcmQpyD
1Fag3ZUq2yojgXWqVrgFHs/HB3QE7UQkykNp1fjQGbKK+5mWTrQkUmVtaSBDb2xs
ZXQgPFJQTVNARmFtaWxsZUNvbGxldC5jb20+iGAEExECACAFAkZ+MYoCGwMGCwkI
BwMCBBUCCAMEFgIDAQIeAQIXgAAKCRAATm9HAPl/Vv/UAJ9EL8ioMTsz/2EPbNuQ
MP5Xx/qPLACeK5rk2hb8VFubnEsbVxnxfxatGZ25AQ0EQmfLXRAEANwGvY+mIZzj
C1L5Nm2LbSGZNTN3NMbPFoqlMfmym8XFDXbdqjAHutGYEZH/PxRI6GC8YW5YK4E0
HoBAH0b0F97JQEkKquahCakj0P5mGuH6Q8gDOfi6pHimnsSAGf+D+6ZwAn8bHnAa
o+HVmEITYi6s+Csrs+saYUcjhu9zhyBfAAMFA/9Rmfj9/URdHfD1u0RXuvFCaeOw
CYfH2/nvkx+bAcSIcbVm+tShA66ybdZ/gNnkFQKyGD9O8unSXqiELGcP8pcHTHsv
JzdD1k8DhdFNhux/WPRwbo/es6QcpIPa2JPjBCzfOTn9GXVdT4pn5tLG2gHayudK
8Sj1OI2vqGLMQzhxw4hJBBgRAgAJBQJCZ8tdAhsMAAoJEABOb0cA+X9WcSAAn11i
gC5ns/82kSprzBOU0BNwUeXZAJ0cvNmY7rvbyiJydyLsSxh/la6HKw==
=6Rbg
The following public key can be used to verify RPM packages
downloaded from  http://dag.wieers.com/apt/  using 'rpm -K'
if you have the GNU GPG package.
Questions about this key should be sent to:
Dag Wieers <dag@wieers.com>

Version: GnuPG v1.2.1 (GNU/Linux)

mQGiBD9JMT0RBAC9Q2B0AloUMTxaK73sD0cOu1MMdD8yuDagbMlDtUYA1aGeJVO6
TV02JLGr67OBY+UkYuC1c3PUwmb3+jakZd5bW1L8E2L705wS0129xQOZPz6J+alF
5rTzVkiefg8ch1yEcMayK20NdyOmhDGXQXNQS8OJFLTIC6bJs+7MZL83/wCg3cG3
3q7MWHm3IpJb+6QKpB9YH58D/2WjPDK+7YIky/JbFBT4JPgTSBy611+bLqHA6PXq
39tzY6un8KDznAMNtm+NAsr6FEG8PHe406+tbgd7tBkecz3HPX8nR5v0JtDT+gzN
8fM3kAiAzjCHUAFWVAMAZLr5TXuoq4lGTTxvZbwTjZfyjCm7gIieCu8+qnPWh6hm
30NgA/0ZyEHG6I4rOWqPks4vZuD+wlp5XL8moBXEKfEVOMh2MCNDRGnvVHu1P3eD
oHOooVMt9sWrGcgxpYuupPNL4Uf6B6smiLlH6D4tEg+qCxC17zABI5572XJTJ170
JklZJrPGtnkPrrKMamnN9MU4RjGmjh9JZPa7rKjZHyWP/z/CBrQ1RGFnIFdpZWVy
cyAoRGFnIEFwdCBSZXBvc2l0b3J5IHYxLjApIDxkYWdAd2llZXJzLmNvbT6IWQQT
EQIAGQUCP0kxPQQLBwMCAxUCAwMWAgECHgECF4AACgkQog5SFGuNeeYvDQCeKHST
hIq/WzFBXtJOnQkJGSqAoHoAnRtsJVWYmzYKHqzkRx1qAzL18Sd0iEYEEBECAAYF
Aj9JMWAACgkQoj2iXPqnmevnOACfRQaageMcESHVE1+RSuP3txPUvoEAoJAtOHon
g+3SzVNSZLn/g7/Ljfw+uQENBD9JMT8QBACj1QzRptL6hbpWl5DdQ2T+3ekEjJGt
llCwt4Mwt/yOHDhzLe8SzUNyYxTXUL4TPfFvVW9/j8WOkNGvffbs7g84k7a5h/+l
IJTTlP9V9NruDt1dlrBe+mWF6eCY55OFHjb6nOIkcJwKxRd3nGlWnLsz0ce9Hjrg
6lMrn0lPsMV6swADBQP9H42sss6mlqnJEFA97Fl3V9s+7UVJoAIA5uSVXxEOwVoh
Vq7uECQRvWzif6tzOY+vHkUxOBRvD6oIU6tlmuG3WByKyA1d0MTqMr3eWieSYf/L
n5VA9NuD7NwjFA1kLkoDwfSbsF51LppTMkUggzwgvwE46MB6yyuqAVI1kReAWw+I
RgQYEQIABgUCP0kxPwAKCRCiDlIUa4155oktAKDAzm9QYbDpk6SrQhkSFy016BjE
BACeJU1hpElFnUZCL4yKj4EuLnlo8kc=
=mqUt
Version: GnuPG v1.4.5 (GNU/Linux)

mQGiBE1e+1MRBAD8j+KyOIpGNRN39gNy2E/1HG4ZoLFuxIOxI5/1FEuZB/GjYF5m
DvJerZukd0QCqCs72J6J+uWnfD/52t2XWTw4IHPpCWeyr9TWex3uOYmrYzY+0l0l
qsCsrhT0XGkAE0+/20oEP2+t/d+1q0yRcYZRwWK/ME2rUUX0jOa/B3Bc6wCg3blw
XdZNrv1wVNd1PCOUI79k0V0D+wfbybos8Cmdv2f8dD746fSR/hmp4SzpBDmPRRQu
0gtJAKI6ycTdotGq5zHfZj76kDQBudeIgdbWtqfckP2lK47i8lIENAyC4MK8dxh9
Ts+b1LqXlbcPyixzImf4qoT5DT1lSEUPwoMRX8W/29GAcvnZpOwQ8g7DNmRBpFFY
8U2GBADz6uEeP3YwJAuL7pi77AalxR0WQAADMR59pGltQdXaZvANXoioU0W519Pb
nl3gKWDiTuwUDrwaSPoBbNLyX4s0AE7/0HSG02/eRjLB8toQpAH9xkK/u2WPe/do
erZg5yg1qhoCbEM7kJ2I/GBl6VbPedt2ORdsC4ZTWTnZJh6tYLQhQW5keSBUaG9t
cHNvbiA8YW5keUB3ZWJ0YXRpYy5jb20+iGAEExECACAFAk1e+1MCGwMGCwkIBwMC
BBUCCAMEFgIDAQIeAQIXgAAKCRC3Q0sGz0xP+TA0AJwJf5ZPeub8v+5CtZwdcZhV
LU0sjgCgrP3y54heBjF1vhZQ3rJywTmRLHe5Ag0ETV77UxAIAIQPLVFbqheJ90Kf
NF8TYt3ZIMpP5chw25OYq4tuZMzVJxKjUlM7KPQxUKquY/F9WpjH980LmICTb4Fz
txzn2bshIsGyg8pDUSnVK0NPY5uaq9bK4oht8wkr3FNFT2FpeqDIJyn+phIuEpIi
qt1LJyzzjobh9csaaGmNHvtrlkIggBj2n/ZQuGNhcYnKUZ/WGmkItCTSOfA++G+C
dCo1aPEymfbnJvaLB/mLyzA+r/r7LQM10cZEtqh5JdclJEh3CzZmx9HsRxCDZF8W
X/C4MmCwmIxmuU4vkVNhHFTQimQEUR8vg9ltiz8+xBjyE1Iav4MxfOYh3xjdJk1d
zlovyUcAAwUH/2KPgf0UQ1o+4IjOYinEEbNlrD1pKw5anUKwaaeQi0vm/oRG0E2F
ZCJ73OHxW/0hMrwbrGwXcm4NBARnAppg+/CecOVpkBgD5hrM+11DPhxdd1bjjfza
Pq8GmPp8SSsiTPUCoSlzojxL3Z05RNbvKVzxzxbYdx5h5XOTflI7bAHTY4AzGSDf
WaFljjCucht/d7u5empAd02haldUXWjT9RvY5RwnRZ+hjI47e+wUA0FMLHYtA1/0
cwEIvpp2xwF/jpH3ODmnIGEeNoLyzAV7X0KAlSN8VRsh7igZRB9TRGI67aTjRgk8
ayf/QNxAzwEk1MeDv67IFKNYVolxHCt4CtqISQQYEQIACQUCTV77UwIbDAAKCRC3
Q0sGz0xP+dPiAKDUNJ5rkB9CRoMH9BC35d0fqXXeugCgwl/HYv52dWgatbyEGLet
etv5Qeg=
=nIAo
Version: GnuPG v1.2.1 (GNU/Linux)

mQGiBEGP+skRBACyZz7muj2OgWc9FxK+Hj7tWPnrfxEN+0PE+n8MtqH+dxwQpMTd
gDpOXxJa45GM5pEwB6CFSFK7Fb/faniF9fDbm1Ga7MpBupIBYLactkoOTZMuTlGB
T0O5ha4h26YLqFfQOtlEi7d0+BDDdfHRQw3o67ycgRnLgYSA79DISc3MywCgk2TR
yd5sRfZAG23b4EDl+D0+oaMEAK73J7zuxf6F6V5EaxLd/w4JVB2xW0Glcn0fACOe
8FV9lzcZuo2xPpdGuyj02f/xlqvEav3XqTfFU2no61mA2pamaRNhlo+CEfGc7qde
/1twfSgOYqzeCx7+aybyPo8Th41b80FT19mfkjBf6+5NbUHffRabFFh1FmcPVNBn
F3FoA/95nRIzqDMItdTRitaZn02dIGNjdwllBD75bSVEvaR9O5hjBo0VMc25DB7f
DM2qEO52wCQbAKw9zFC284ekZVDaK4aHYt7iobHaqJEpKHgsDut5WWuMiSLR+SsF
aBHIZ9HvrKWLSUQKHU6A1Hva0P0r3GnoCMc/VCVfrLl721SjPbQzQXRvbWljIFJv
Y2tldCBUdXJ0bGUgPGFkbWluQGF0b21pY3JvY2tldHR1cnRsZS5jb20+iFkEExEC
ABkFAkGP+skECwcDAgMVAgMDFgIBAh4BAheAAAoJEDKpURRevSdEzcQAn1hSHqTO
jwv/z/picpOnR+mgycwHAKCBex2ciyXo5xeaQ9w7OMf7Jsmon7kBDQRBj/rMEAQA
6JvRndqE4koK0e49fUkICm1X0ZEzsVg9VmUW+Zft5guCRxmGlYTmtlC7oJCToRP/
m/xH5uIevGiJycRKB0Ix+Csl6f9QuTkQ7tSTHcaIKbI3tL1x6CCBoWeTGYaOJlvk
ubrmajiMFaBfopLH2firoSToDGoUvv4e7bImIHEgNr8AAwUEAND0YR9DOEZvc+Lq
Ta/PQyxkdZ75o+Ty/O64E3OmO1Tuw2ciSQXCcwrbrMSE6EHHetxtGCnOdkjjjtmH
AnxsxdONv/EJuQmLcoNcsigZZ4tfRdmtXgcbnOmXBgmy1ea1KvWcsmecNSAMJHwR
7vDDKzbj4mSmudzjapHeeOewFF10iEYEGBECAAYFAkGP+swACgkQMqlRFF69J0Sq
nQCfa/q9Y/oY4dOTGj6MsdmRIQkKZhYAoIscjinFwTru4FVi2MIEzUUMToDK
=NOIx
Version: GnuPG v1.4.6 (GNU/Linux)

mQGiBD5gtCgRBACKIvjMF+20r9k/Uw2Hq6Y/qn1nM0AZEFalhglXP5pMm5bMgkcI
1vCWqJxSbhQhk8hSEenoszes8hyUxHj4hFFUDiRtAxOpCpGCsCnUddgQtHAQd+tm
aQsM6J3Jm/EZPtwR0lvwvRGvz2x6Rr95G8+42KK9x+mBYhLk0y3gAbBzhwCgnkDH
a97MGBT7gRLrmtFqiHrWlPkD/2tBaH6IEuoJhcAbNj9MukbhDOYJ6ic9Nzf6sR3t
ZG+XgQLLS2DNy8+HWcYJOjpJDEe8zWFDdUv3cL1D0U2f2e85FuJaMucHn+816iw8
mNjZXJEoDE4LJ8Vv53fkevNZpdWmO2VtRwI+woDnIHYHukDLj2sWhVt+5W+uOKAE
OippA/9OzuWrwBtTR+Np8ApZGkxhxU1z0iEStV+kQNqJE7YoR4SGMuzEa3bFzrPx
k4qIU+rw4YgFgHrs1x08lXxNOZkq6avvbl60HqN2qF2UQL/YdU+5X3ixaJVaYYk8
yuK+hp0Hx2DdBWmVhq6rEzIfpnFhF4qspwMWEiiBGjYDL62W7LQ0QVRycG1zLm5l
dCAocnBtIHNpZ25pbmcga2V5KSA8QXhlbC5UaGltbUBBVHJwbXMubmV0PohnBBMR
AgAnAhsDBgsJCAcDAgMVAgMDFgIBAh4BAheAAhkBBQJFfF9PBQkJGI4nAAoJEFCM
5eZmU0wrJ0IAnA0BdyRlq2S8ess55R8YMFnWAWXEAJ9Fa7cEHku4j4B83shCODps
+DYUZohnBBMRAgAnAhsDBQkDdMLsBgsJCAcDAgMVAgMDFgIBAh4BAheABQJAKteu
AhkBAAoJEFCM5eZmU0wrMMUAnRjS2PXQp0tsC/69IGMMxqU+8xeAAJ9XQjVAo+mU
kg/3AeBlMBIlFe5hDQ==
=23Fz
Version: GnuPG v1.2.6 (GNU/Linux)

mQGiBEY5QQ0RBACfC1NbAdGFMOS/Y7P9hmNph2Wh3TJTh6IZpL+lTJBuZSEa6rp0
CghS/yU3gGXUPaxAy91M7PXMv5p7S3U/SusZHATLhFdU5J4LuWMf4IiBy9FOB/aj
Q1s5vZ/i3YFaqolXsRP8TgIu4Lzp/j3+KAxFb3gF7lz64J/Et2Jil0OQzwCgkn9i
SoPEM6d9SCFOidhUuTHUhM0D/3UXl/FKPVFrFzjslFpaN9NgArRrmXKTOBWEqMLy
12pbTzOtv+p17Ot51q4h0ebEWrmVJ/h/7Is6QT6AKHuOIW+1/88fcSrmef//0Scz
wtEwVudkYA+kOGt1pwhapVYf1lWE9Z6L3V/MVdxXUesylGO6jJjOjpUB+ZBItwl7
exkhA/4iemhq4D5Jp6r1Kv3aKSPNENdhTORyfZz4UfyOsUfYncaprP5IZja0j+rd
tQLIsH8hXvCT2kSAUY6nMGmzPgpgGamtHI6gH1ZmoNX2gEF7tzGNgKMbbUmwO89B
N56U7wm68AreXE8XviRjGjAtZWnouqe5X+EiUurdJkzRwU0c2rQpVGhvdWdodFdv
cmtzIDxydWJ5d29ya3NAdGhvdWdodHdvcmtzLmNvbT6IYAQTEQIAIAUCRjlBDQIb
AwYLCQgHAwIEFQIIAwQWAgMBAh4BAheAAAoJEHM/KlUQbeB0SSYAn0sgAx5ZK975
wZiChkIqOCyFZ9PLAJ9laivkzqT2y+Kh9FGe3TP/CAhRTbkCDQRGOUEVEAgAqxJI
MFrYV3JKyeXHVKXHNd5Nf1WdqKi37VOdSTBftiehzZdR9hxkGEknYxnbBLGJR9YD
/uJ2+DRwNBcw2RrrEmb0DCZxcLQLZ3xYa7+WvcR4/Nir/3858SGJ+wmGCHKyX2So
M2TurmKu5bqyUUaBgf+IhKfwOr9zeK3rIRhUq/aiYkw8sWA8ruUvxXwLnbkK1aP9
hfvSqScwjkfUVk6CQ6GFUD+4N4mNRtRcZz3gYa+0jSNeEJZQOJxRuE/gBHav3eyN
dm4VAFPF20BobvBVEcMhO0KaR/X4jW1G1eFAKLxI7cdx3+vLeNPaFwHiSMSknsNs
UiucI9oV+I5S/50ZrwADBwf/StYTK9KvPnY9ZqmirBpSh0Zl0xylMtAiMblG7pKv
qKTPNr9zXooheQBpAbnhOfju0DB/OtE4V21HqnbMws2aFvHecEbO5EmjwT7ZTltH
5vlbiPrXOc7SpP22FdkOYdunM2+nsA6398mpYFEiFFNAzX6pReN2tbbmXf6zxS9n
nHjMAgl5nMuOASLZrTrUX/7yu6ySS1hy0ZVfEoAFeILy4MV8y0lVjBQa2kNOCNpO
Cc+y1+4EHLS3fuN0x+tho3rhjKAzj8KOt4XnALn8OouRMx9G7ItC2U8kNzHHFRg5
adT/+nEthVd9q9pYLrUaze7aMQyl+7cD1KzmSe34X9B6W4hJBBgRAgAJBQJGOUEV
AhsMAAoJEHM/KlUQbeB0O7QAn09h4qrKPhWD9eaiyMRS5YeARTYgAJ9WxLcQEvkA
yOSLb33CweehCrlTnQ==
=scSy
Version: GnuPG v1.4.5 (GNU/Linux)

mQINBE4P06MBEACqn48FZgYkG2QrtUAVDV58H6LpDYEcTcv4CIFSkgs6dJ9TavCW
NyPBZRpM2R+Rg5eVqlborp7TmktBP/sSsxc8eJ+3P2aQWSWc5ol74Y0OznJUCrBr
bIdypJllsD9Fe+h7gLBXTh3vdBEWr2lR+xA+Oou8UlO2gFbVFQqMafUgU1s0vqaE
/hHH0TzwD0/tJ6eqIbHwVR/Bu6kHFK4PwePovhfvyYD9Y+C0vOYd5Ict2vbLHz1f
QBDZObv4M6KN3j7nzme47hKtdMd+LwFqxM5cXfM6b5doDulWPmuGV78VoX6OR7el
x1tlfpuiFeuXYnImm5nTawArcQ1UkXUSYcTUKShJebRDLR3BycxR39Q9jtbOQ29R
FumHginovEhdUcinRr22eRXgcmzpR00zFIWoFCwHh/OCtG14nFhefuZ8Z80qbVhW
2J9+/O4tksv9HtQBmQNOK5S8C4HNF2M8AfOWNTr8esFSDc0YA5/cxzdfOOtWam/w
lBpNcUUSSgddRsBwijPuWhVA3NmA/uQlJtAo4Ji5vo8cj5MTPG3+U+rfNqRxu1Yc
ioXRo4LzggPscaTZX6V24n0fzw0J2k7TT4sX007k+7YXwEMqmHpcMYbDNzdCzUer
Zilh5hihJwvGfdi234W3GofttoO+jaAZjic7a3p6cO1ICMgfVqrbZCUQVQARAQAB
tEZDZW50T1MtNiBLZXkgKENlbnRPUyA2IE9mZmljaWFsIFNpZ25pbmcgS2V5KSA8
Y2VudG9zLTYta2V5QGNlbnRvcy5vcmc+iQI8BBMBAgAmBQJOD9OjAhsDBQkSzAMA
BgsJCAcDAgQVAggDBBYCAwECHgECF4AACgkQCUb8osEFud6ajRAAnb6d+w6Y/v/d
MSy7UEy4rNquArix8xhqBwwjoGXpa37OqTvvcJrftZ1XgtzmTbkqXc+9EFch0C+w
ST10f+H0SPTUGuPwqLkg27snUkDAv1B8laub+l2L9erzCaRriH8MnFyxt5v1rqWA
mVlRymzgXK+EQDr+XOgMm1CvxVY3OwdjdoHNox4TdVQWlZl83xdLXBxkd5IRciNm
sg5fJAzAMeg8YsoDee3m4khg9gEm+/Rj5io8Gfk0nhQpgGGeS1HEXl5jzTb44zQW
qudkfcLEdUMOECbu7IC5Z1wrcj559qcp9C94IwQQO+LxLwg4kHffvZjCaOXDRiya
h8KGsEDuiqwjU9HgGq9fa0Ceo3OyUazUi+WnOxBLVIQ8cUZJJ2Ia5PDnEsz59kCp
JmBZaYPxUEteMtG3yDTa8c8jUnJtMPpkwpSkeMBeNr/rEH4YcBoxuFjppHzQpJ7G
hZRbOfY8w97TgJbfDElwTX0/xX9ypsmBezgGoOvOkzP9iCy9YUBc9q/SNnflRWPO
sMVrjec0vc6ffthu2xBdigBXhL7x2bphWzTXf2T067k+JOdoh5EGney6LhQzcp8m
YCTENStCR+L/5XwrvNgRBnoXe4e0ZHet1CcCuBCBvSmsPHp5ml21ahsephnHx+rl
JNGtzulnNP07RyfzQcpCNFH7W4lXzqM=
=jrWY
Version: GnuPG v1.4.5 (GNU/Linux)

mQINBEvSKUIBEADLGnUj24ZVKW7liFN/JA5CgtzlNnKs7sBg7fVbNWryiE3URbn1
JXvrdwHtkKyY96/ifZ1Ld3lE2gOF61bGZ2CWwJNee76Sp9Z+isP8RQXbG5jwj/4B
M9HK7phktqFVJ8VbY2jfTjcfxRvGM8YBwXF8hx0CDZURAjvf1xRSQJ7iAo58qcHn
XtxOAvQmAbR9z6Q/h/D+Y/PhoIJp1OV4VNHCbCs9M7HUVBpgC53PDcTUQuwcgeY6
pQgo9eT1eLNSZVrJ5Bctivl1UcD6P6CIGkkeT2gNhqindRPngUXGXW7Qzoefe+fV
QqJSm7Tq2q9oqVZ46J964waCRItRySpuW5dxZO34WM6wsw2BP2MlACbH4l3luqtp
Xo3Bvfnk+HAFH3HcMuwdaulxv7zYKXCfNoSfgrpEfo2Ex4Im/I3WdtwME/Gbnwdq
3VJzgAxLVFhczDHwNkjmIdPAlNJ9/ixRjip4dgZtW8VcBCrNoL+LhDrIfjvnLdRu
vBHy9P3sCF7FZycaHlMWP6RiLtHnEMGcbZ8QpQHi2dReU1wyr9QgguGU+jqSXYar
1yEcsdRGasppNIZ8+Qawbm/a4doT10TEtPArhSoHlwbvqTDYjtfV92lC/2iwgO6g
YgG9XrO4V8dV39Ffm7oLFfvTbg5mv4Q/E6AWo/gkjmtxkculbyAvjFtYAQARAQAB
tCFFUEVMICg2KSA8ZXBlbEBmZWRvcmFwcm9qZWN0Lm9yZz6JAjYEEwECACAFAkvS
KUICGw8GCwkIBwMCBBUCCAMEFgIDAQIeAQIXgAAKCRA7Sd8qBgi4lR/GD/wLGPv9
qO39eyb9NlrwfKdUEo1tHxKdrhNz+XYrO4yVDTBZRPSuvL2yaoeSIhQOKhNPfEgT
9mdsbsgcfmoHxmGVcn+lbheWsSvcgrXuz0gLt8TGGKGGROAoLXpuUsb1HNtKEOwP
Q4z1uQ2nOz5hLRyDOV0I2LwYV8BjGIjBKUMFEUxFTsL7XOZkrAg/WbTH2PW3hrfS
WtcRA7EYonI3B80d39ffws7SmyKbS5PmZjqOPuTvV2F0tMhKIhncBwoojWZPExft
HpKhzKVh8fdDO/3P1y1Fk3Cin8UbCO9MWMFNR27fVzCANlEPljsHA+3Ez4F7uboF
p0OOEov4Yyi4BEbgqZnthTG4ub9nyiupIZ3ckPHr3nVcDUGcL6lQD/nkmNVIeLYP
x1uHPOSlWfuojAYgzRH6LL7Idg4FHHBA0to7FW8dQXFIOyNiJFAOT2j8P5+tVdq8
wB0PDSH8yRpn4HdJ9RYquau4OkjluxOWf0uRaS//SUcCZh+1/KBEOmcvBHYRZA5J
l/nakCgxGb2paQOzqqpOcHKvlyLuzO5uybMXaipLExTGJXBlXrbbASfXa/yGYSAG
iVrGz9CE6676dMlm8F+s3XXE13QZrXmjloc6jwOljnfAkjTGXjiB7OULESed96MR
XtfLk0W5Ab9pd7tKDR6QHI7rgHXfCopRnZ2VVQ==
=V/6I
Version: GnuPG v1.4.7 (GNU/Linux)

mQGiBEeD8koRBACC1VBRsUwGr9gxFFRho9kZpdRUjBJoPhkeOTvp9LzkdAQMFngr
BFi6N0ov1kCX7LLwBmDG+JPR7N+XcH9YR1coSHpLVg+JNy2kFDd4zAyWxJafjZ3a
9zFg9Yx+0va1BJ2t4zVcmKS4aOfbgQ5KwIOWUujalQW5Y+Fw39Gn86qjbwCg5dIo
tkM0l19h2sx50D027pV5aPsD/2c9pfcFTbMhB0CcKS836GH1qY+NCAdUwPs646ee
Ex/k9Uy4qMwhl3HuCGGGa+N6Plyon7V0TzZuRGp/1742dE8IO+I/KLy2L1d1Fxrn
XOTBZd8qe6nBwh12OMcKrsPBVBxn+iSkaG3ULsgOtx+HHLfa1/p22L5+GzGdxizr
peBuA/90cCp+lYcEwdYaRoFVR501yDOTmmzBc1DrsyWP79QMEGzMqa393G0VnqXt
L4pGmunq66Agw2EhPcIt3pDYiCmEt/obdVtSJH6BtmSDB/zYhbE8u3vLP3jfFDa9
KXxgtYj0NvuUVoRmxSKm8jtfmj1L7zoKNz3jl+Ba3L0WxIv4+bRBUG9zdGdyZVNR
TCBSUE0gQnVpbGRpbmcgUHJvamVjdCA8cGdzcWxycG1zLWhhY2tlcnNAcGdmb3Vu
ZHJ5Lm9yZz6IYAQTEQIAIAUCR4PySgIbIwYLCQgHAwIEFQIIAwQWAgMBAh4BAheA
AAoJEB8W0uFELfD4jnkAoMqd6ZwwsgYHZ3hP9vt+DJt1uDW7AKDbRwP8ESKFhwdJ
8m91RPBeJW/tMLkCDQRHg/JKEAgA64+ZXgcERPYfZYo4p+yMTJAAa9aqnE3U4Ni6
ZMB57GPuEy8NfbNya+HiftO8hoozmJdcI6XFyRBCDUVCdZ8SE+PJdOx2FFqZVIu6
dKnr8ykhgLpNNEFDG3boK9UfLj/5lYQ3Y550Iym1QKOgyrJYeAp6sZ+Nx2PavsP3
nMFCSD67BqAbcLCVQN7a2dAUXfEbfXJjPHXTbo1/kxtzE+KCRTLdXEbSEe3nHO04
K/EgTBjeBUOxnciH5RylJ2oGy/v4xr9ed7R1jJtshsDKMdWApwoLlCBJ63jg/4T/
z/OtXmu4AvmWaJxaTl7fPf2GqSqqb6jLCrQAH7AIhXr9V0zPZwADBQgAlpptNQHl
u7euIdIujFwwcxyQGfee6BG+3zaNSEHMVQMuc6bxuvYmgM9r7aki/b0YMfjJBk8v
OJ3Eh1vDH/woJi2iJ13vQ21ot+1JP3fMd6NPR8/qEeDnmVXu7QAtlkmSKI9Rdnjz
FFSUJrQPHnKsH4V4uvAM+njwYD+VFiwlBPTKNeL8cdBb4tPN2cdVJzoAp57wkZAN
VA2tKxNsTJKBi8wukaLWX8+yPHiWCNWItvyB4WCEp/rZKG4A868NM5sZQMAabpLd
l4fTiGu68OYgK9qUPZvhEAL2C1jPDVHPkLm+ZsD+90Pe66w9vB00cxXuHLzm8Pad
GaCXCY8h3xi6VIhJBBgRAgAJBQJHg/JKAhsMAAoJEB8W0uFELfD4K4cAoJ4yug8y
1U0cZEiF5W25HDzMTtaDAKCaM1m3Cbd+AZ0NGWNg/VvIX9MsPA==
=au6K

Version: GnuPG v2.0.14 (GNU/Linux)

mQGiBEZ6qawRBAC2gDuA1sZioGh1VP/U0l+9RmzOdkWBGB3NfWqezAwt1Up+cP5o
h+UNkghOKbJVQ/zLyY/edYOppQ78yxT1X/J1RHNhs5bjqzWlQxMbT5/tt1N4PExu
gvO38RGFTV0DqIy3lQw5YIwp2le+G8MktYh2NKI4lG0AJoXZicNlI7+mEwCgmfw+
CnsB/kb/xUD1dq6Mo3dYXVcEAKSFfqt+6jvJNxcIYfpQqjEslQsQmPKpXzK9CPyV
UCjUEOirbhPxV86u3Ge/yuy5USMvTTs+ztImabbH6UHBEP+tEw3LiuPUpfh+nEna
3Hz+U81PvUwGEwUMzCr+OemBXqGW7jl66NqKqm8YM3Pkvc4NlS/7slky9A/s6i8S
hToWA/9kP55aSbIXte5TbC88lx6YuLx7qW541ni38DmJfPN5hHywLGnM82MMQMbk
hg1v49+7TTNv44LJpGT7t8gsW9F4Z4rWoChhsldypeeqbDOIv4kFiXt/8122Ud9J
nE67CR9XUuS5Jp+gP6xxNr9/vbvqsOGMJAQkVgkBPVuKYv25gLQ3U2VyZ2lvIFJ1
YmlvIChGcmFtZU9TIERldmVsb3BlcnMpIDxydWJpb2pyQGZyYW1lb3Mub3JnPohr
BBMRAgArAhsDBQkGE0x0BgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAUCTBs76AIZ
AQAKCRCOw9dP80W+dFhjAJ0dKy761iPcG+ALwEAuAgxDpUVBzgCdFxGCAZ7ELYvf
3uFc0Ou2ihDzvyy0IFNlcmdpbyBSdWJpbyA8c2VyZ2lvQHJ1YmlvLm5hbWU+iGYE
ExECACYCGwMGCwkIBwMCBBUCCAMEFgIDAQIeAQIXgAUJBhNMdAUCTBs7XgAKCRCO
w9dP80W+dDdtAJ9NYoW1ChfMyES7nQUlesEQ4aWXjQCeIoGxoOuIGyg6+AKr/2Wr
6fE1zt2IaQQTEQIAKQIbAwYLCQgHAwIEFQIIAwQWAgMBAh4BAheAAhkBBQJIHsGo
BQkCuHFEAAoJEI7D10/zRb50KjgAnRTzzNIODKqrHnrHaUG8dWDCwmYjAJ48Hbcn
ZC6E8LGTeM8vPN0mMI9ijLkCDQRGeqm2EAgAh720kjA9bNDms+6agb6CirD9RkmZ
3G+OHd5iia3KbaUiBtC3PECg4UE8N54JuBNKdjgJQfdYSg2J0EZHyhZHdAVWjykE
tj/IKZKnAfUqKh44uT9OUPW8PChPo/gioLn+DexSAW7n19h7VIa1P3shYqYR/gz8
zgfrXkFFpkpKnOLsXuF20JEEBIBdwrfYRJIBrUTYrfS/2GKLJjyutENkb9uI3JgQ
LfR6DckTaar4eeArjgvOxZRHiU0vRezetlbG8ZM9mSYrcMM3Xa5vLpFlDj6vYzat
RWEuZUfLgXWUVoVyFiNVXhpff/w7/bAb3WpXqjZd6sK8CCJJPNtnbLE7CwADBQf9
EQjT9iiEZis35V9HqeLsxXVjPOGNuLiwjIpacI7CM3aGV1q7NXiCE4oWS/PvpHmu
W+XdXMPH4Bt2VmjZSarlAipTeNnOuiEXipUFIjAlNn1xNVRRd7T35zIvXLtmNtUe
nN1/mqZljKPbCbW1AgktH417t/vJfTnRWr9IgS3Am+o4q200i+1FjrQ/UI3s9+vg
5B+KASFP6HspNttl0kwzQ6SFIHAebd4DKHOj6ShxXPNl18W4R8qPqayrAFqdkgMJ
Jn8j2E8rmGYnssSfjck2kLtvNdTEAMjFnhg+oUapUzJAVeterudiWZFNrtn9ewnf
8SUiiYJlxb+nz545zo0gQIhJBBgRAgAJBQJGeqm2AhsMAAoJEI7D10/zRb50PJEA
mwTA+Sp3wvzwDr8sk7W7U4bBfw26AKCVoYw3mfTime+j3mFk1yk1yxjE2Q==
=iyOs

Version: GnuPG v1.2.6 (GNU/Linux)

mQGiBEWfBuERBACrwDH+6QvpyaOgzhXiemsIX+q4HlhX/HDmrmZOUd7i9VmZNogP
6LRRiTygn2+UphaGV3NDA36ZB/1JRpgvgpzbpZNeAoFvsljIbxGIwkH2JgRF6oNo
eGB3QYzDQJvYVIejk79M0ed3oor4w8OiNVcdxLyVIthFrjrrCqwRP3bLZwCgtY9t
Ezf5WL63Ue45vdht7A2GH+0D/iNAnWKsU7FUMFZrcwMaMbyP7YG8z0+zXUOgtgyP
tbgJG5yikNT3vJypb42gbKfcriUUDC5AeiRmkR8QPvYuOm34rM90+wx2LGqXWnHM
IyLAyl8TS3MQmePem8bfTGTNYxtt3Q7iadez2WYTLBSlmM6hbxZfdwm1hhyM0AJU
YyFUA/9kHH+CUBxKb1UgG7TSp53Po/5p/Yyuty+RJ7zIGv6SiN/JK4/ntWfm5WS5
ZprSdE5ODoFQ/Gs3/VB/eolg2fBW1DcftH6lKHT3GKEOaicGX+T9eOMerZZedm5U
vDA9mFvWnOdOxK8LuRgVqip4jCnWICchpatmdP0whJQHQ6MGLLRMQ2VudE9TLTUg
QmV0YSBLZXkgKENlbnRPUyA1IEJldGEgU2lnbmluZyBLZXkpIDxjZW50b3MtNS1i
ZXRhLWtleUBjZW50b3Mub3JnPohkBBMRAgAkBQJFnwbhAhsDBQkSzAMABgsJCAcD
AgMVAgMDFgIBAh4BAheAAAoJEM/aaIEJLXsrWDkAoKcqa+AAdAWvp5qlJkGQiRy8
aNFDAJ4qRfIxMiLinmjbqcuygWMp61wY5ohMBBMRAgAMBQJFnwhtBYMSzAF0AAoJ
EDjCFhY5bKCkG/wAn14LDlJqjZv1Wz0WNfhr80+qJrf6AKCaIZExwo4ApQpESk/F
SApLd/pEILkBDQRFnwbrEAQAwKzjI2aTB/sS9HuQ4CHCwrj4vr0HxMMwQikYBIvy
MYTtek04KDTKoJL5g3411DsfDW9VRGJdFCHvldgam/5UVfO6nywLkdwAA5TQA5dv
8YE8jTtwdy5Y1QKFc8LaIBZK0+ZbhEvdNfv67egvfcxZc5PvpBZ3C03n+iQ3wPcg
PhcAAwUD/iYkq4LG/je43Qa5rTz5kF5rIiX7Bk5vXT7XSFOFKwHy8V+PGEoVM1W8
+EHIlmTycwIlsVp3by6qCDkMYu4V6VukxZNzJyeoMICiYIXUPh6NKHRoqaYlu6ZO
eFN1TQNXmodPk+iNtdbcby/zAklNqoO/dWSwd8NAo8s6WAHq3VPpiE8EGBECAA8F
AkWfBusCGwwFCRLMAwAACgkQz9pogQkteysXkACgoraCU0EBC+W8TuxrsePO20ma
D0IAoLRRQLTEXL0p3K0WE+LfyTr9EVG5
=mH0S

Version: GnuPG v1.2.6 (GNU/Linux)

mQGiBEIu6hwRBACOz2JFa1nW+seAKlVGOu0ykhdFVNI9E4/Abp2+8nsJIZyUwLAp
ei76rPD8WdptgIjtYOCsqz1TbP+eqeEG0LLihOdFRLUuAjQX4X7LLf5Qm+nvUB73
uLbSf9Ptps2CMUEtu7+0wVoTbuC19HXUhUr5sRdCnJbPJBH6aAHG7Pl9ZwCguN9o
V7IKTnIQiZg0nxSjZ4V9e6UD/R7KoMwH3NPQQF7T7rJaBjSZcVHUPhAcNPNn+ms/
Tw9mzHZ0mnQnOzSEW0ZUj9TkLN52VQ3WmGZKAv9yeVr0/230YIgmtH863lSystmk
LNO9brK0+3vKg5GRpV0/MSWSmf39WPAS1hXNXIFfYp1eGHUfed4FVNxrMTWHQozr
8JosA/wP+zGfM51bSAazLUqP/MEm7F9OFkuD7Sw97w55FyYlrPp1FQWrWczoiKHr
wS5NRCQbCGEEM/+j9id6CukxPLXxwMYCfeg5K0HxMaQT6hxbwjOzAzN3PBFytNel
09qdrdoSDa35twT0SAt+rzM+zvRI8ycizFG3lIih4UItWWve2bQ6S2FyYW5iaXIg
U2luZ2ggKGh0dHA6Ly93d3cua2FyYW4ub3JnLykgPGtic2luZ2hAa2FyYW4ub3Jn
PoheBBMRAgAeBQJCLuocAhsDBgsJCAcDAgMVAgMDFgIBAh4BAheAAAoJEDANvZ4+
E89b/P4AnjufrDCS+TAEL0KpkYDURePbDCHBAJ4+0iI1Td4YrcnLwmQ1+XDCJ3Zr
a7kBDQRCLuocEAQAjAl48FM9eGtP6M9FgswlSPAuCcJct6wOHmd/qZ923HckJPAD
zIFRMlM6H8P0bKoaIluv7agZM7Gsf8NeTg3NEeMKqnibIAyvjYeSkceRIwvBCQ3A
YwWk+B2zLUAFMxnE31oA10zjCKUo7Dc6XDUxSY/qdLymZzyG/Ndav+vMOVsAAwUD
/RCFDuW/GSM/s3DO7XxrOBRTGQmf9v9tCYdZZD615+s8ghaa5oZTvp1cbTTWiSq8
ybncfjVHz9HezDgQjJsFZtrYd4w2JD+7K0+8sZ+BUGo1dDSv4UgN8ACtaGJnShiq
s8pQWRZFqFa3waay8oUSTKHiTHdpxLi3x4HhK/8MTsxniEkEGBECAAkFAkIu6hwC
GwwACgkQMA29nj4Tz1tHSgCcDgKL4swEu7ShvI8nZt2JLmTKB5QAn0qZi2zbexbi
DX+bbalHM+xVnXZN
=rZT6
Version: GnuPG v1.4.7 (GNU/Linux)

mQGiBEJny1wRBACRnbQgZ6qLmJSuGvi/EwrRL6aW610BbdpLQRL3dnwy5wI5t9T3
/JEiEJ7GTvAwfiisEHifMfk2sRlWRf2EDQFttHyrrYXfY5L6UAF2IxixK5FL7PWA
/2a7tkw1IbCbt4IGG0aZJ6/xgQejrOLi4ewniqWuXCc+tLuWBZrGpE2QfwCggZ+L
0e6KPTHMP97T4xV81e3Ba5MD/3NwOQh0pVvZlW66Em8IJnBgM+eQh7pl4xq7nVOh
dEMJwVU0wDRKkXqQVghOxALOSAMapj5mDppEDzGLZHZNSRcvGEs2iPwo9vmY+Qhp
AyEBzE4blNR8pwPtAwL0W3cBKUx7ZhqmHr2FbNGYNO/hP4tO2ochCn5CxSwAfN1B
Qs5pBACOkTZMNC7CLsSUT5P4+64t04x/STlAFczEBcJBLF1T16oItDITJmAsPxbY
iee6JRfXmZKqmDP04fRdboWMcRjfDfCciSdIeGqP7vMcO25bDZB6x6++fOcmQpyD
1Fag3ZUq2yojgXWqVrgFHs/HB3QE7UQkykNp1fjQGbKK+5mWTrQkUmVtaSBDb2xs
ZXQgPFJQTVNARmFtaWxsZUNvbGxldC5jb20+iGAEExECACAFAkZ+MYoCGwMGCwkI
BwMCBBUCCAMEFgIDAQIeAQIXgAAKCRAATm9HAPl/Vv/UAJ9EL8ioMTsz/2EPbNuQ
MP5Xx/qPLACeK5rk2hb8VFubnEsbVxnxfxatGZ25AQ0EQmfLXRAEANwGvY+mIZzj
C1L5Nm2LbSGZNTN3NMbPFoqlMfmym8XFDXbdqjAHutGYEZH/PxRI6GC8YW5YK4E0
HoBAH0b0F97JQEkKquahCakj0P5mGuH6Q8gDOfi6pHimnsSAGf+D+6ZwAn8bHnAa
o+HVmEITYi6s+Csrs+saYUcjhu9zhyBfAAMFA/9Rmfj9/URdHfD1u0RXuvFCaeOw
CYfH2/nvkx+bAcSIcbVm+tShA66ybdZ/gNnkFQKyGD9O8unSXqiELGcP8pcHTHsv
JzdD1k8DhdFNhux/WPRwbo/es6QcpIPa2JPjBCzfOTn9GXVdT4pn5tLG2gHayudK
8Sj1OI2vqGLMQzhxw4hJBBgRAgAJBQJCZ8tdAhsMAAoJEABOb0cA+X9WcSAAn11i
gC5ns/82kSprzBOU0BNwUeXZAJ0cvNmY7rvbyiJydyLsSxh/la6HKw==
=6Rbg
The following public key can be used to verify RPM packages
downloaded from  http://dag.wieers.com/apt/  using 'rpm -K'
if you have the GNU GPG package.
Questions about this key should be sent to:
Dag Wieers <dag@wieers.com>

Version: GnuPG v1.2.1 (GNU/Linux)

mQGiBD9JMT0RBAC9Q2B0AloUMTxaK73sD0cOu1MMdD8yuDagbMlDtUYA1aGeJVO6
TV02JLGr67OBY+UkYuC1c3PUwmb3+jakZd5bW1L8E2L705wS0129xQOZPz6J+alF
5rTzVkiefg8ch1yEcMayK20NdyOmhDGXQXNQS8OJFLTIC6bJs+7MZL83/wCg3cG3
3q7MWHm3IpJb+6QKpB9YH58D/2WjPDK+7YIky/JbFBT4JPgTSBy611+bLqHA6PXq
39tzY6un8KDznAMNtm+NAsr6FEG8PHe406+tbgd7tBkecz3HPX8nR5v0JtDT+gzN
8fM3kAiAzjCHUAFWVAMAZLr5TXuoq4lGTTxvZbwTjZfyjCm7gIieCu8+qnPWh6hm
30NgA/0ZyEHG6I4rOWqPks4vZuD+wlp5XL8moBXEKfEVOMh2MCNDRGnvVHu1P3eD
oHOooVMt9sWrGcgxpYuupPNL4Uf6B6smiLlH6D4tEg+qCxC17zABI5572XJTJ170
JklZJrPGtnkPrrKMamnN9MU4RjGmjh9JZPa7rKjZHyWP/z/CBrQ1RGFnIFdpZWVy
cyAoRGFnIEFwdCBSZXBvc2l0b3J5IHYxLjApIDxkYWdAd2llZXJzLmNvbT6IWQQT
EQIAGQUCP0kxPQQLBwMCAxUCAwMWAgECHgECF4AACgkQog5SFGuNeeYvDQCeKHST
hIq/WzFBXtJOnQkJGSqAoHoAnRtsJVWYmzYKHqzkRx1qAzL18Sd0iEYEEBECAAYF
Aj9JMWAACgkQoj2iXPqnmevnOACfRQaageMcESHVE1+RSuP3txPUvoEAoJAtOHon
g+3SzVNSZLn/g7/Ljfw+uQENBD9JMT8QBACj1QzRptL6hbpWl5DdQ2T+3ekEjJGt
llCwt4Mwt/yOHDhzLe8SzUNyYxTXUL4TPfFvVW9/j8WOkNGvffbs7g84k7a5h/+l
IJTTlP9V9NruDt1dlrBe+mWF6eCY55OFHjb6nOIkcJwKxRd3nGlWnLsz0ce9Hjrg
6lMrn0lPsMV6swADBQP9H42sss6mlqnJEFA97Fl3V9s+7UVJoAIA5uSVXxEOwVoh
Vq7uECQRvWzif6tzOY+vHkUxOBRvD6oIU6tlmuG3WByKyA1d0MTqMr3eWieSYf/L
n5VA9NuD7NwjFA1kLkoDwfSbsF51LppTMkUggzwgvwE46MB6yyuqAVI1kReAWw+I
RgQYEQIABgUCP0kxPwAKCRCiDlIUa4155oktAKDAzm9QYbDpk6SrQhkSFy016BjE
BACeJU1hpElFnUZCL4yKj4EuLnlo8kc=
=mqUt
Version: GnuPG v1.4.5 (GNU/Linux)

mQGiBE1e+1MRBAD8j+KyOIpGNRN39gNy2E/1HG4ZoLFuxIOxI5/1FEuZB/GjYF5m
DvJerZukd0QCqCs72J6J+uWnfD/52t2XWTw4IHPpCWeyr9TWex3uOYmrYzY+0l0l
qsCsrhT0XGkAE0+/20oEP2+t/d+1q0yRcYZRwWK/ME2rUUX0jOa/B3Bc6wCg3blw
XdZNrv1wVNd1PCOUI79k0V0D+wfbybos8Cmdv2f8dD746fSR/hmp4SzpBDmPRRQu
0gtJAKI6ycTdotGq5zHfZj76kDQBudeIgdbWtqfckP2lK47i8lIENAyC4MK8dxh9
Ts+b1LqXlbcPyixzImf4qoT5DT1lSEUPwoMRX8W/29GAcvnZpOwQ8g7DNmRBpFFY
8U2GBADz6uEeP3YwJAuL7pi77AalxR0WQAADMR59pGltQdXaZvANXoioU0W519Pb
nl3gKWDiTuwUDrwaSPoBbNLyX4s0AE7/0HSG02/eRjLB8toQpAH9xkK/u2WPe/do
erZg5yg1qhoCbEM7kJ2I/GBl6VbPedt2ORdsC4ZTWTnZJh6tYLQhQW5keSBUaG9t
cHNvbiA8YW5keUB3ZWJ0YXRpYy5jb20+iGAEExECACAFAk1e+1MCGwMGCwkIBwMC
BBUCCAMEFgIDAQIeAQIXgAAKCRC3Q0sGz0xP+TA0AJwJf5ZPeub8v+5CtZwdcZhV
LU0sjgCgrP3y54heBjF1vhZQ3rJywTmRLHe5Ag0ETV77UxAIAIQPLVFbqheJ90Kf
NF8TYt3ZIMpP5chw25OYq4tuZMzVJxKjUlM7KPQxUKquY/F9WpjH980LmICTb4Fz
txzn2bshIsGyg8pDUSnVK0NPY5uaq9bK4oht8wkr3FNFT2FpeqDIJyn+phIuEpIi
qt1LJyzzjobh9csaaGmNHvtrlkIggBj2n/ZQuGNhcYnKUZ/WGmkItCTSOfA++G+C
dCo1aPEymfbnJvaLB/mLyzA+r/r7LQM10cZEtqh5JdclJEh3CzZmx9HsRxCDZF8W
X/C4MmCwmIxmuU4vkVNhHFTQimQEUR8vg9ltiz8+xBjyE1Iav4MxfOYh3xjdJk1d
zlovyUcAAwUH/2KPgf0UQ1o+4IjOYinEEbNlrD1pKw5anUKwaaeQi0vm/oRG0E2F
ZCJ73OHxW/0hMrwbrGwXcm4NBARnAppg+/CecOVpkBgD5hrM+11DPhxdd1bjjfza
Pq8GmPp8SSsiTPUCoSlzojxL3Z05RNbvKVzxzxbYdx5h5XOTflI7bAHTY4AzGSDf
WaFljjCucht/d7u5empAd02haldUXWjT9RvY5RwnRZ+hjI47e+wUA0FMLHYtA1/0
cwEIvpp2xwF/jpH3ODmnIGEeNoLyzAV7X0KAlSN8VRsh7igZRB9TRGI67aTjRgk8
ayf/QNxAzwEk1MeDv67IFKNYVolxHCt4CtqISQQYEQIACQUCTV77UwIbDAAKCRC3
Q0sGz0xP+dPiAKDUNJ5rkB9CRoMH9BC35d0fqXXeugCgwl/HYv52dWgatbyEGLet
etv5Qeg=
=nIAo
Version: GnuPG v1.2.1 (GNU/Linux)

mQGiBEGP+skRBACyZz7muj2OgWc9FxK+Hj7tWPnrfxEN+0PE+n8MtqH+dxwQpMTd
gDpOXxJa45GM5pEwB6CFSFK7Fb/faniF9fDbm1Ga7MpBupIBYLactkoOTZMuTlGB
T0O5ha4h26YLqFfQOtlEi7d0+BDDdfHRQw3o67ycgRnLgYSA79DISc3MywCgk2TR
yd5sRfZAG23b4EDl+D0+oaMEAK73J7zuxf6F6V5EaxLd/w4JVB2xW0Glcn0fACOe
8FV9lzcZuo2xPpdGuyj02f/xlqvEav3XqTfFU2no61mA2pamaRNhlo+CEfGc7qde
/1twfSgOYqzeCx7+aybyPo8Th41b80FT19mfkjBf6+5NbUHffRabFFh1FmcPVNBn
F3FoA/95nRIzqDMItdTRitaZn02dIGNjdwllBD75bSVEvaR9O5hjBo0VMc25DB7f
DM2qEO52wCQbAKw9zFC284ekZVDaK4aHYt7iobHaqJEpKHgsDut5WWuMiSLR+SsF
aBHIZ9HvrKWLSUQKHU6A1Hva0P0r3GnoCMc/VCVfrLl721SjPbQzQXRvbWljIFJv
Y2tldCBUdXJ0bGUgPGFkbWluQGF0b21pY3JvY2tldHR1cnRsZS5jb20+iFkEExEC
ABkFAkGP+skECwcDAgMVAgMDFgIBAh4BAheAAAoJEDKpURRevSdEzcQAn1hSHqTO
jwv/z/picpOnR+mgycwHAKCBex2ciyXo5xeaQ9w7OMf7Jsmon7kBDQRBj/rMEAQA
6JvRndqE4koK0e49fUkICm1X0ZEzsVg9VmUW+Zft5guCRxmGlYTmtlC7oJCToRP/
m/xH5uIevGiJycRKB0Ix+Csl6f9QuTkQ7tSTHcaIKbI3tL1x6CCBoWeTGYaOJlvk
ubrmajiMFaBfopLH2firoSToDGoUvv4e7bImIHEgNr8AAwUEAND0YR9DOEZvc+Lq
Ta/PQyxkdZ75o+Ty/O64E3OmO1Tuw2ciSQXCcwrbrMSE6EHHetxtGCnOdkjjjtmH
AnxsxdONv/EJuQmLcoNcsigZZ4tfRdmtXgcbnOmXBgmy1ea1KvWcsmecNSAMJHwR
7vDDKzbj4mSmudzjapHeeOewFF10iEYEGBECAAYFAkGP+swACgkQMqlRFF69J0Sq
nQCfa/q9Y/oY4dOTGj6MsdmRIQkKZhYAoIscjinFwTru4FVi2MIEzUUMToDK
=NOIx
Version: GnuPG v1.4.6 (GNU/Linux)

mQGiBD5gtCgRBACKIvjMF+20r9k/Uw2Hq6Y/qn1nM0AZEFalhglXP5pMm5bMgkcI
1vCWqJxSbhQhk8hSEenoszes8hyUxHj4hFFUDiRtAxOpCpGCsCnUddgQtHAQd+tm
aQsM6J3Jm/EZPtwR0lvwvRGvz2x6Rr95G8+42KK9x+mBYhLk0y3gAbBzhwCgnkDH
a97MGBT7gRLrmtFqiHrWlPkD/2tBaH6IEuoJhcAbNj9MukbhDOYJ6ic9Nzf6sR3t
ZG+XgQLLS2DNy8+HWcYJOjpJDEe8zWFDdUv3cL1D0U2f2e85FuJaMucHn+816iw8
mNjZXJEoDE4LJ8Vv53fkevNZpdWmO2VtRwI+woDnIHYHukDLj2sWhVt+5W+uOKAE
OippA/9OzuWrwBtTR+Np8ApZGkxhxU1z0iEStV+kQNqJE7YoR4SGMuzEa3bFzrPx
k4qIU+rw4YgFgHrs1x08lXxNOZkq6avvbl60HqN2qF2UQL/YdU+5X3ixaJVaYYk8
yuK+hp0Hx2DdBWmVhq6rEzIfpnFhF4qspwMWEiiBGjYDL62W7LQ0QVRycG1zLm5l
dCAocnBtIHNpZ25pbmcga2V5KSA8QXhlbC5UaGltbUBBVHJwbXMubmV0PohnBBMR
AgAnAhsDBgsJCAcDAgMVAgMDFgIBAh4BAheAAhkBBQJFfF9PBQkJGI4nAAoJEFCM
5eZmU0wrJ0IAnA0BdyRlq2S8ess55R8YMFnWAWXEAJ9Fa7cEHku4j4B83shCODps
+DYUZohnBBMRAgAnAhsDBQkDdMLsBgsJCAcDAgMVAgMDFgIBAh4BAheABQJAKteu
AhkBAAoJEFCM5eZmU0wrMMUAnRjS2PXQp0tsC/69IGMMxqU+8xeAAJ9XQjVAo+mU
kg/3AeBlMBIlFe5hDQ==
=23Fz
Version: GnuPG v1.2.6 (GNU/Linux)

mQGiBEY5QQ0RBACfC1NbAdGFMOS/Y7P9hmNph2Wh3TJTh6IZpL+lTJBuZSEa6rp0
CghS/yU3gGXUPaxAy91M7PXMv5p7S3U/SusZHATLhFdU5J4LuWMf4IiBy9FOB/aj
Q1s5vZ/i3YFaqolXsRP8TgIu4Lzp/j3+KAxFb3gF7lz64J/Et2Jil0OQzwCgkn9i
SoPEM6d9SCFOidhUuTHUhM0D/3UXl/FKPVFrFzjslFpaN9NgArRrmXKTOBWEqMLy
12pbTzOtv+p17Ot51q4h0ebEWrmVJ/h/7Is6QT6AKHuOIW+1/88fcSrmef//0Scz
wtEwVudkYA+kOGt1pwhapVYf1lWE9Z6L3V/MVdxXUesylGO6jJjOjpUB+ZBItwl7
exkhA/4iemhq4D5Jp6r1Kv3aKSPNENdhTORyfZz4UfyOsUfYncaprP5IZja0j+rd
tQLIsH8hXvCT2kSAUY6nMGmzPgpgGamtHI6gH1ZmoNX2gEF7tzGNgKMbbUmwO89B
N56U7wm68AreXE8XviRjGjAtZWnouqe5X+EiUurdJkzRwU0c2rQpVGhvdWdodFdv
cmtzIDxydWJ5d29ya3NAdGhvdWdodHdvcmtzLmNvbT6IYAQTEQIAIAUCRjlBDQIb
AwYLCQgHAwIEFQIIAwQWAgMBAh4BAheAAAoJEHM/KlUQbeB0SSYAn0sgAx5ZK975
wZiChkIqOCyFZ9PLAJ9laivkzqT2y+Kh9FGe3TP/CAhRTbkCDQRGOUEVEAgAqxJI
MFrYV3JKyeXHVKXHNd5Nf1WdqKi37VOdSTBftiehzZdR9hxkGEknYxnbBLGJR9YD
/uJ2+DRwNBcw2RrrEmb0DCZxcLQLZ3xYa7+WvcR4/Nir/3858SGJ+wmGCHKyX2So
M2TurmKu5bqyUUaBgf+IhKfwOr9zeK3rIRhUq/aiYkw8sWA8ruUvxXwLnbkK1aP9
hfvSqScwjkfUVk6CQ6GFUD+4N4mNRtRcZz3gYa+0jSNeEJZQOJxRuE/gBHav3eyN
dm4VAFPF20BobvBVEcMhO0KaR/X4jW1G1eFAKLxI7cdx3+vLeNPaFwHiSMSknsNs
UiucI9oV+I5S/50ZrwADBwf/StYTK9KvPnY9ZqmirBpSh0Zl0xylMtAiMblG7pKv
qKTPNr9zXooheQBpAbnhOfju0DB/OtE4V21HqnbMws2aFvHecEbO5EmjwT7ZTltH
5vlbiPrXOc7SpP22FdkOYdunM2+nsA6398mpYFEiFFNAzX6pReN2tbbmXf6zxS9n
nHjMAgl5nMuOASLZrTrUX/7yu6ySS1hy0ZVfEoAFeILy4MV8y0lVjBQa2kNOCNpO
Cc+y1+4EHLS3fuN0x+tho3rhjKAzj8KOt4XnALn8OouRMx9G7ItC2U8kNzHHFRg5
adT/+nEthVd9q9pYLrUaze7aMQyl+7cD1KzmSe34X9B6W4hJBBgRAgAJBQJGOUEV
AhsMAAoJEHM/KlUQbeB0O7QAn09h4qrKPhWD9eaiyMRS5YeARTYgAJ9WxLcQEvkA
yOSLb33CweehCrlTnQ==
=scSy
Version: GnuPG v1.2.6 (GNU/Linux)

mQGiBEWfB6MRBACrnYW6yKMT+MwJlCIhoyTxGf3mAxmnAiDEy6HcYN8rivssVTJk
CFtQBlBOpLV/OW2YtKrCO2xHn46eNfnMri8FGT8g+9JF3MUVi7kiV1He4iJynHXB
+F2ZqIvHf3IaUj1ys+p8TK64FDFxDQDrGQfIsD/+pkSGx53/877IrvdwjwCguQcr
Ioip5TH0Fj0OLUY4asYVZH8EAIqFHEqsY+9ziP+2R3/FyxSllKkjwcMLrBug+cYO
LYDD6eQXE9Mq8XKGFDj9ZB/0+JzK/XQeStheeFG75q3noq5oCPVFO4czuKErIRAB
qKbDBhaTj3JhOgM12XsUYn+rI6NeMV2ZogoQCC2tWmDETfRpYp2moo53NuFWHbAy
XjETA/sHEeQT9huHzdi/lebNBj0L8nBGfLN1nSRP1GtvagBvkR4RZ6DTQyl0UzOJ
RA3ywWlrL9IV9mrpb1Fmn60l2jTMMCc7J6LacmPK906N+FcN/Docj1M4s/4CNanQ
NhzcFhAFtQL56SNyLTCk1XzhssGZ/jwGnNbU/aaj4wOj0Uef5LRGQ2VudE9TLTUg
S2V5IChDZW50T1MgNSBPZmZpY2lhbCBTaWduaW5nIEtleSkgPGNlbnRvcy01LWtl
eUBjZW50b3Mub3JnPohkBBMRAgAkBQJFnwekAhsDBQkSzAMABgsJCAcDAgMVAgMD
FgIBAh4BAheAAAoJEKikR9zoViiXKlEAmwSoZDvZo+WChcg3s/SpNoWCKhMAAJwI
E2aXpZVrpsQnInUQWwkdrTiL5YhMBBMRAgAMBQJFnwiSBYMSzAIRAAoJEDjCFhY5
bKCk0hAAn134bIx3wSbq58E6P6U5RT7Z2Zx4AJ9VxnVkoGHkVIgSdsxHUgRjo27N
F7kBDQRFnwezEAQA/HnJ5yiozwgtf6jt+kii8iua+WnjqBKomPHOQ8moxbWdv5Ks
4e1DPhzRqxhshjmub4SuJ93sgMSAF2ayC9t51mSJV33KfzPF2gIahcMqfABe/2hJ
aMzcQZHrGJCEX6ek8l8SFKou7vICzyajRSIK8gxWKBuQknP/9LKsoczV+xsAAwUD
/idXPkk4vRRHsCwc6I23fdI0ur52bzEqHiAIswNfO521YgLk2W1xyCLc2aYjc8Ni
nrMX1tCnEx0/gK7ICyJoWH1Vc7//79sWFtX2EaTO+Q07xjFX4E66WxJlCo9lOjos
Vk5qc7R+xzLDoLGFtbzaTRQFzf6yr7QTu+BebWLoPwNTiE8EGBECAA8FAkWfB7MC
GwwFCRLMAwAACgkQqKRH3OhWKJfvvACfbsF1WK193zM7vSc4uq51XsceLwgAoI0/
9GxdNhGQEAweSlQfhPa3yYXH
=o/Mx

Version: GnuPG v1.4.5 (GNU/Linux)

mQINBEvSKUIBEADLGnUj24ZVKW7liFN/JA5CgtzlNnKs7sBg7fVbNWryiE3URbn1
JXvrdwHtkKyY96/ifZ1Ld3lE2gOF61bGZ2CWwJNee76Sp9Z+isP8RQXbG5jwj/4B
M9HK7phktqFVJ8VbY2jfTjcfxRvGM8YBwXF8hx0CDZURAjvf1xRSQJ7iAo58qcHn
XtxOAvQmAbR9z6Q/h/D+Y/PhoIJp1OV4VNHCbCs9M7HUVBpgC53PDcTUQuwcgeY6
pQgo9eT1eLNSZVrJ5Bctivl1UcD6P6CIGkkeT2gNhqindRPngUXGXW7Qzoefe+fV
QqJSm7Tq2q9oqVZ46J964waCRItRySpuW5dxZO34WM6wsw2BP2MlACbH4l3luqtp
Xo3Bvfnk+HAFH3HcMuwdaulxv7zYKXCfNoSfgrpEfo2Ex4Im/I3WdtwME/Gbnwdq
3VJzgAxLVFhczDHwNkjmIdPAlNJ9/ixRjip4dgZtW8VcBCrNoL+LhDrIfjvnLdRu
vBHy9P3sCF7FZycaHlMWP6RiLtHnEMGcbZ8QpQHi2dReU1wyr9QgguGU+jqSXYar
1yEcsdRGasppNIZ8+Qawbm/a4doT10TEtPArhSoHlwbvqTDYjtfV92lC/2iwgO6g
YgG9XrO4V8dV39Ffm7oLFfvTbg5mv4Q/E6AWo/gkjmtxkculbyAvjFtYAQARAQAB
tCFFUEVMICg2KSA8ZXBlbEBmZWRvcmFwcm9qZWN0Lm9yZz6JAjYEEwECACAFAkvS
KUICGw8GCwkIBwMCBBUCCAMEFgIDAQIeAQIXgAAKCRA7Sd8qBgi4lR/GD/wLGPv9
qO39eyb9NlrwfKdUEo1tHxKdrhNz+XYrO4yVDTBZRPSuvL2yaoeSIhQOKhNPfEgT
9mdsbsgcfmoHxmGVcn+lbheWsSvcgrXuz0gLt8TGGKGGROAoLXpuUsb1HNtKEOwP
Q4z1uQ2nOz5hLRyDOV0I2LwYV8BjGIjBKUMFEUxFTsL7XOZkrAg/WbTH2PW3hrfS
WtcRA7EYonI3B80d39ffws7SmyKbS5PmZjqOPuTvV2F0tMhKIhncBwoojWZPExft
HpKhzKVh8fdDO/3P1y1Fk3Cin8UbCO9MWMFNR27fVzCANlEPljsHA+3Ez4F7uboF
p0OOEov4Yyi4BEbgqZnthTG4ub9nyiupIZ3ckPHr3nVcDUGcL6lQD/nkmNVIeLYP
x1uHPOSlWfuojAYgzRH6LL7Idg4FHHBA0to7FW8dQXFIOyNiJFAOT2j8P5+tVdq8
wB0PDSH8yRpn4HdJ9RYquau4OkjluxOWf0uRaS//SUcCZh+1/KBEOmcvBHYRZA5J
l/nakCgxGb2paQOzqqpOcHKvlyLuzO5uybMXaipLExTGJXBlXrbbASfXa/yGYSAG
iVrGz9CE6676dMlm8F+s3XXE13QZrXmjloc6jwOljnfAkjTGXjiB7OULESed96MR
XtfLk0W5Ab9pd7tKDR6QHI7rgHXfCopRnZ2VVQ==
=V/6I
Version: GnuPG v2.0.14 (GNU/Linux)

mQGiBEZ6qawRBAC2gDuA1sZioGh1VP/U0l+9RmzOdkWBGB3NfWqezAwt1Up+cP5o
h+UNkghOKbJVQ/zLyY/edYOppQ78yxT1X/J1RHNhs5bjqzWlQxMbT5/tt1N4PExu
gvO38RGFTV0DqIy3lQw5YIwp2le+G8MktYh2NKI4lG0AJoXZicNlI7+mEwCgmfw+
CnsB/kb/xUD1dq6Mo3dYXVcEAKSFfqt+6jvJNxcIYfpQqjEslQsQmPKpXzK9CPyV
UCjUEOirbhPxV86u3Ge/yuy5USMvTTs+ztImabbH6UHBEP+tEw3LiuPUpfh+nEna
3Hz+U81PvUwGEwUMzCr+OemBXqGW7jl66NqKqm8YM3Pkvc4NlS/7slky9A/s6i8S
hToWA/9kP55aSbIXte5TbC88lx6YuLx7qW541ni38DmJfPN5hHywLGnM82MMQMbk
hg1v49+7TTNv44LJpGT7t8gsW9F4Z4rWoChhsldypeeqbDOIv4kFiXt/8122Ud9J
nE67CR9XUuS5Jp+gP6xxNr9/vbvqsOGMJAQkVgkBPVuKYv25gLQ3U2VyZ2lvIFJ1
YmlvIChGcmFtZU9TIERldmVsb3BlcnMpIDxydWJpb2pyQGZyYW1lb3Mub3JnPohr
BBMRAgArAhsDBQkGE0x0BgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAUCTBs76AIZ
AQAKCRCOw9dP80W+dFhjAJ0dKy761iPcG+ALwEAuAgxDpUVBzgCdFxGCAZ7ELYvf
3uFc0Ou2ihDzvyy0IFNlcmdpbyBSdWJpbyA8c2VyZ2lvQHJ1YmlvLm5hbWU+iGYE
ExECACYCGwMGCwkIBwMCBBUCCAMEFgIDAQIeAQIXgAUJBhNMdAUCTBs7XgAKCRCO
w9dP80W+dDdtAJ9NYoW1ChfMyES7nQUlesEQ4aWXjQCeIoGxoOuIGyg6+AKr/2Wr
6fE1zt2IaQQTEQIAKQIbAwYLCQgHAwIEFQIIAwQWAgMBAh4BAheAAhkBBQJIHsGo
BQkCuHFEAAoJEI7D10/zRb50KjgAnRTzzNIODKqrHnrHaUG8dWDCwmYjAJ48Hbcn
ZC6E8LGTeM8vPN0mMI9ijLkCDQRGeqm2EAgAh720kjA9bNDms+6agb6CirD9RkmZ
3G+OHd5iia3KbaUiBtC3PECg4UE8N54JuBNKdjgJQfdYSg2J0EZHyhZHdAVWjykE
tj/IKZKnAfUqKh44uT9OUPW8PChPo/gioLn+DexSAW7n19h7VIa1P3shYqYR/gz8
zgfrXkFFpkpKnOLsXuF20JEEBIBdwrfYRJIBrUTYrfS/2GKLJjyutENkb9uI3JgQ
LfR6DckTaar4eeArjgvOxZRHiU0vRezetlbG8ZM9mSYrcMM3Xa5vLpFlDj6vYzat
RWEuZUfLgXWUVoVyFiNVXhpff/w7/bAb3WpXqjZd6sK8CCJJPNtnbLE7CwADBQf9
EQjT9iiEZis35V9HqeLsxXVjPOGNuLiwjIpacI7CM3aGV1q7NXiCE4oWS/PvpHmu
W+XdXMPH4Bt2VmjZSarlAipTeNnOuiEXipUFIjAlNn1xNVRRd7T35zIvXLtmNtUe
nN1/mqZljKPbCbW1AgktH417t/vJfTnRWr9IgS3Am+o4q200i+1FjrQ/UI3s9+vg
5B+KASFP6HspNttl0kwzQ6SFIHAebd4DKHOj6ShxXPNl18W4R8qPqayrAFqdkgMJ
Jn8j2E8rmGYnssSfjck2kLtvNdTEAMjFnhg+oUapUzJAVeterudiWZFNrtn9ewnf
8SUiiYJlxb+nz545zo0gQIhJBBgRAgAJBQJGeqm2AhsMAAoJEI7D10/zRb50PJEA
mwTA+Sp3wvzwDr8sk7W7U4bBfw26AKCVoYw3mfTime+j3mFk1yk1yxjE2Q==
=iyOs

Version: GnuPG v1.2.6 (GNU/Linux)

mQGiBEWfBuERBACrwDH+6QvpyaOgzhXiemsIX+q4HlhX/HDmrmZOUd7i9VmZNogP
6LRRiTygn2+UphaGV3NDA36ZB/1JRpgvgpzbpZNeAoFvsljIbxGIwkH2JgRF6oNo
eGB3QYzDQJvYVIejk79M0ed3oor4w8OiNVcdxLyVIthFrjrrCqwRP3bLZwCgtY9t
Ezf5WL63Ue45vdht7A2GH+0D/iNAnWKsU7FUMFZrcwMaMbyP7YG8z0+zXUOgtgyP
tbgJG5yikNT3vJypb42gbKfcriUUDC5AeiRmkR8QPvYuOm34rM90+wx2LGqXWnHM
IyLAyl8TS3MQmePem8bfTGTNYxtt3Q7iadez2WYTLBSlmM6hbxZfdwm1hhyM0AJU
YyFUA/9kHH+CUBxKb1UgG7TSp53Po/5p/Yyuty+RJ7zIGv6SiN/JK4/ntWfm5WS5
ZprSdE5ODoFQ/Gs3/VB/eolg2fBW1DcftH6lKHT3GKEOaicGX+T9eOMerZZedm5U
vDA9mFvWnOdOxK8LuRgVqip4jCnWICchpatmdP0whJQHQ6MGLLRMQ2VudE9TLTUg
QmV0YSBLZXkgKENlbnRPUyA1IEJldGEgU2lnbmluZyBLZXkpIDxjZW50b3MtNS1i
ZXRhLWtleUBjZW50b3Mub3JnPohkBBMRAgAkBQJFnwbhAhsDBQkSzAMABgsJCAcD
AgMVAgMDFgIBAh4BAheAAAoJEM/aaIEJLXsrWDkAoKcqa+AAdAWvp5qlJkGQiRy8
aNFDAJ4qRfIxMiLinmjbqcuygWMp61wY5ohMBBMRAgAMBQJFnwhtBYMSzAF0AAoJ
EDjCFhY5bKCkG/wAn14LDlJqjZv1Wz0WNfhr80+qJrf6AKCaIZExwo4ApQpESk/F
SApLd/pEILkBDQRFnwbrEAQAwKzjI2aTB/sS9HuQ4CHCwrj4vr0HxMMwQikYBIvy
MYTtek04KDTKoJL5g3411DsfDW9VRGJdFCHvldgam/5UVfO6nywLkdwAA5TQA5dv
8YE8jTtwdy5Y1QKFc8LaIBZK0+ZbhEvdNfv67egvfcxZc5PvpBZ3C03n+iQ3wPcg
PhcAAwUD/iYkq4LG/je43Qa5rTz5kF5rIiX7Bk5vXT7XSFOFKwHy8V+PGEoVM1W8
+EHIlmTycwIlsVp3by6qCDkMYu4V6VukxZNzJyeoMICiYIXUPh6NKHRoqaYlu6ZO
eFN1TQNXmodPk+iNtdbcby/zAklNqoO/dWSwd8NAo8s6WAHq3VPpiE8EGBECAA8F
AkWfBusCGwwFCRLMAwAACgkQz9pogQkteysXkACgoraCU0EBC+W8TuxrsePO20ma
D0IAoLRRQLTEXL0p3K0WE+LfyTr9EVG5
=mH0S

Version: GnuPG v1.2.1 (GNU/Linux)

mQGiBD/9sIMRBADp28M+gDNgYJ/UMW1Tem0W/D17FAZRVRI8Ht68QcZsq6uS1k3L
HPX7rLG3iKrKj4crvEE+CY/3L182NZ6bRJt61rQLrtSbMFIMvt7L6dG6BYYw0i8P
SqyVC6uPb2W8wi1RtNdQk0pSeDSQh8wCsDDo8WYHkdRztoKWHvd3hAN7NwCgzRVU
QS3Uw6McILxO9cUBgJEhBj8D/38TomjexWRUp+rzs6aouqHoZyslSCUe4aLeJvSQ
Whi1j4E0sgWMJ2L/Ta6FXNM2Of3Ze6delf8eVPZ2N78yELh+LV7DZr5Cy+zDtSWY
WnyWGSqHVEqf0UarpC8XVcJ1jJu3sHfaBf94tnKJI/uipxbD8oU4ixoLvANFR1fp
YfKdBACm+C8Rk2NpXeAtXIyN9UgJPpj9H5IXxnrdYJa0ce72qrrniM0dhGHz9+9H
5d8rVJYTNEW6kDhj79vnFLq86o0n8VIpv/0g38FO+FCi4yVJ49qA2+D7unysBVTm
ZXo3LRMiBJfeh39ONEIg+CWVD6sXo7FTwVKpawJpeO6Lp8nrlbQ6VHJveSBEYXdz
b24gKFNwaWt5IEhhaXIgSGF3YWlpYW4gU2hpcnRzKSA8ZGF3c29uQGZuYWwuZ292
PohZBBMRAgAZBQI//bCDBAsHAwIDFQIDAxYCAQIeAQIXgAAKCRDaatAIgv0XsoJ2
AJ9KdOcfYSVAjoUwwrQjARa6xWP/NQCcCJKfBYUVZDiWsiZjVm1EOGcNCSS5AQ0E
P/2whBAEAJYHI18UVqIrZPX3C3FvzXf7MzNs31UPA1iCgp3f02w6nh/XZs8Y0CNB
ig9rCR/e2O8O4Fnl56Z+N+a9H7jPmF8sOhacvqNaS7yAJ+9pHj0op6Az/X69dWnS
AdaFXPB1Tc6ryfNtbs0CB0tWRbjlB4BTd/1PEerLNUNGoLOpFWeXAAMFA/0UD2ku
vIRoQwAjNf1/swcIQe44DNNQYY+GSzi0tXVhytiJquziPk/la2elinl4N1KERrO8
fgdrHtZl4X7n3nv5GGdwVjQfcZJfzFcGIlzqJOcLHAlVSVEpAJAlkykbx8BDtfod
JbODs9NfU+VwmwrTwyVdpbOEHb9ktdeuabIXMIhGBBgRAgAGBQI//bCEAAoJENpq
0AiC/Rey1JoAnjJ1qsi4gbkb+srAgH2UCBRcM0uQAKCGiibCE9G5udph5YplnHhL
ZpAqxA==
=3u8+
Version: GnuPG v1.2.6 (GNU/Linux)

mQINBEmkAzABEAC2/c7bP1lHQ3XScxbIk0LQWe1YOiibQBRLwf8Si5PktgtuPibT
kKpZjw8p4D+fM7jD1WUzUE0X7tXg2l/eUlMM4dw6XJAQ1AmEOtlwSg7rrMtTvM0A
BEtI7Km6fC6sU6RtBMdcqD1cH/6dbsfh8muznVA7UlX+PRBHVzdWzj6y8h84dBjo
gzcbYu9Hezqgj/lLzicqsSZPz9UdXiRTRAIhp8V30BD8uRaaa0KDDnD6IzJv3D9P
xQWbFM4Z12GN9LyeZqmD7bpKzZmXG/3drvfXVisXaXp3M07t3NlBa3Dt8NFIKZ0D
FRXBz5bvzxRVmdH6DtkDWXDPOt+Wdm1rZrCOrySFpBZQRpHw12eo1M1lirANIov7
Z+V1Qh/aBxj5EUu32u9ZpjAPPNtQF6F/KjaoHHHmEQAuj4DLex4LY646Hv1rcv2i
QFuCdvLKQGSiFBrfZH0j/IX3/0JXQlZzb3MuMFPxLXGAoAV9UP/Sw/WTmAuTzFVm
G13UYFeMwrToOiqcX2VcK0aC1FCcTP2z4JW3PsWvU8rUDRUYfoXovc7eg4Vn5wHt
0NBYsNhYiAAf320AUIHzQZYi38JgVwuJfFu43tJZE4Vig++RQq6tsEx9Ftz3EwRR
fJ9z9mEvEiieZm+vbOvMvIuimFVPSCmLH+bI649K8eZlVRWsx3EXCVb0nQARAQAB
tDBSZWQgSGF0LCBJbmMuIChiZXRhIGtleSAyKSA8c2VjdXJpdHlAcmVkaGF0LmNv
bT6JAjYEEwECACAFAkpSM+cCGwMGCwkIBwMCBBUCCAMEFgIDAQIeAQIXgAAKCRCT
ioDK8hVB6/9tEAC0+KmzeKceXQ/GTUoU6jy9vtkFCFrmv+c7ol4XpdTt0QhqBOwy
6m2mKWwmm8KfYfy0cADQ4y/EcoXl7FtFBwYmkCuEQGXhTDn9DvVjhooIq59LEMBQ
OW879RwwzRIZ8ebbjMUjDPF5MfPQqP2LBu9N4KvXlZp4voykwuuaJ+cbsKZR6pZ6
0RQKPHKP+NgUFC0fff7XY9cuOZZWFAeKRhLN2K7bnRHKxp+kELWb6R9ZfrYwZjWc
MIPbTd1khE53L4NTfpWfAnJRtkPSDOKEGVlVLtLq4HEAxQt07kbslqISRWyXER3u
QOJj64D1ZiIMz6t6uZ424VE4ry9rBR0Jz55cMMx5O/ni9x3xzFUgH8Su2yM0r3jE
Rf24+tbOaPf7tebyx4OKe+JW95hNVstWUDyGbs6K9qGfI/pICuO1nMMFTo6GqzQ6
DwLZvJ9QdXo7ujEtySZnfu42aycaQ9ZLC2DOCQCUBY350Hx6FLW3O546TAvpTfk0
B6x+DV7mJQH7MGmRXQsE7TLBJKjq28Cn4tVp04PmybQyTxZdGA/8zY6pPl6xyVMH
V68hSBKEVT/rlouOHuxfdmZva1DhVvUC6Xj7+iTMTVJUAq/4Uyn31P1OJmA2a0PT
CAqWkbJSgKFccsjPoTbLyxhuMSNkEZFHvlZrSK9vnPzmfiRH0Orx3wYpMQ==
=21pb
The following public key can be used to verify RPM packages built and
signed by Red Hat, Inc. for this beta using `rpm -K' using the GNU GPG
package.  Questions about this key should be sent to security@redhat.com.


Version: GnuPG v1.0.6 (GNU/Linux)
Comment: For info see http://www.gnupg.org

mQGiBDySTqsRBACzc7xuCIp10oj5B2PAV4XzDeVxprv/WTMreSNSK+iC0bEz0IBp
Vnn++qtyiXfH+bGIE9jqZgIEnpttWhUOaU5LhcLFzy+m8NWfngIFP9QfGmGAe9Gd
LFeAdhj4RmSG/vgr7vDd83Hz22dv403Ar/sliWO4vDOrMmZBG57WGYTWtwCgkMsi
UUQuJ6slbzKn82w+bYxOlL0EAIylWJGaTkKOTL5DqVR3ik9aT0Dt3FNVYiuhcKBe
II4E3KOIVA9kO8in1IZjx2gs6K2UV+GsoAVANdfKL7l9O+k+J8OxhE74oycvYJxW
QzCgXMZkNcvW5wyXwEMcr6TVd/5BGztcMw8oT3/l2MtAEG/vn1XaWToRSO1XDMDz
+AjUA/4m0mTkN8S4wjzJG8lqN7+quW3UOaiCe8J3SFrrrhE0XbY9cTJI/9nuXHU1
VjqOSmXQYH2Db7UOroFTBiWhlAedA4O4yuK52AJnvSsHbnJSEmn9rpo5z1Q8F+qI
mDlzriJdrIrVLeDiUeTlpH3kpG38D7007GhXBV72k1gpMoMcpbQ3UmVkIEhhdCwg
SW5jLiAoQmV0YSBUZXN0IFNvZnR3YXJlKSA8cmF3aGlkZUByZWRoYXQuY29tPohX
BBMRAgAXBQI8l5p/BQsHCgMEAxUDAgMWAgECF4AACgkQ/TcmiYl9oHqdeQCfZjw4
F9sir3XfRAjVe9kYNcQ8hnIAn0WgyT7H5RriWYTOCfauOmd+cAW4iEYEEBECAAYF
AjyXmqQACgkQIZGAzdtCpg5nDQCfepuRUyuVJvhuQkPWySETYvRw+WoAnjAWhx6q
0npMx4OE1JGFi8ymKXktuQENBDySTq4QBADKL/mK7S8E3synxISlu7R6fUvu07Oc
RoX96n0Di6T+BS99hC44XzHjMDhUX2ZzVvYS88EZXoUDDkB/8g7SwZrOJ/QE1zrI
JmSVciNhSYWwqeT40Evs88ajZUfDiNbS/cSC6oui98iS4vxd7sE7IPY+FSx9vuAR
xOa9vBnJY/dx0wADBQQAosm+Iltt2uigC6LJzxNOoIdB5r0GqTC1o5sHCeNqXJhU
ExAG8m74uzMlYVLOpGZi4y4NwwAWvCWC0MWWnnu+LGFy1wKiJKRjhv5F+WkFutY5
WHV5L44vp9jSIlBCRG+84jheTh8xqhndM9wOfPwWdYYu1vxrB8Tn6kA17PcYfHSI
RgQYEQIABgUCPJJergAKCRD9NyaJiX2geiCPAJ4nEM4NtI9Uj8lONDk6FU86PmoL
yACfb68fBd2pWEzLKsOk9imIobHHpzE=
=gpIn
The following public key can be used to verify RPM packages built and
signed by Red Hat, Inc.  This key is used for packages in Red Hat
products shipped prior to November 2006, and for all updates to those
products.

Questions about this key should be sent to security@redhat.com.

Version: GnuPG v1.0.0 (GNU/Linux)
Comment: For info see http://www.gnupg.org

mQGiBDfqVDgRBADBKr3Bl6PO8BQ0H8sJoD6p9U7Yyl7pjtZqioviPwXP+DCWd4u8
HQzcxAZ57m8ssA1LK1Fx93coJhDzM130+p5BG9mYSWShLabR3N1KXdXQYYcowTOM
GxdwYRGr1Spw8QydLhjVfU1VSl4xt6bupPbWJbyjkg5Z3P7BlUOUJmrx3wCgobNV
EDGaWYJcch5z5B1of/41G8kEAKii6q7Gu/vhXXnLS6m15oNnPVybyngiw/23dKjS
ZVG7rKANEK2mxg1VB+vc/uUc4k49UxJJfCZg1gu1sPFV3GSa+Y/7jsiLktQvCiLP
lncQt1dV+ENmHR5BdIDPWDzKBVbgWnSDnqQ6KrZ7T6AlZ74VMpjGxxkWU6vV2xsW
XCLPA/9P/vtImA8CZN3jxGgtK5GGtDNJ/cMhhuv5tnfwFg4b/VGo2Jr8mhLUqoIb
E6zeGAmZbUpdckDco8D5fiFmqTf5+++pCEpJLJkkzel/32N2w4qzPrcRMCiBURES
PjCLd4Y5rPoU8E4kOHc/4BuHN903tiCsCPloCrWsQZ7UdxfQ5LQiUmVkIEhhdCwg
SW5jIDxzZWN1cml0eUByZWRoYXQuY29tPohVBBMRAgAVBQI36lQ4AwsKAwMVAwID
FgIBAheAAAoJECGRgM3bQqYOsBQAnRVtg7B25Hm11PHcpa8FpeddKiq2AJ9aO8sB
XmLDmPOEFI75mpTrKYHF6rkCDQQ36lRyEAgAokgI2xJ+3bZsk8jRA8ORIX8DH05U
lMH27qFYzLbT6npXwXYIOtVn0K2/iMDj+oEB1Aa2au4OnddYaLWp06v3d+XyS0t+
5ab2ZfIQzdh7wCwxqRkzR+/H5TLYbMG+hvtTdylfqIX0WEfoOXMtWEGSVwyUsnM3
Jy3LOi48rQQSCKtCAUdV20FoIGWhwnb/gHU1BnmES6UdQujFBE6EANqPhp0coYoI
hHJ2oIO8ujQItvvNaU88j/s/izQv5e7MXOgVSjKe/WX3s2JtB/tW7utpy12wh1J+
JsFdbLV/t8CozUTpJgx5mVA3RKlxjTA+On+1IEUWioB+iVfT7Ov/0kcAzwADBQf9
E4SKCWRand8K0XloMYgmipxMhJNnWDMLkokvbMNTUoNpSfRoQJ9EheXDxwMpTPwK
ti/PYrrL2J11P2ed0x7zm8v3gLrY0cue1iSba+8glY+p31ZPOr5ogaJw7ZARgoS8
BwjyRymXQp+8Dete0TELKOL2/itDOPGHW07SsVWOR6cmX4VlRRcWB5KejaNvdrE5
4XFtOd04NMgWI63uqZc4zkRa+kwEZtmbz3tHSdRCCE+Y7YVP6IUf/w6YPQFQriWY
FiA6fD10eB+BlIUqIw80VgjsBKmCwvKkn4jg8kibXgj4/TzQSx77uYokw1EqQ2wk
OZoaEtcubsNMquuLCMWijYhGBBgRAgAGBQI36lRyAAoJECGRgM3bQqYOhyYAnj7h
VDY/FJAGqmtZpwVp9IlitW5tAJ4xQApr/jNFZCTksnI+4O1765F7tA==
=3AHZ
The following public key can be used to verify RPM packages built and
signed by Red Hat, Inc.  This key is used for packages in Red Hat
products shipped after November 2006, and for all updates to those
products.

Questions about this key should be sent to security@redhat.com.

Version: GnuPG v1.2.6 (GNU/Linux)

mQGiBEV2EyQRBAD4/SR69qoLzK4HIa6g9iS+baiX0o3NjkLftFHg/xy+IMOMg//i
4c5bUpLKDTMH3+yT0G8qpul/RALUFOESKFkZm3/SlkJKuroXcB8U6s2dh5XX9DDB
ISqRwL7M5qB8rfDPKHN+k/XwJ9CNpHMdNxnnc2WhnnmHNp6NrD/bUEH4vwCglMa0
rFRXPaN7407DARGHvW/jugsEANFaeZsFwos/sajL1XQRfHZUTnvDjJgz31IFY+OL
DlOVAOtV/NaECMwIJsMIhoisW4Luwp4m75Qh3ogq3bwqSWNLsfJ9WFnNqXOgamyD
h/F4q492z6FpyIb1JZLABBSH7LEQjHlR/s/Ct5JEWc5MyfzdjBi6J9qCh3y/IYL0
EbfRA/4yoJ/fH9uthDLZsZRWmnGJvb+VpRvcVs8IQ4aIAcOMbWu2Sp3U9pm6cxZF
N7tShmAwiiGj9UXVtlhpj3lnqulLMD9VqXGF0YgDOaQ7CP/99OEEhUjBj/8o8udF
gxc1i2WJjc7/sr8IMbDv/SNToi0bnZUxXa/BUjj92uaQ6/LupbQxUmVkIEhhdCwg
SW5jLiAocmVsZWFzZSBrZXkpIDxzZWN1cml0eUByZWRoYXQuY29tPohfBBMRAgAf
BQJFdhMkAhsDBgsJCAcDAgQVAggDAxYCAQIeAQIXgAAKCRBTJoEBNwFxhogXAKCD
TuYeyQrkYXjg9JmOdTZvsIVfZgCcCWKJXtfbC5dbv0piTHI/cdwVzJo=
=mhzo
Version: GnuPG v1.2.6 (GNU/Linux)

mQGiBEYk7/IRBACdWFJInc51/+0sqvadIvf0E+Vhv4aIqB76jWtIGqXnTeG6hEl/
9tJoLszBh4g/KBFVF3E4VxTHXKO/L7GZRa8JzoMtvV8XiP6BaYq6ykx6H7alKvoP
qzk7xBbvNbqsXJCO7keo+g7iIDdfAxvsSJYbhQBxDn5W4Hw7SnHcMmTDOQCg7vOj
UzaZG32yYMBZLjOAB/QzXgsD/1JRDnQ8cL6d17B1ie57ZuVOI3ziQJSmj0zbC0IX
OsxlcFjwydLk3TA88iCr0SO2mfXCsGTeDGFbrl2IRCoH91l3Ew49HI4OYtl+OPSt
pIYdFLSQ+RUPs9CFYwF9Ogjrwmi6jVptKq/+v0WgnCrbfz3DYxCWt/VB1PYDj5y6
Mv//BACKa2mUuQoukDvzqiwZXV/Z52MeDOzPbOFo6qhx+54nav9Inz1yziEjYrP/
ZrNJ4BT6fBgin/a6UmD5FqMtkrrhOCpHFQK2H+XYZ0vVJGZI7h74/fY8U2n+1Mle
xQ/ejWojF+H5nFUAwKHaNVNofKcw8c8msgGn2jsvrAISTSHshrQwUmVkIEhhdCwg
SW5jLiAoUkhYIGtleSkgPHJoeC1zdXBwb3J0QHJlZGhhdC5jb20+iF8EExECAB8F
AkYk7/ICGwMGCwkIBwMCBBUCCAMDFgIBAh4BAheAAAoJEDmhOhJCGT5r6FoAoLsB
+DOPmTc3P+77DnNhU460nmjQAKCI3BJ/SxqPqfp8jL6lTfVo2zxegQ==
=t0np
The following public key can be used to verify RPM packages built and
signed by Red Hat, Inc.  This key is used for packages in Red Hat
products shipped after November 2009, and for all updates to those
products.

Questions about this key should be sent to security@redhat.com.

pub  4096R/FD431D51 2009-10-22 Red Hat, Inc. (release key 2) <security@redhat.com>

Version: GnuPG v1.2.6 (GNU/Linux)

mQINBErgSTsBEACh2A4b0O9t+vzC9VrVtL1AKvUWi9OPCjkvR7Xd8DtJxeeMZ5eF
0HtzIG58qDRybwUe89FZprB1ffuUKzdE+HcL3FbNWSSOXVjZIersdXyH3NvnLLLF
0DNRB2ix3bXG9Rh/RXpFsNxDp2CEMdUvbYCzE79K1EnUTVh1L0Of023FtPSZXX0c
u7Pb5DI5lX5YeoXO6RoodrIGYJsVBQWnrWw4xNTconUfNPk0EGZtEnzvH2zyPoJh
XGF+Ncu9XwbalnYde10OCvSWAZ5zTCpoLMTvQjWpbCdWXJzCm6G+/hx9upke546H
5IjtYm4dTIVTnc3wvDiODgBKRzOl9rEOCIgOuGtDxRxcQkjrC+xvg5Vkqn7vBUyW
9pHedOU+PoF3DGOM+dqv+eNKBvh9YF9ugFAQBkcG7viZgvGEMGGUpzNgN7XnS1gj
/DPo9mZESOYnKceve2tIC87p2hqjrxOHuI7fkZYeNIcAoa83rBltFXaBDYhWAKS1
PcXS1/7JzP0ky7d0L6Xbu/If5kqWQpKwUInXtySRkuraVfuK3Bpa+X1XecWi24JY
HVtlNX025xx1ewVzGNCTlWn1skQN2OOoQTV4C8/qFpTW6DTWYurd4+fE0OJFJZQF
buhfXYwmRlVOgN5i77NTIJZJQfYFj38c/Iv5vZBPokO6mffrOTv3MHWVgQARAQAB
tDNSZWQgSGF0LCBJbmMuIChyZWxlYXNlIGtleSAyKSA8c2VjdXJpdHlAcmVkaGF0
LmNvbT6JAjYEEwECACAFAkrgSTsCGwMGCwkIBwMCBBUCCAMEFgIDAQIeAQIXgAAK
CRAZni+R/UMdUWzpD/9s5SFR/ZF3yjY5VLUFLMXIKUztNN3oc45fyLdTI3+UClKC
2tEruzYjqNHhqAEXa2sN1fMrsuKec61Ll2NfvJjkLKDvgVIh7kM7aslNYVOP6BTf
C/JJ7/ufz3UZmyViH/WDl+AYdgk3JqCIO5w5ryrC9IyBzYv2m0HqYbWfphY3uHw5
un3ndLJcu8+BGP5F+ONQEGl+DRH58Il9Jp3HwbRa7dvkPgEhfFR+1hI+Btta2C7E
0/2NKzCxZw7Lx3PBRcU92YKyaEihfy/aQKZCAuyfKiMvsmzs+4poIX7I9NQCJpyE
IGfINoZ7VxqHwRn/d5mw2MZTJjbzSf+Um9YJyA0iEEyD6qjriWQRbuxpQXmlAJbh
8okZ4gbVFv1F8MzK+4R8VvWJ0XxgtikSo72fHjwha7MAjqFnOq6eo6fEC/75g3NL
Ght5VdpGuHk0vbdENHMC8wS99e5qXGNDued3hlTavDMlEAHl34q2H9nakTGRF5Ki
JUfNh3DVRGhg8cMIti21njiRh7gyFI2OccATY7bBSr79JhuNwelHuxLrCFpY7V25
OFktl15jZJaMxuQBqYdBgSay2G0U6D1+7VsWufpzd/Abx1/c3oi9ZaJvW22kAggq
dzdA27UUYjWvx42w9menJwh/0jeQcTecIUd0d0rFcw/c1pvgMMl/Q73yzKgKYw==
=zbHE
The following public key can be used to verify RPM packages built and
signed by Red Hat, Inc.  This key is a supporting (auxiliary) key for
Red Hat products shipped after November 2006 and for all updates to
those products.

Questions about this key should be sent to security@redhat.com.

Version: GnuPG v1.2.6 (GNU/Linux)

mQGiBEVwDGkRBACwPhZIpvkjI8wV9sFTDoqyPLx1ub8Sd/w+YuI5Ovm49mvvEQVT
VLg8FgE5JlST59AbsLDyVtRa9CxIvN5syBVrWWWtHtDnnylFBcqG/A6J3bI4E9/A
UtSL5Zxbav0+utP6f3wOpxQrxc+WIDVgpurdBKAQ3dsobGBqypeX6FXZ5wCgou6C
yZpGIBqosJaDWLzNeOfb/70D/1thLkQyhW3JJ6cHCYJHNfBShvbLWBf6S231mgmu
MyMlt8Kmipc9bw+saaAkSkVsQ/ZbfjrWB7e5kbMruKLVrH+nGhamlHYUGyAPtsPg
Uj/NUSj5BmrCsOkMpn43ngTLssE9MLhSPj2nIHGFv9B+iVLvomDdwnaBRgQ1aK8z
z6MAA/406yf5yVJ/MlTWs1/68VwDhosc9BtU1V5IE0NXgZUAfBJzzfVzzKQq6zJ2
eZsMLhr96wbsW13zUZt1ing+ulwh2ee4meuJq6h/971JspFY/XBhcfq4qCNqVjsq
SZnWoGdCO6J8CxPIemD2IUHzjoyyeEj3RVydup6pcWZAmhzkKrQzUmVkIEhhdCwg
SW5jLiAoYXV4aWxpYXJ5IGtleSkgPHNlY3VyaXR5QHJlZGhhdC5jb20+iF4EExEC
AB4FAkVwDGkCGwMGCwkIBwMCAxUCAwMWAgECHgECF4AACgkQRWiciC+mWOC1rQCg
ooNLCFOzNPcvhd9Za8C801HmnsYAniCw3yzrCqtjYnxDDxlufH0FVTwX
=d/bm
Version: GnuPG v1.4.7 (GNU/Linux)

mQGiBEJny1wRBACRnbQgZ6qLmJSuGvi/EwrRL6aW610BbdpLQRL3dnwy5wI5t9T3
/JEiEJ7GTvAwfiisEHifMfk2sRlWRf2EDQFttHyrrYXfY5L6UAF2IxixK5FL7PWA
/2a7tkw1IbCbt4IGG0aZJ6/xgQejrOLi4ewniqWuXCc+tLuWBZrGpE2QfwCggZ+L
0e6KPTHMP97T4xV81e3Ba5MD/3NwOQh0pVvZlW66Em8IJnBgM+eQh7pl4xq7nVOh
dEMJwVU0wDRKkXqQVghOxALOSAMapj5mDppEDzGLZHZNSRcvGEs2iPwo9vmY+Qhp
AyEBzE4blNR8pwPtAwL0W3cBKUx7ZhqmHr2FbNGYNO/hP4tO2ochCn5CxSwAfN1B
Qs5pBACOkTZMNC7CLsSUT5P4+64t04x/STlAFczEBcJBLF1T16oItDITJmAsPxbY
iee6JRfXmZKqmDP04fRdboWMcRjfDfCciSdIeGqP7vMcO25bDZB6x6++fOcmQpyD
1Fag3ZUq2yojgXWqVrgFHs/HB3QE7UQkykNp1fjQGbKK+5mWTrQkUmVtaSBDb2xs
ZXQgPFJQTVNARmFtaWxsZUNvbGxldC5jb20+iGAEExECACAFAkZ+MYoCGwMGCwkI
BwMCBBUCCAMEFgIDAQIeAQIXgAAKCRAATm9HAPl/Vv/UAJ9EL8ioMTsz/2EPbNuQ
MP5Xx/qPLACeK5rk2hb8VFubnEsbVxnxfxatGZ25AQ0EQmfLXRAEANwGvY+mIZzj
C1L5Nm2LbSGZNTN3NMbPFoqlMfmym8XFDXbdqjAHutGYEZH/PxRI6GC8YW5YK4E0
HoBAH0b0F97JQEkKquahCakj0P5mGuH6Q8gDOfi6pHimnsSAGf+D+6ZwAn8bHnAa
o+HVmEITYi6s+Csrs+saYUcjhu9zhyBfAAMFA/9Rmfj9/URdHfD1u0RXuvFCaeOw
CYfH2/nvkx+bAcSIcbVm+tShA66ybdZ/gNnkFQKyGD9O8unSXqiELGcP8pcHTHsv
JzdD1k8DhdFNhux/WPRwbo/es6QcpIPa2JPjBCzfOTn9GXVdT4pn5tLG2gHayudK
8Sj1OI2vqGLMQzhxw4hJBBgRAgAJBQJCZ8tdAhsMAAoJEABOb0cA+X9WcSAAn11i
gC5ns/82kSprzBOU0BNwUeXZAJ0cvNmY7rvbyiJydyLsSxh/la6HKw==
=6Rbg
The following public key can be used to verify RPM packages
downloaded from  http://dag.wieers.com/apt/  using 'rpm -K'
if you have the GNU GPG package.
Questions about this key should be sent to:
Dag Wieers <dag@wieers.com>

Version: GnuPG v1.2.1 (GNU/Linux)

mQGiBD9JMT0RBAC9Q2B0AloUMTxaK73sD0cOu1MMdD8yuDagbMlDtUYA1aGeJVO6
TV02JLGr67OBY+UkYuC1c3PUwmb3+jakZd5bW1L8E2L705wS0129xQOZPz6J+alF
5rTzVkiefg8ch1yEcMayK20NdyOmhDGXQXNQS8OJFLTIC6bJs+7MZL83/wCg3cG3
3q7MWHm3IpJb+6QKpB9YH58D/2WjPDK+7YIky/JbFBT4JPgTSBy611+bLqHA6PXq
39tzY6un8KDznAMNtm+NAsr6FEG8PHe406+tbgd7tBkecz3HPX8nR5v0JtDT+gzN
8fM3kAiAzjCHUAFWVAMAZLr5TXuoq4lGTTxvZbwTjZfyjCm7gIieCu8+qnPWh6hm
30NgA/0ZyEHG6I4rOWqPks4vZuD+wlp5XL8moBXEKfEVOMh2MCNDRGnvVHu1P3eD
oHOooVMt9sWrGcgxpYuupPNL4Uf6B6smiLlH6D4tEg+qCxC17zABI5572XJTJ170
JklZJrPGtnkPrrKMamnN9MU4RjGmjh9JZPa7rKjZHyWP/z/CBrQ1RGFnIFdpZWVy
cyAoRGFnIEFwdCBSZXBvc2l0b3J5IHYxLjApIDxkYWdAd2llZXJzLmNvbT6IWQQT
EQIAGQUCP0kxPQQLBwMCAxUCAwMWAgECHgECF4AACgkQog5SFGuNeeYvDQCeKHST
hIq/WzFBXtJOnQkJGSqAoHoAnRtsJVWYmzYKHqzkRx1qAzL18Sd0iEYEEBECAAYF
Aj9JMWAACgkQoj2iXPqnmevnOACfRQaageMcESHVE1+RSuP3txPUvoEAoJAtOHon
g+3SzVNSZLn/g7/Ljfw+uQENBD9JMT8QBACj1QzRptL6hbpWl5DdQ2T+3ekEjJGt
llCwt4Mwt/yOHDhzLe8SzUNyYxTXUL4TPfFvVW9/j8WOkNGvffbs7g84k7a5h/+l
IJTTlP9V9NruDt1dlrBe+mWF6eCY55OFHjb6nOIkcJwKxRd3nGlWnLsz0ce9Hjrg
6lMrn0lPsMV6swADBQP9H42sss6mlqnJEFA97Fl3V9s+7UVJoAIA5uSVXxEOwVoh
Vq7uECQRvWzif6tzOY+vHkUxOBRvD6oIU6tlmuG3WByKyA1d0MTqMr3eWieSYf/L
n5VA9NuD7NwjFA1kLkoDwfSbsF51LppTMkUggzwgvwE46MB6yyuqAVI1kReAWw+I
RgQYEQIABgUCP0kxPwAKCRCiDlIUa4155oktAKDAzm9QYbDpk6SrQhkSFy016BjE
BACeJU1hpElFnUZCL4yKj4EuLnlo8kc=
=mqUt
Version: GnuPG v1.4.5 (GNU/Linux)

mQGiBEpXadARBACHhOfMUuT/4iDvBRmm6bEsvnMN++L79aYhEUMNlrZ2TjKPjPvG
Y0vGk+I0JhUJWutkQRZVbqgVDsNjmnELnACK+xvdryvtxh50wCI9WUl7CT5EV7BS
/jD7JxTFbXyC/Xv0ixMB9vj6U9cySyE8PxONp0HzO6LTIr1OMPgDUsP4lwCgh8De
fmY8TN2m9a0huLdNrnmKw0cD/2bkt6rJAi3+BGHWNgQ9Nb/4wQff8BKGDtL/8acp
3yH91axuD2iYCKw0ZP5akBpRGv+4e30Plmbi1f5NaEDo9Ga1c4TDPopwgiYhrVLj
56efoTfP2AiZl3iBKFPI83/YOhrVZF8UiYoAoUnOFpOg8vmtCzgvYip5UZLTgbfJ
lcWvA/9vMb8By+1pHjW98d7GkzvZqzyMtWlbO7PXCn8P7bGQYjwvyTGiRNz3q22c
2Z29qQw4r1L1L1JGsUwuOMahkczWVdD4TRHc8mhVJEUEA6AkNAZc+Ymsfr/ip0kX
nSZLE3pYVifOhBRO8EbT0WhCMScmZNpwvZU//HKL/p+n3LArUrRZU2NpZW50aWZp
YyBMaW51eCAoUlBNIHNpZ25pbmcga2V5IGZvciBTY2llbnRpZmljIExpbnV4KSA8
c2NpZW50aWZpYy1saW51eC1kZXZlbEBmbmFsLmdvdj6IYAQTEQIAIAUCSldp0AIb
AwYLCQgHAwIEFQIIAwQWAgMBAh4BAheAAAoJELC0GD8ZKn19cXIAnA5R+EbaYr4/
IL6It/UxHXlBFIajAJ9bwmNDF14uvDnFigg1PLevLTBnTIhGBBARAgAGBQJKV6lf
AAoJENpq0AiC/ReyKLQAmwVC/Ii3sAKsptwZKHw/uk1kbupCAJ0eIzSaUo1hSa1V
fP7O/dqigu6JAbkCDQRKV2nZEAgAzAcaC7unRNdrIwAGGKqOIvI8WNwpftHY50Y5
zPSl7vtWVkp3N+2fynJR+tW4G/2xDChBbPzPz/TavRyBc21LKzAlym8qIGEE02cZ
U/YJAYnbAkNNiGMOAnAIjBw1KUcQamAxdk0glE7MP1JiXY1MO4tTW38UEcvQbSvg
Mh/eECqFOwiQXJmkPpZhPUwnwmZRCV4vlCZQM3CMExZ9pDV/V+kuhefw2WeheXyh
g4DC88gcrv2mO0I3sVmpxn3JLMayiMlQbOSYLQuNVKN/EFDwuAbS9Ane7vm6wF9X
NswMX0I/vO1IVvSN1fi5ZM71QzeYUGKBQv97kLO20hbRWZ1V+wADBggAys+jhlYH
mtFZQxV4an1ucqnVauKnstj0zF88Hiy7yivT3W5h3Zd067uOfcBQCJUlt7y8sYD2
q9htm5Rrxx+J29bl0zxwrEatnv0gLzprSa7Ei3wR6IrvBM3Ic0mGSzlsSxlzaFtt
Pwak5C47vX9+PwKEKXFdM1gVzHTuD6PXEYxA4YMlQGeGVA68FvTHxMHpf8POQWTV
QtjoI0flvFT7d4ozqUJdjJZxJDFQ7GO2YdIfF3sUdfn5kFxK0SUzqrmCYXeheniS
LKC4mpAR0PetWJ7r1gY5khHb2eHW1vdEBYUXlHjB+jLaOBns05MHMZYd4CHe8q/Q
gzMeVlh8YLSdZYhJBBgRAgAJBQJKV2nZAhsMAAoJELC0GD8ZKn19iU8AniUIFu32
VeRJ+VKL2vBQMVbFVZOMAJ434Bi99fN2CSh7T62oxtQvhw70fw==
=eL9H
Version: GnuPG v1.4.5 (GNU/Linux)

mQGiBEpXatkRBADSVLhSFxxebo3H16HGjvOg+tSAuppoqrmg9WrC2ly6I41BHXng
n2H0t07nAemb35XSRfb6j4vNIiNoXGFzcjTMP5/cwn24hvilXyA0zX59hhD0ut4c
VGksNhUKnYkVI/+0+EjJ3RnCouVvVx8p2eCIDhjIueDjuLp3mVBLYh7OEwCgmQrO
ysS+xHHcYfUX4jsghfzge10EAIuMAXGWmMLRUJ6PCjrAKVVGT4FxH53UyPjXGXga
SYR4A4aFq9eoDPLRo/nRB/isT0/NfcBbp4wdzYUxz8pmMOWGLFjg7DBBvOj84q+0
ZFibybxFJAtjaZcKw+feCb6R2tJPOfJr6+noOeAZ9MFYZ7z5NG5vezGB1rLu/c5k
vb5LA/9wI8pz7jCMOPBE4LGO9C1tbvKfrFHEfsgn5zsF/+YABCrbHrc2eN2NESpv
84jLHvrssKaPjJVHL1JlRRfO2myT37hLa/D3pUrAcs/CqWGeddKkhJE7c816EO6d
FZU5/7Utill9x3tLu8ZS+WXkH5sr/garxim5P3Sm3K1/ZXZaEbRbU2NpZW50aWZp
YyBMaW51eCAoUlBNIHNpZ25pbmcga2V5IGZvciBTY2llbnRpZmljIExpbnV4IDMp
IDxzY2llbnRpZmljLWxpbnV4LWRldmVsQGZuYWwuZ292PohgBBMRAgAgBQJKV2rZ
AhsDBgsJCAcDAgQVAggDBBYCAwECHgECF4AACgkQAYjOtesQYlrupwCfR65pEGRf
air4Nzf+ZP5Q2i8doscAnAhod/cVNjPA9Lo4UOEAJ5kWZ4CXiEYEEBECAAYFAkpX
pTwACgkQsLQYPxkqfX2m9QCfUzSI3MVchLk00M2c67Xj7ghvNaMAn3TybHcAHpGu
pJ8qBwisCX6mPMSqiEYEEBECAAYFAkpXqW4ACgkQ2mrQCIL9F7LGjwCfWBc67ftN
jTGxL+ilnrYyZhupKd8AoKoSkHG61pxk+Ja58aSvsGRWAdv9uQINBEpXat0QCADG
G22g1V5t8xoxjA5sgDw+ow3QonkA8p+EEr1+xjZyJTsMMiRioz88WH54xcbLBoCM
ltgK3gSYpywEoB76yzFS/woLSjBdCLEMwX6Dj/y1U67ykoDoop31LIW8a4geYJpW
0a83Np00noLidNi7xhuExvp3BxHPpM9mVvqfDOkFcuiexaAU9uF6cgVov8eE95l9
jWcNn1oLnqo2mq2pqJFk0Qkq612Nj2TWOdcrJlksIqEG+H6Jn434u+leGgyR6RnW
Ty4OS4JnwRYXeAfLh2wCCFPWVL6eQTfRjkWmjWlvKIgz8YX+vTx7SfYsfhPRKkgs
ZS0VyRkUSV8EkkRlaRw3AAQLB/9YOgCeW673SBZJUITb1TM4bxT2bk03ORpfqPzu
NBfb4Szm1lsJvlOgEfwZZR2UcQeCqm+WtSSx/Ajce/LA/Q+MYW0X/Vcy1pEYYhs1
9YRZ/1Q7+JR2Q/hCMBvtMf3XN+1sEjHwPJpskq0qBng6SofE+V7FOELswfSk6j+b
2d4G4WEyuiaj6FD5tvrWFmcWgBnhpGG+Rx2n1UT1lqk+r81H4iZB6MoIkicR1gyx
i6mfqJnKMFSWeeXddx7kr6xclDungGlTF/dnk5K73CRm5XBxxYsUYS1Kz8tF6MbB
d/FYJjYlQWx2eAh1xoimlnBgX8BNsmzjbvOtcLtZOUTT95F2iEkEGBECAAkFAkpX
at0CGwwACgkQAYjOtesQYlqHcACfQqTUZxtuSjHWeM2yODl4Cb6kMqkAnjgBLM1s
uix25Q+HkPygJyHv7nEI
=eJoE
Version: GnuPG v1.4.5 (GNU/Linux)

mQGiBEpXa1QRBACRt4l3x+38VrBV58HhPrz8iOKDhMVzBODGetPzqmIX0bLz7nz/
ZYmEPsY0Nhnp77e3cU4YRSUKOM96BZwo8DsJz9sT14b3IozNEo2R7JZNp22RrvU4
gRXjgQmg5N83tnU03KK/IxrbjdO29Go3vGBWM4tWxUoGLG9kQGhYtZL0MwCgn13c
xYt5JRtxLdfNM/Kxbg4FDTsD/31hBoeMetdNHjuMq+I3SMgnAATkgQ1TZHj8lCV3
y0qM0zAfVRuPSTVodlJuMjOUKkERAAWqzXiNkgKtIgREBORmz6d9q/bangLr9ygL
fz/4vTxtfdmXxG8Ru/zVF9Ulu1GuLZKlP1PZosZsMQfbByWVOybg38qdyeC93EGd
qmrBBACQeehjanXRjgEROKXkpe2A6w31m0iu2sT42TUvq5neSXjrFTXN8YPd0SpK
8IiCZHkAh3YBCRogfT7T+uWQsrwICCAf00pEAuP9c6BUeepbjQZPK2fqD16lhRn8
A1TjdngDto45/2T8eIUafh8ONheRuA1Lnb3gV92fUSkQDppw57RbU2NpZW50aWZp
YyBMaW51eCAoUlBNIHNpZ25pbmcga2V5IGZvciBTY2llbnRpZmljIExpbnV4IDQp
IDxzY2llbnRpZmljLWxpbnV4LWRldmVsQGZuYWwuZ292PohgBBMRAgAgBQJKV2tU
AhsDBgsJCAcDAgQVAggDBBYCAwECHgECF4AACgkQ8VzxvJUFci5eswCffepTdZlb
60FSFxWfLGXdr6NLVY0Anj2ILigIHnOQ/Tb0fX4Wok2rObm1iEYEEBECAAYFAkpX
pPwACgkQsLQYPxkqfX27WgCfccR97sqL4klabdAmAkQ0TSXZ+AgAn0FUCu92L9xP
i9td6W7lPh0zdnudiEYEEBECAAYFAkpXqXsACgkQ2mrQCIL9F7LzywCdGT6FQ4ZT
swwxZA63MrLn7ZdN/r4AoLvfdudahfiuiZQtGTYvoR3gzw70uQINBEpXa10QCACr
GeMNUJTtApiwStqIKXGj5BahvI2muQPOF0yr5fqpOwA1SnucTQmwEVtBHRhR+J3V
iOQ8igyMUxOe0F6JCOAbZIx0G5iVs51+wT1LYD2bQkUoObIToGut9r6NlI2selcP
lqx2ckziGVOSU77/7MoGo5GNbWJaNHWCNh6zrA+5hKY46va7hkm0WFFvlZ+U8OCB
aI8BnwB7JZCNdrBgL37oX1qm53BboDaE4aY/73gIvCd3M5bjuqbe666zvQo8xdbL
wiSe8LrHHa7EHxWNFYxv91H56FIP7sbnbiSYKZiOMahnc2hBAa0CAsWhWKDSnqt4
IN6VOMvqooFllvRXLVgnAAQLCACMm7NhtX0k5AAz3dsXREiQ5hpCS0+djxHTOyAf
aYjB9FTV2WfWQ9G/KTowpQm4nu6IHzFtHWn8mt7/wnxnSIPeykjgAeuzXd/mSBM6
/FobeXZsb7a6vDZNP4gSGzMAv7xl4QdBWGxQMRED7Lvg1rU70Dh/X2WvRu3a0MBy
xHdTBmpIUIQJ0VV6ikGXvu7DS2skvL7lZxKTHPr0zho6rf9De7GJ6FGCAKfdmgjQ
Gm1i9/pH05UQ4+FD/JyNwEX/CPf8qb6PgtwoJeJ+SPnWZlayYBEB03sK1fD/RIfF
TbRoJz8YRBniC0AwLlUj3n6IdVGrcK8vy2MvVHF//cXLmCroiEgEGBECAAkFAkpX
a10CGwwACgkQ8VzxvJUFci4ylgCY4OS+SEAqiiqz1VBCKq5PxNpzXgCffwtqFgV9
aFtaKnBEuQRBQ5uz+mA=
=G01V
Version: GnuPG v1.4.5 (GNU/Linux)

mQGiBEpXa6URBADLDs4W73NK1DOZq0mWfmMwv27uaAS4RZuJJWj6eTmF2YcAdVPr
rsfvBB1GrN5YluqGCN0CBSULtmoxE8AVB/2kGgIZmD7x10+dMXn0cYJrQuTjtf1z
xos1cmdzK7Or0p5dQbuxvlpEseFATGimggBeunwSt5qMpXqN9/1dqksK0wCgi/Tu
JyR3Wsg0NqZrUbr5vEiqHoMEALmYht9n6lCt4j6oYZGZ1DlTwjaAjeJe9qdDlbx7
fNsfFwV1fqMFc2Bop7UJXfTytVXzDwISsn5YLK2ty1kSuA/7PCt7OkrbchBwm/y0
5KiGjnC0D+6qdApnwJClWFsu6VqquRiplAJ+6bMw/z+VXVnJztMx09tQ/M9idN//
mJYHA/9989JcHDi0hPlCCYHGs9Bw70H9TvzanKwq5GRlSbEDz9LrrJopJuz788Xu
xg0WXVlduwrEqU2wlq8lY2m6UlkfIya/fs6NkDCJE3bHSMjfovpL6cUFCKedKsas
ODOio6i3ZEcWXz3w4Dv43Mb/z1m8Fe5e6Z0jw5OwEQeWLIHHjbRbU2NpZW50aWZp
YyBMaW51eCAoUlBNIHNpZ25pbmcga2V5IGZvciBTY2llbnRpZmljIExpbnV4IDUp
IDxzY2llbnRpZmljLWxpbnV4LWRldmVsQGZuYWwuZ292PohgBBMRAgAgBQJKV2ul
AhsDBgsJCAcDAgQVAggDBBYCAwECHgECF4AACgkQKHfjrROgotzliQCfdmgSNeDY
fkako6w5P1RgYg+gnoAAnjdtRp8wrrlT7lD1fyZelaX+5GOxiEYEEBECAAYFAkpX
pFMACgkQsLQYPxkqfX1tUACdEsZdXFXMG2nhU4Eema+NQ7dPT3EAn2xH8ARaCHLo
xg/knc9G04Wd0Q6NiEYEEBECAAYFAkpXqYgACgkQ2mrQCIL9F7Ji0gCbBQ6cYMbI
Dd9B+cYFXDrSDqUmkXMAoJAv8rAPO4IfRsVd++gt28/G293TuQINBEpXa6gQCAC3
VnB5gncnFQSjlu0YXhMQzOlXZ1/UVT262emIACbECDTUoy9U1J4VEecZimIe/BId
uEEBY76i5pmvEV5iWzP3UbCCCUQmpMlFk2LV1jci30/2uTSVXL3yicfrOs74W3rG
4DxN3cHbttEAZJgH0nKAg48APWsKOgrlgzPk63/vzcuymSnXWTiYksslXQ+NYOoV
2Oux9y65K1PjEZoftjorrtcx4E6P0LO5hoowFucfo3VEYpzCjeLogjMmS5Af5GyI
+/5QSQLQ+m0vzppwE8mIt1jsHtEy/0XIdOZTIA10e/I4AvxVoRHbdVY1LjtrkXKN
CGTyaydBe3a4MDoUQWTzAAMGCACW8tORZd0boInktcNWS/szBgAllwPVhFUF4hk7
pp1rPsiW3h36ARvhvdtNlHHgFPExU4fSinnpMUL0ajx4jEXGg6178WHMFvLUw6ww
Ts1rXaHHagLwemG9iQ1++lLewSkqlKOjVvdV03WOHBwt5GTNe7KCuuM2ko27wSVY
YpbP4A5jEhMkQuWsXPpNu+Oj5uS8XzrIR9McHK0lD9vU2cUUM7OauRo4obygodOa
cwmd0NnRyYf5aPMn4AI795/eWuFK1WYz1Fe7uX7PNcrc2oGEUuqADFNfwtN2HN1V
4dDBHUiPiPydrSml2l4T2NOLI2wVaXIfKdM/6R4agf7lruJliEkEGBECAAkFAkpX
a6gCGwwACgkQKHfjrROgotzpAwCfbLfWIHyWyaWdBRRTixIRs/LFkzYAn3eVy9pL
omk16gZFWxiB8lelViC1
=ta+t
Version: GnuPG v1.4.5 (GNU/Linux)

mQGiBEpXa+QRBADFJtkQOdBsPIElO4SQnri0o6+d1uaaIkclI3uu88Pmy7LkBO4L
y8U7jKS1y4m6I49hpqALM43wq8tm7BYWObd+xlol2mZEgbrxHoFugqfEKAOKxLut
CkCC0wFOK3psQQMSNLokPHYLP6MJL84VsS+molGpUE7EtZZMRaHXyHiU+wCgg5dF
3TD3rYn2PXkiAFlHs6/OficEAK0zmzEdzNfdfWwipf4AQrAEaBO9If7eo5zj6RX9
bajg0IRgTxpwq6dP+bnnoEtm/v0vZeAGe8zscCX8xIPtDqu7+QbMe89SSdKJXHog
/cC/vOS1+s5TKX2ervZ7pAauyve1xO53eVxsg6oDtTwIqvlQbmi6Vs2I3lplhJj9
sZZ1A/4oNeWoZlBnxr/0eyHDktW89x0wt0R+jJVksnHJxyg7D+MLmaDZR0Fjg8Wt
EhW8Q5WS0rkk39VaFoA3oR9nfEzAJgymSqNjTEwLsPaqvq6Q5zE+nouYP46cMbcW
PKmST+QZCRMfznam667eKk0+opBIhDy57M2Kerx4EZyMy/0l4LRbU2NpZW50aWZp
YyBMaW51eCAoUlBNIHNpZ25pbmcga2V5IGZvciBTY2llbnRpZmljIExpbnV4IDYp
IDxzY2llbnRpZmljLWxpbnV4LWRldmVsQGZuYWwuZ292PohgBBMRAgAgBQJKV2vk
AhsDBgsJCAcDAgQVAggDBBYCAwECHgECF4AACgkQkV114Jsf01BepACeO7UR33C6
g4HfHvLVq8zf1SU99y4An1ZOfgrW5iVCEwDc+bWiUu6sbujIiEYEEBECAAYFAkpX
pBIACgkQsLQYPxkqfX0yCACfap7Y7XpjuSr2DXL+ohDbAM+xdOIAnRjegnSEBqHa
Hpi8a7gS69H2hz51iEYEEBECAAYFAkpXqZUACgkQ2mrQCIL9F7IHlgCgr/SqepQ/
8aXpbQqtwXQho6kDEHIAnRbtNiBRZl4B+fbh6ZsdOr6QHIiOuQINBEpXa+oQCACw
50+Jv6VEVrAL+rRoptmBmHbg8XhNfOPn349GYCtZ9TebCtmU82MEWYF4Eo5vk1JM
P29EBTKfYHBYsD231HavQa4EXVcjYm38i43c0P0sVvO1t5x2EDncthd+Sx3P/36k
mr9pjCA9PFR3zLUA3YxqeipgrfU2NhDh4yvxgHogYjn1Gdqf0TWo2lqYnLjAMbZ0
y7Mk5G6SfZcSRrZvjZgvXUlmynJXMY766LjyrfasuS4fd2LWFovXOakBb5lR7Z/O
ec1U8CEypQ2iC9ww+Tg0tq+oIJ8g27pJrYsfoCf6HVhsxFOzxf8pjNTilWIB4lMk
ok5+QnQwDVOykeXFDoKXAAMFB/9w1l+PFODmKJFCPqkYj2+0a+rT+76hDVaPJC8E
xcsGf5uJQpOdgqgqMgT1kczMX4CbJ/OIqJVnuFGxoBh2tblwtHvGTwepSTn/yUyd
SbCKmgMr8WafSZUxcRFPql4U2yBvAvdkTCTl+OHv3CrAZxDTV15FoHyPRm/2XU2f
75Y3EutNLrh3TB5aXEveTe1LP+eYDtYTa/nW6A3WqOKWN7wpMBQ9H65mgN9au+g2
Euh4DtV/myhnyILMYfCPvUAO68MZ4INC/koV0R78HBI4HHVE0Im338fQeS4g30eL
+IPoYGAkRQsZ8pi5JnVdqUK9DuNA+NuEhZmYycC6RCxUaKFmiEkEGBECAAkFAkpX
a+oCGwwACgkQkV114Jsf01C04QCdGkNIVHih/YkT79eykpQ8dUUfGkUAnjV0pyzz
5XK12rKD3j1Z+SNr+Lqs
=EcEL
Version: GnuPG v1.4.6 (GNU/Linux)

mQGiBD5gtCgRBACKIvjMF+20r9k/Uw2Hq6Y/qn1nM0AZEFalhglXP5pMm5bMgkcI
1vCWqJxSbhQhk8hSEenoszes8hyUxHj4hFFUDiRtAxOpCpGCsCnUddgQtHAQd+tm
aQsM6J3Jm/EZPtwR0lvwvRGvz2x6Rr95G8+42KK9x+mBYhLk0y3gAbBzhwCgnkDH
a97MGBT7gRLrmtFqiHrWlPkD/2tBaH6IEuoJhcAbNj9MukbhDOYJ6ic9Nzf6sR3t
ZG+XgQLLS2DNy8+HWcYJOjpJDEe8zWFDdUv3cL1D0U2f2e85FuJaMucHn+816iw8
mNjZXJEoDE4LJ8Vv53fkevNZpdWmO2VtRwI+woDnIHYHukDLj2sWhVt+5W+uOKAE
OippA/9OzuWrwBtTR+Np8ApZGkxhxU1z0iEStV+kQNqJE7YoR4SGMuzEa3bFzrPx
k4qIU+rw4YgFgHrs1x08lXxNOZkq6avvbl60HqN2qF2UQL/YdU+5X3ixaJVaYYk8
yuK+hp0Hx2DdBWmVhq6rEzIfpnFhF4qspwMWEiiBGjYDL62W7LQ0QVRycG1zLm5l
dCAocnBtIHNpZ25pbmcga2V5KSA8QXhlbC5UaGltbUBBVHJwbXMubmV0PohnBBMR
AgAnAhsDBgsJCAcDAgMVAgMDFgIBAh4BAheAAhkBBQJFfF9PBQkJGI4nAAoJEFCM
5eZmU0wrJ0IAnA0BdyRlq2S8ess55R8YMFnWAWXEAJ9Fa7cEHku4j4B83shCODps
+DYUZohnBBMRAgAnAhsDBQkDdMLsBgsJCAcDAgMVAgMDFgIBAh4BAheABQJAKteu
AhkBAAoJEFCM5eZmU0wrMMUAnRjS2PXQp0tsC/69IGMMxqU+8xeAAJ9XQjVAo+mU
kg/3AeBlMBIlFe5hDQ==
=23Fz
Version: GnuPG v1.2.6 (GNU/Linux)

mQGiBEY5QQ0RBACfC1NbAdGFMOS/Y7P9hmNph2Wh3TJTh6IZpL+lTJBuZSEa6rp0
CghS/yU3gGXUPaxAy91M7PXMv5p7S3U/SusZHATLhFdU5J4LuWMf4IiBy9FOB/aj
Q1s5vZ/i3YFaqolXsRP8TgIu4Lzp/j3+KAxFb3gF7lz64J/Et2Jil0OQzwCgkn9i
SoPEM6d9SCFOidhUuTHUhM0D/3UXl/FKPVFrFzjslFpaN9NgArRrmXKTOBWEqMLy
12pbTzOtv+p17Ot51q4h0ebEWrmVJ/h/7Is6QT6AKHuOIW+1/88fcSrmef//0Scz
wtEwVudkYA+kOGt1pwhapVYf1lWE9Z6L3V/MVdxXUesylGO6jJjOjpUB+ZBItwl7
exkhA/4iemhq4D5Jp6r1Kv3aKSPNENdhTORyfZz4UfyOsUfYncaprP5IZja0j+rd
tQLIsH8hXvCT2kSAUY6nMGmzPgpgGamtHI6gH1ZmoNX2gEF7tzGNgKMbbUmwO89B
N56U7wm68AreXE8XviRjGjAtZWnouqe5X+EiUurdJkzRwU0c2rQpVGhvdWdodFdv
cmtzIDxydWJ5d29ya3NAdGhvdWdodHdvcmtzLmNvbT6IYAQTEQIAIAUCRjlBDQIb
AwYLCQgHAwIEFQIIAwQWAgMBAh4BAheAAAoJEHM/KlUQbeB0SSYAn0sgAx5ZK975
wZiChkIqOCyFZ9PLAJ9laivkzqT2y+Kh9FGe3TP/CAhRTbkCDQRGOUEVEAgAqxJI
MFrYV3JKyeXHVKXHNd5Nf1WdqKi37VOdSTBftiehzZdR9hxkGEknYxnbBLGJR9YD
/uJ2+DRwNBcw2RrrEmb0DCZxcLQLZ3xYa7+WvcR4/Nir/3858SGJ+wmGCHKyX2So
M2TurmKu5bqyUUaBgf+IhKfwOr9zeK3rIRhUq/aiYkw8sWA8ruUvxXwLnbkK1aP9
hfvSqScwjkfUVk6CQ6GFUD+4N4mNRtRcZz3gYa+0jSNeEJZQOJxRuE/gBHav3eyN
dm4VAFPF20BobvBVEcMhO0KaR/X4jW1G1eFAKLxI7cdx3+vLeNPaFwHiSMSknsNs
UiucI9oV+I5S/50ZrwADBwf/StYTK9KvPnY9ZqmirBpSh0Zl0xylMtAiMblG7pKv
qKTPNr9zXooheQBpAbnhOfju0DB/OtE4V21HqnbMws2aFvHecEbO5EmjwT7ZTltH
5vlbiPrXOc7SpP22FdkOYdunM2+nsA6398mpYFEiFFNAzX6pReN2tbbmXf6zxS9n
nHjMAgl5nMuOASLZrTrUX/7yu6ySS1hy0ZVfEoAFeILy4MV8y0lVjBQa2kNOCNpO
Cc+y1+4EHLS3fuN0x+tho3rhjKAzj8KOt4XnALn8OouRMx9G7ItC2U8kNzHHFRg5
adT/+nEthVd9q9pYLrUaze7aMQyl+7cD1KzmSe34X9B6W4hJBBgRAgAJBQJGOUEV
AhsMAAoJEHM/KlUQbeB0O7QAn09h4qrKPhWD9eaiyMRS5YeARTYgAJ9WxLcQEvkA
yOSLb33CweehCrlTnQ==
=scSy
# Placeholder for git
Version: GnuPG v1.2.6 (GNU/Linux)

mQGiBEWfB6MRBACrnYW6yKMT+MwJlCIhoyTxGf3mAxmnAiDEy6HcYN8rivssVTJk
CFtQBlBOpLV/OW2YtKrCO2xHn46eNfnMri8FGT8g+9JF3MUVi7kiV1He4iJynHXB
+F2ZqIvHf3IaUj1ys+p8TK64FDFxDQDrGQfIsD/+pkSGx53/877IrvdwjwCguQcr
Ioip5TH0Fj0OLUY4asYVZH8EAIqFHEqsY+9ziP+2R3/FyxSllKkjwcMLrBug+cYO
LYDD6eQXE9Mq8XKGFDj9ZB/0+JzK/XQeStheeFG75q3noq5oCPVFO4czuKErIRAB
qKbDBhaTj3JhOgM12XsUYn+rI6NeMV2ZogoQCC2tWmDETfRpYp2moo53NuFWHbAy
XjETA/sHEeQT9huHzdi/lebNBj0L8nBGfLN1nSRP1GtvagBvkR4RZ6DTQyl0UzOJ
RA3ywWlrL9IV9mrpb1Fmn60l2jTMMCc7J6LacmPK906N+FcN/Docj1M4s/4CNanQ
NhzcFhAFtQL56SNyLTCk1XzhssGZ/jwGnNbU/aaj4wOj0Uef5LRGQ2VudE9TLTUg
S2V5IChDZW50T1MgNSBPZmZpY2lhbCBTaWduaW5nIEtleSkgPGNlbnRvcy01LWtl
eUBjZW50b3Mub3JnPohkBBMRAgAkBQJFnwekAhsDBQkSzAMABgsJCAcDAgMVAgMD
FgIBAh4BAheAAAoJEKikR9zoViiXKlEAmwSoZDvZo+WChcg3s/SpNoWCKhMAAJwI
E2aXpZVrpsQnInUQWwkdrTiL5YhMBBMRAgAMBQJFnwiSBYMSzAIRAAoJEDjCFhY5
bKCk0hAAn134bIx3wSbq58E6P6U5RT7Z2Zx4AJ9VxnVkoGHkVIgSdsxHUgRjo27N
F7kBDQRFnwezEAQA/HnJ5yiozwgtf6jt+kii8iua+WnjqBKomPHOQ8moxbWdv5Ks
4e1DPhzRqxhshjmub4SuJ93sgMSAF2ayC9t51mSJV33KfzPF2gIahcMqfABe/2hJ
aMzcQZHrGJCEX6ek8l8SFKou7vICzyajRSIK8gxWKBuQknP/9LKsoczV+xsAAwUD
/idXPkk4vRRHsCwc6I23fdI0ur52bzEqHiAIswNfO521YgLk2W1xyCLc2aYjc8Ni
nrMX1tCnEx0/gK7ICyJoWH1Vc7//79sWFtX2EaTO+Q07xjFX4E66WxJlCo9lOjos
Vk5qc7R+xzLDoLGFtbzaTRQFzf6yr7QTu+BebWLoPwNTiE8EGBECAA8FAkWfB7MC
GwwFCRLMAwAACgkQqKRH3OhWKJfvvACfbsF1WK193zM7vSc4uq51XsceLwgAoI0/
9GxdNhGQEAweSlQfhPa3yYXH
=o/Mx

Version: GnuPG v1.4.5 (GNU/Linux)

mQINBE4P06MBEACqn48FZgYkG2QrtUAVDV58H6LpDYEcTcv4CIFSkgs6dJ9TavCW
NyPBZRpM2R+Rg5eVqlborp7TmktBP/sSsxc8eJ+3P2aQWSWc5ol74Y0OznJUCrBr
bIdypJllsD9Fe+h7gLBXTh3vdBEWr2lR+xA+Oou8UlO2gFbVFQqMafUgU1s0vqaE
/hHH0TzwD0/tJ6eqIbHwVR/Bu6kHFK4PwePovhfvyYD9Y+C0vOYd5Ict2vbLHz1f
QBDZObv4M6KN3j7nzme47hKtdMd+LwFqxM5cXfM6b5doDulWPmuGV78VoX6OR7el
x1tlfpuiFeuXYnImm5nTawArcQ1UkXUSYcTUKShJebRDLR3BycxR39Q9jtbOQ29R
FumHginovEhdUcinRr22eRXgcmzpR00zFIWoFCwHh/OCtG14nFhefuZ8Z80qbVhW
2J9+/O4tksv9HtQBmQNOK5S8C4HNF2M8AfOWNTr8esFSDc0YA5/cxzdfOOtWam/w
lBpNcUUSSgddRsBwijPuWhVA3NmA/uQlJtAo4Ji5vo8cj5MTPG3+U+rfNqRxu1Yc
ioXRo4LzggPscaTZX6V24n0fzw0J2k7TT4sX007k+7YXwEMqmHpcMYbDNzdCzUer
Zilh5hihJwvGfdi234W3GofttoO+jaAZjic7a3p6cO1ICMgfVqrbZCUQVQARAQAB
tEZDZW50T1MtNiBLZXkgKENlbnRPUyA2IE9mZmljaWFsIFNpZ25pbmcgS2V5KSA8
Y2VudG9zLTYta2V5QGNlbnRvcy5vcmc+iQI8BBMBAgAmBQJOD9OjAhsDBQkSzAMA
BgsJCAcDAgQVAggDBBYCAwECHgECF4AACgkQCUb8osEFud6ajRAAnb6d+w6Y/v/d
MSy7UEy4rNquArix8xhqBwwjoGXpa37OqTvvcJrftZ1XgtzmTbkqXc+9EFch0C+w
ST10f+H0SPTUGuPwqLkg27snUkDAv1B8laub+l2L9erzCaRriH8MnFyxt5v1rqWA
mVlRymzgXK+EQDr+XOgMm1CvxVY3OwdjdoHNox4TdVQWlZl83xdLXBxkd5IRciNm
sg5fJAzAMeg8YsoDee3m4khg9gEm+/Rj5io8Gfk0nhQpgGGeS1HEXl5jzTb44zQW
qudkfcLEdUMOECbu7IC5Z1wrcj559qcp9C94IwQQO+LxLwg4kHffvZjCaOXDRiya
h8KGsEDuiqwjU9HgGq9fa0Ceo3OyUazUi+WnOxBLVIQ8cUZJJ2Ia5PDnEsz59kCp
JmBZaYPxUEteMtG3yDTa8c8jUnJtMPpkwpSkeMBeNr/rEH4YcBoxuFjppHzQpJ7G
hZRbOfY8w97TgJbfDElwTX0/xX9ypsmBezgGoOvOkzP9iCy9YUBc9q/SNnflRWPO
sMVrjec0vc6ffthu2xBdigBXhL7x2bphWzTXf2T067k+JOdoh5EGney6LhQzcp8m
YCTENStCR+L/5XwrvNgRBnoXe4e0ZHet1CcCuBCBvSmsPHp5ml21ahsephnHx+rl
JNGtzulnNP07RyfzQcpCNFH7W4lXzqM=
=jrWY
Version: GnuPG v1.2.6 (GNU/Linux)

mQGiBEXopTIRBACZDBMOoFOakAjaxw1LXjeSvh/kmE35fU1rXfM7T0AV31NATCLF
l5CQiNDA4oWreDThg2Bf6+LIVTsGQb1V+XXuLak4Em5yTYwMTVB//4/nMxQEbpl/
QB2XwlJ7EQ0vW+kiPDz/7pHJz1p1jADzd9sQQicMtzysS4qT2i5A23j0VwCg1PB/
lpYqo0ZhWTrevxKMa1n34FcD/REavj0hSLQFTaKNLHRotRTF8V0BajjSaTkUT4uk
/RTaZ8Kr1mTosVtosqmdIAA2XHxi8ZLiVPPSezJjfElsSqOAxEKPL0djfpp2wrTm
l/1iVnX+PZH5DRKCbjdCMLDJhYap7YUhcPsMGSeUKrwmBCBJUPc6DhjFvyhA9IMl
1T0+A/9SKTv94ToP/JYoCTHTgnG5MoVNafisfe0wojP2mWU4gRk8X4dNGKMj6lic
vM6gne3hESyjcqZSmr7yELPPGhI9MNauJ6Ob8cTR2T12Fmv9w03DD3MnBstR6vhP
QcqZKhc5SJYYY7oVfxlSOfF4xfwcHQKoD5TOKwIAQ6T8jyFpKbQkRmVkb3JhIEVQ
RUwgPGVwZWxAZmVkb3JhcHJvamVjdC5vcmc+iGQEExECACQFAkXopTICGwMFCRLM
AwAGCwkIBwMCAxUCAwMWAgECHgECF4AACgkQEZzANiF1IfabmQCgzvE60MnHSOBa
ZXXF7uU2Vzu8EOkAoKg9h+j0NuNom6WUYZyJQt4zc5seuQINBEXopTYQCADapnR/
blrJ8FhlgNPl0X9S3JE/kygPbNXIqne4XBVYisVp0uzNCRUxNZq30MpY027JCs2J
nL2fMpwvx33f0phU029vrIZKA3CmnnwVsjcWfMJOVPBmVN7m5bGU68F+PdRIcDsl
PMOWRLkTBZOGolLgIbM4719fqA8etewILrX6uPvRDwywV7/sPCFpRcfNNBUY+Zx3
5bf4fnkaCKxgXgQS3AT+hGYhlzIqQVTkGNveHTnt4SSzgAqR9sSwQwqvEfVtYNeS
w5rDguLG41HQm1Hojv59HNYjH6F/S1rClZi21bLgZbKpCFX76qPt8CTw+iQLBPPd
yoOGHfzyp7nsfhUrAAMFB/9/H9Gpk822ZpBexQW4y3LGFo9ZSnmu+ueOZPU3SqDA
DW1ovZdYzGuJTGGM9oMl6bL8eZrcUBBOFaWge5wZczIE3hx2exEOkDdvq+MUDVD1
axmN45q/7h1NYRp5GQL2ZsoV4g9U2gMdzHOFtZCER6PP9ErVlfJpgBUCdSL93V4H
Sgpkk7znmTOklbCM6l/G/A6q4sCRqfzHwVSTiruyTBiU9lfROsAl8fjIq2OzWJ2T
P9sadBe1llUYaow7txYSUxssW+89avct35gIyrBbof5M+CBXyAOUaSWmpM2eub24
0qbqiSr/Y6Om0t6vSzR8gRk7g+1H6IE0Tt1IJCvCAMimiE8EGBECAA8FAkXopTYC
GwwFCRLMAwAACgkQEZzANiF1IfZQYgCgiZHCv4xb+sTHCn/otc1Ovvi/OgMAnRXY
bbsLFWOfmzAnNIGvFRWy+YHi
=MMNL
Version: GnuPG v1.2.6 (GNU/Linux)

mQGiBEXopTIRBACZDBMOoFOakAjaxw1LXjeSvh/kmE35fU1rXfM7T0AV31NATCLF
l5CQiNDA4oWreDThg2Bf6+LIVTsGQb1V+XXuLak4Em5yTYwMTVB//4/nMxQEbpl/
QB2XwlJ7EQ0vW+kiPDz/7pHJz1p1jADzd9sQQicMtzysS4qT2i5A23j0VwCg1PB/
lpYqo0ZhWTrevxKMa1n34FcD/REavj0hSLQFTaKNLHRotRTF8V0BajjSaTkUT4uk
/RTaZ8Kr1mTosVtosqmdIAA2XHxi8ZLiVPPSezJjfElsSqOAxEKPL0djfpp2wrTm
l/1iVnX+PZH5DRKCbjdCMLDJhYap7YUhcPsMGSeUKrwmBCBJUPc6DhjFvyhA9IMl
1T0+A/9SKTv94ToP/JYoCTHTgnG5MoVNafisfe0wojP2mWU4gRk8X4dNGKMj6lic
vM6gne3hESyjcqZSmr7yELPPGhI9MNauJ6Ob8cTR2T12Fmv9w03DD3MnBstR6vhP
QcqZKhc5SJYYY7oVfxlSOfF4xfwcHQKoD5TOKwIAQ6T8jyFpKbQkRmVkb3JhIEVQ
RUwgPGVwZWxAZmVkb3JhcHJvamVjdC5vcmc+iGQEExECACQFAkXopTICGwMFCRLM
AwAGCwkIBwMCAxUCAwMWAgECHgECF4AACgkQEZzANiF1IfabmQCgzvE60MnHSOBa
ZXXF7uU2Vzu8EOkAoKg9h+j0NuNom6WUYZyJQt4zc5seuQINBEXopTYQCADapnR/
blrJ8FhlgNPl0X9S3JE/kygPbNXIqne4XBVYisVp0uzNCRUxNZq30MpY027JCs2J
nL2fMpwvx33f0phU029vrIZKA3CmnnwVsjcWfMJOVPBmVN7m5bGU68F+PdRIcDsl
PMOWRLkTBZOGolLgIbM4719fqA8etewILrX6uPvRDwywV7/sPCFpRcfNNBUY+Zx3
5bf4fnkaCKxgXgQS3AT+hGYhlzIqQVTkGNveHTnt4SSzgAqR9sSwQwqvEfVtYNeS
w5rDguLG41HQm1Hojv59HNYjH6F/S1rClZi21bLgZbKpCFX76qPt8CTw+iQLBPPd
yoOGHfzyp7nsfhUrAAMFB/9/H9Gpk822ZpBexQW4y3LGFo9ZSnmu+ueOZPU3SqDA
DW1ovZdYzGuJTGGM9oMl6bL8eZrcUBBOFaWge5wZczIE3hx2exEOkDdvq+MUDVD1
axmN45q/7h1NYRp5GQL2ZsoV4g9U2gMdzHOFtZCER6PP9ErVlfJpgBUCdSL93V4H
Sgpkk7znmTOklbCM6l/G/A6q4sCRqfzHwVSTiruyTBiU9lfROsAl8fjIq2OzWJ2T
P9sadBe1llUYaow7txYSUxssW+89avct35gIyrBbof5M+CBXyAOUaSWmpM2eub24
0qbqiSr/Y6Om0t6vSzR8gRk7g+1H6IE0Tt1IJCvCAMimiE8EGBECAA8FAkXopTYC
GwwFCRLMAwAACgkQEZzANiF1IfZQYgCgiZHCv4xb+sTHCn/otc1Ovvi/OgMAnRXY
bbsLFWOfmzAnNIGvFRWy+YHi
=MMNL
Version: GnuPG v1.2.6 (GNU/Linux)

mQGiBEXopTIRBACZDBMOoFOakAjaxw1LXjeSvh/kmE35fU1rXfM7T0AV31NATCLF
l5CQiNDA4oWreDThg2Bf6+LIVTsGQb1V+XXuLak4Em5yTYwMTVB//4/nMxQEbpl/
QB2XwlJ7EQ0vW+kiPDz/7pHJz1p1jADzd9sQQicMtzysS4qT2i5A23j0VwCg1PB/
lpYqo0ZhWTrevxKMa1n34FcD/REavj0hSLQFTaKNLHRotRTF8V0BajjSaTkUT4uk
/RTaZ8Kr1mTosVtosqmdIAA2XHxi8ZLiVPPSezJjfElsSqOAxEKPL0djfpp2wrTm
l/1iVnX+PZH5DRKCbjdCMLDJhYap7YUhcPsMGSeUKrwmBCBJUPc6DhjFvyhA9IMl
1T0+A/9SKTv94ToP/JYoCTHTgnG5MoVNafisfe0wojP2mWU4gRk8X4dNGKMj6lic
vM6gne3hESyjcqZSmr7yELPPGhI9MNauJ6Ob8cTR2T12Fmv9w03DD3MnBstR6vhP
QcqZKhc5SJYYY7oVfxlSOfF4xfwcHQKoD5TOKwIAQ6T8jyFpKbQkRmVkb3JhIEVQ
RUwgPGVwZWxAZmVkb3JhcHJvamVjdC5vcmc+iGQEExECACQFAkXopTICGwMFCRLM
AwAGCwkIBwMCAxUCAwMWAgECHgECF4AACgkQEZzANiF1IfabmQCgzvE60MnHSOBa
ZXXF7uU2Vzu8EOkAoKg9h+j0NuNom6WUYZyJQt4zc5seuQINBEXopTYQCADapnR/
blrJ8FhlgNPl0X9S3JE/kygPbNXIqne4XBVYisVp0uzNCRUxNZq30MpY027JCs2J
nL2fMpwvx33f0phU029vrIZKA3CmnnwVsjcWfMJOVPBmVN7m5bGU68F+PdRIcDsl
PMOWRLkTBZOGolLgIbM4719fqA8etewILrX6uPvRDwywV7/sPCFpRcfNNBUY+Zx3
5bf4fnkaCKxgXgQS3AT+hGYhlzIqQVTkGNveHTnt4SSzgAqR9sSwQwqvEfVtYNeS
w5rDguLG41HQm1Hojv59HNYjH6F/S1rClZi21bLgZbKpCFX76qPt8CTw+iQLBPPd
yoOGHfzyp7nsfhUrAAMFB/9/H9Gpk822ZpBexQW4y3LGFo9ZSnmu+ueOZPU3SqDA
DW1ovZdYzGuJTGGM9oMl6bL8eZrcUBBOFaWge5wZczIE3hx2exEOkDdvq+MUDVD1
axmN45q/7h1NYRp5GQL2ZsoV4g9U2gMdzHOFtZCER6PP9ErVlfJpgBUCdSL93V4H
Sgpkk7znmTOklbCM6l/G/A6q4sCRqfzHwVSTiruyTBiU9lfROsAl8fjIq2OzWJ2T
P9sadBe1llUYaow7txYSUxssW+89avct35gIyrBbof5M+CBXyAOUaSWmpM2eub24
0qbqiSr/Y6Om0t6vSzR8gRk7g+1H6IE0Tt1IJCvCAMimiE8EGBECAA8FAkXopTYC
GwwFCRLMAwAACgkQEZzANiF1IfZQYgCgiZHCv4xb+sTHCn/otc1Ovvi/OgMAnRXY
bbsLFWOfmzAnNIGvFRWy+YHi
=MMNL
Version: GnuPG v1.4.5 (GNU/Linux)

mQINBEvSKUIBEADLGnUj24ZVKW7liFN/JA5CgtzlNnKs7sBg7fVbNWryiE3URbn1
JXvrdwHtkKyY96/ifZ1Ld3lE2gOF61bGZ2CWwJNee76Sp9Z+isP8RQXbG5jwj/4B
M9HK7phktqFVJ8VbY2jfTjcfxRvGM8YBwXF8hx0CDZURAjvf1xRSQJ7iAo58qcHn
XtxOAvQmAbR9z6Q/h/D+Y/PhoIJp1OV4VNHCbCs9M7HUVBpgC53PDcTUQuwcgeY6
pQgo9eT1eLNSZVrJ5Bctivl1UcD6P6CIGkkeT2gNhqindRPngUXGXW7Qzoefe+fV
QqJSm7Tq2q9oqVZ46J964waCRItRySpuW5dxZO34WM6wsw2BP2MlACbH4l3luqtp
Xo3Bvfnk+HAFH3HcMuwdaulxv7zYKXCfNoSfgrpEfo2Ex4Im/I3WdtwME/Gbnwdq
3VJzgAxLVFhczDHwNkjmIdPAlNJ9/ixRjip4dgZtW8VcBCrNoL+LhDrIfjvnLdRu
vBHy9P3sCF7FZycaHlMWP6RiLtHnEMGcbZ8QpQHi2dReU1wyr9QgguGU+jqSXYar
1yEcsdRGasppNIZ8+Qawbm/a4doT10TEtPArhSoHlwbvqTDYjtfV92lC/2iwgO6g
YgG9XrO4V8dV39Ffm7oLFfvTbg5mv4Q/E6AWo/gkjmtxkculbyAvjFtYAQARAQAB
tCFFUEVMICg2KSA8ZXBlbEBmZWRvcmFwcm9qZWN0Lm9yZz6JAjYEEwECACAFAkvS
KUICGw8GCwkIBwMCBBUCCAMEFgIDAQIeAQIXgAAKCRA7Sd8qBgi4lR/GD/wLGPv9
qO39eyb9NlrwfKdUEo1tHxKdrhNz+XYrO4yVDTBZRPSuvL2yaoeSIhQOKhNPfEgT
9mdsbsgcfmoHxmGVcn+lbheWsSvcgrXuz0gLt8TGGKGGROAoLXpuUsb1HNtKEOwP
Q4z1uQ2nOz5hLRyDOV0I2LwYV8BjGIjBKUMFEUxFTsL7XOZkrAg/WbTH2PW3hrfS
WtcRA7EYonI3B80d39ffws7SmyKbS5PmZjqOPuTvV2F0tMhKIhncBwoojWZPExft
HpKhzKVh8fdDO/3P1y1Fk3Cin8UbCO9MWMFNR27fVzCANlEPljsHA+3Ez4F7uboF
p0OOEov4Yyi4BEbgqZnthTG4ub9nyiupIZ3ckPHr3nVcDUGcL6lQD/nkmNVIeLYP
x1uHPOSlWfuojAYgzRH6LL7Idg4FHHBA0to7FW8dQXFIOyNiJFAOT2j8P5+tVdq8
wB0PDSH8yRpn4HdJ9RYquau4OkjluxOWf0uRaS//SUcCZh+1/KBEOmcvBHYRZA5J
l/nakCgxGb2paQOzqqpOcHKvlyLuzO5uybMXaipLExTGJXBlXrbbASfXa/yGYSAG
iVrGz9CE6676dMlm8F+s3XXE13QZrXmjloc6jwOljnfAkjTGXjiB7OULESed96MR
XtfLk0W5Ab9pd7tKDR6QHI7rgHXfCopRnZ2VVQ==
=V/6I
Version: GnuPG v1.4.7 (GNU/Linux)

mQGiBEeD8koRBACC1VBRsUwGr9gxFFRho9kZpdRUjBJoPhkeOTvp9LzkdAQMFngr
BFi6N0ov1kCX7LLwBmDG+JPR7N+XcH9YR1coSHpLVg+JNy2kFDd4zAyWxJafjZ3a
9zFg9Yx+0va1BJ2t4zVcmKS4aOfbgQ5KwIOWUujalQW5Y+Fw39Gn86qjbwCg5dIo
tkM0l19h2sx50D027pV5aPsD/2c9pfcFTbMhB0CcKS836GH1qY+NCAdUwPs646ee
Ex/k9Uy4qMwhl3HuCGGGa+N6Plyon7V0TzZuRGp/1742dE8IO+I/KLy2L1d1Fxrn
XOTBZd8qe6nBwh12OMcKrsPBVBxn+iSkaG3ULsgOtx+HHLfa1/p22L5+GzGdxizr
peBuA/90cCp+lYcEwdYaRoFVR501yDOTmmzBc1DrsyWP79QMEGzMqa393G0VnqXt
L4pGmunq66Agw2EhPcIt3pDYiCmEt/obdVtSJH6BtmSDB/zYhbE8u3vLP3jfFDa9
KXxgtYj0NvuUVoRmxSKm8jtfmj1L7zoKNz3jl+Ba3L0WxIv4+bRBUG9zdGdyZVNR
TCBSUE0gQnVpbGRpbmcgUHJvamVjdCA8cGdzcWxycG1zLWhhY2tlcnNAcGdmb3Vu
ZHJ5Lm9yZz6IYAQTEQIAIAUCR4PySgIbIwYLCQgHAwIEFQIIAwQWAgMBAh4BAheA
AAoJEB8W0uFELfD4jnkAoMqd6ZwwsgYHZ3hP9vt+DJt1uDW7AKDbRwP8ESKFhwdJ
8m91RPBeJW/tMLkCDQRHg/JKEAgA64+ZXgcERPYfZYo4p+yMTJAAa9aqnE3U4Ni6
ZMB57GPuEy8NfbNya+HiftO8hoozmJdcI6XFyRBCDUVCdZ8SE+PJdOx2FFqZVIu6
dKnr8ykhgLpNNEFDG3boK9UfLj/5lYQ3Y550Iym1QKOgyrJYeAp6sZ+Nx2PavsP3
nMFCSD67BqAbcLCVQN7a2dAUXfEbfXJjPHXTbo1/kxtzE+KCRTLdXEbSEe3nHO04
K/EgTBjeBUOxnciH5RylJ2oGy/v4xr9ed7R1jJtshsDKMdWApwoLlCBJ63jg/4T/
z/OtXmu4AvmWaJxaTl7fPf2GqSqqb6jLCrQAH7AIhXr9V0zPZwADBQgAlpptNQHl
u7euIdIujFwwcxyQGfee6BG+3zaNSEHMVQMuc6bxuvYmgM9r7aki/b0YMfjJBk8v
OJ3Eh1vDH/woJi2iJ13vQ21ot+1JP3fMd6NPR8/qEeDnmVXu7QAtlkmSKI9Rdnjz
FFSUJrQPHnKsH4V4uvAM+njwYD+VFiwlBPTKNeL8cdBb4tPN2cdVJzoAp57wkZAN
VA2tKxNsTJKBi8wukaLWX8+yPHiWCNWItvyB4WCEp/rZKG4A868NM5sZQMAabpLd
l4fTiGu68OYgK9qUPZvhEAL2C1jPDVHPkLm+ZsD+90Pe66w9vB00cxXuHLzm8Pad
GaCXCY8h3xi6VIhJBBgRAgAJBQJHg/JKAhsMAAoJEB8W0uFELfD4K4cAoJ4yug8y
1U0cZEiF5W25HDzMTtaDAKCaM1m3Cbd+AZ0NGWNg/VvIX9MsPA==
=au6K

Version: GnuPG v2.0.14 (GNU/Linux)

mQGiBEZ6qawRBAC2gDuA1sZioGh1VP/U0l+9RmzOdkWBGB3NfWqezAwt1Up+cP5o
h+UNkghOKbJVQ/zLyY/edYOppQ78yxT1X/J1RHNhs5bjqzWlQxMbT5/tt1N4PExu
gvO38RGFTV0DqIy3lQw5YIwp2le+G8MktYh2NKI4lG0AJoXZicNlI7+mEwCgmfw+
CnsB/kb/xUD1dq6Mo3dYXVcEAKSFfqt+6jvJNxcIYfpQqjEslQsQmPKpXzK9CPyV
UCjUEOirbhPxV86u3Ge/yuy5USMvTTs+ztImabbH6UHBEP+tEw3LiuPUpfh+nEna
3Hz+U81PvUwGEwUMzCr+OemBXqGW7jl66NqKqm8YM3Pkvc4NlS/7slky9A/s6i8S
hToWA/9kP55aSbIXte5TbC88lx6YuLx7qW541ni38DmJfPN5hHywLGnM82MMQMbk
hg1v49+7TTNv44LJpGT7t8gsW9F4Z4rWoChhsldypeeqbDOIv4kFiXt/8122Ud9J
nE67CR9XUuS5Jp+gP6xxNr9/vbvqsOGMJAQkVgkBPVuKYv25gLQ3U2VyZ2lvIFJ1
YmlvIChGcmFtZU9TIERldmVsb3BlcnMpIDxydWJpb2pyQGZyYW1lb3Mub3JnPohr
BBMRAgArAhsDBQkGE0x0BgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAUCTBs76AIZ
AQAKCRCOw9dP80W+dFhjAJ0dKy761iPcG+ALwEAuAgxDpUVBzgCdFxGCAZ7ELYvf
3uFc0Ou2ihDzvyy0IFNlcmdpbyBSdWJpbyA8c2VyZ2lvQHJ1YmlvLm5hbWU+iGYE
ExECACYCGwMGCwkIBwMCBBUCCAMEFgIDAQIeAQIXgAUJBhNMdAUCTBs7XgAKCRCO
w9dP80W+dDdtAJ9NYoW1ChfMyES7nQUlesEQ4aWXjQCeIoGxoOuIGyg6+AKr/2Wr
6fE1zt2IaQQTEQIAKQIbAwYLCQgHAwIEFQIIAwQWAgMBAh4BAheAAhkBBQJIHsGo
BQkCuHFEAAoJEI7D10/zRb50KjgAnRTzzNIODKqrHnrHaUG8dWDCwmYjAJ48Hbcn
ZC6E8LGTeM8vPN0mMI9ijLkCDQRGeqm2EAgAh720kjA9bNDms+6agb6CirD9RkmZ
3G+OHd5iia3KbaUiBtC3PECg4UE8N54JuBNKdjgJQfdYSg2J0EZHyhZHdAVWjykE
tj/IKZKnAfUqKh44uT9OUPW8PChPo/gioLn+DexSAW7n19h7VIa1P3shYqYR/gz8
zgfrXkFFpkpKnOLsXuF20JEEBIBdwrfYRJIBrUTYrfS/2GKLJjyutENkb9uI3JgQ
LfR6DckTaar4eeArjgvOxZRHiU0vRezetlbG8ZM9mSYrcMM3Xa5vLpFlDj6vYzat
RWEuZUfLgXWUVoVyFiNVXhpff/w7/bAb3WpXqjZd6sK8CCJJPNtnbLE7CwADBQf9
EQjT9iiEZis35V9HqeLsxXVjPOGNuLiwjIpacI7CM3aGV1q7NXiCE4oWS/PvpHmu
W+XdXMPH4Bt2VmjZSarlAipTeNnOuiEXipUFIjAlNn1xNVRRd7T35zIvXLtmNtUe
nN1/mqZljKPbCbW1AgktH417t/vJfTnRWr9IgS3Am+o4q200i+1FjrQ/UI3s9+vg
5B+KASFP6HspNttl0kwzQ6SFIHAebd4DKHOj6ShxXPNl18W4R8qPqayrAFqdkgMJ
Jn8j2E8rmGYnssSfjck2kLtvNdTEAMjFnhg+oUapUzJAVeterudiWZFNrtn9ewnf
8SUiiYJlxb+nz545zo0gQIhJBBgRAgAJBQJGeqm2AhsMAAoJEI7D10/zRb50PJEA
mwTA+Sp3wvzwDr8sk7W7U4bBfw26AKCVoYw3mfTime+j3mFk1yk1yxjE2Q==
=iyOs

Version: GnuPG v1.2.6 (GNU/Linux)

mQGiBEWfBuERBACrwDH+6QvpyaOgzhXiemsIX+q4HlhX/HDmrmZOUd7i9VmZNogP
6LRRiTygn2+UphaGV3NDA36ZB/1JRpgvgpzbpZNeAoFvsljIbxGIwkH2JgRF6oNo
eGB3QYzDQJvYVIejk79M0ed3oor4w8OiNVcdxLyVIthFrjrrCqwRP3bLZwCgtY9t
Ezf5WL63Ue45vdht7A2GH+0D/iNAnWKsU7FUMFZrcwMaMbyP7YG8z0+zXUOgtgyP
tbgJG5yikNT3vJypb42gbKfcriUUDC5AeiRmkR8QPvYuOm34rM90+wx2LGqXWnHM
IyLAyl8TS3MQmePem8bfTGTNYxtt3Q7iadez2WYTLBSlmM6hbxZfdwm1hhyM0AJU
YyFUA/9kHH+CUBxKb1UgG7TSp53Po/5p/Yyuty+RJ7zIGv6SiN/JK4/ntWfm5WS5
ZprSdE5ODoFQ/Gs3/VB/eolg2fBW1DcftH6lKHT3GKEOaicGX+T9eOMerZZedm5U
vDA9mFvWnOdOxK8LuRgVqip4jCnWICchpatmdP0whJQHQ6MGLLRMQ2VudE9TLTUg
QmV0YSBLZXkgKENlbnRPUyA1IEJldGEgU2lnbmluZyBLZXkpIDxjZW50b3MtNS1i
ZXRhLWtleUBjZW50b3Mub3JnPohkBBMRAgAkBQJFnwbhAhsDBQkSzAMABgsJCAcD
AgMVAgMDFgIBAh4BAheAAAoJEM/aaIEJLXsrWDkAoKcqa+AAdAWvp5qlJkGQiRy8
aNFDAJ4qRfIxMiLinmjbqcuygWMp61wY5ohMBBMRAgAMBQJFnwhtBYMSzAF0AAoJ
EDjCFhY5bKCkG/wAn14LDlJqjZv1Wz0WNfhr80+qJrf6AKCaIZExwo4ApQpESk/F
SApLd/pEILkBDQRFnwbrEAQAwKzjI2aTB/sS9HuQ4CHCwrj4vr0HxMMwQikYBIvy
MYTtek04KDTKoJL5g3411DsfDW9VRGJdFCHvldgam/5UVfO6nywLkdwAA5TQA5dv
8YE8jTtwdy5Y1QKFc8LaIBZK0+ZbhEvdNfv67egvfcxZc5PvpBZ3C03n+iQ3wPcg
PhcAAwUD/iYkq4LG/je43Qa5rTz5kF5rIiX7Bk5vXT7XSFOFKwHy8V+PGEoVM1W8
+EHIlmTycwIlsVp3by6qCDkMYu4V6VukxZNzJyeoMICiYIXUPh6NKHRoqaYlu6ZO
eFN1TQNXmodPk+iNtdbcby/zAklNqoO/dWSwd8NAo8s6WAHq3VPpiE8EGBECAA8F
AkWfBusCGwwFCRLMAwAACgkQz9pogQkteysXkACgoraCU0EBC+W8TuxrsePO20ma
D0IAoLRRQLTEXL0p3K0WE+LfyTr9EVG5
=mH0S

Version: GnuPG v1.4.5 (GNU/Linux)

mQGiBEm+/6QRBAC5mbtqOFSQ0FkTLIMdIoqxtraIeUqwbPp3IBYQ/u/EREjyEf1D
qFyBEXII0dD8JDT85vRZ81jhB7nFWa0VbUfY0xfghkbnokiNBVNpiQcvszw3UYDF
aLAaOC8Z98vmlsQaBBTQG6704ZXLr7FJyG3GP5WE6egXIQQbrMcdmCoRBwCg/dwC
HLWjuemoDc5SX7hKHbB4zZ8D/jP+oMbqz+bDn8OZ2UuaGdxr+mHW8tzTdPjnEU8e
hUt1ws8eBqn/gMfKvUBa8xFSILe8Ty99u+VjFbcRsdf0H6dRre9AdDVUz5oxzoPw
gamA8mhPQvFh3wt9smtRUh5IoM2LiM1s5pGMLuYuvSnVUPArEnSfW6K5I6v7OarU
3WfrBACDEGGcaWKjfdkRtmKIQrzu6AnldVC1ISLVAoqxHnKNFTk1BgO0PSZDpfJI
x8fMCnGlusoL6F5+LYEk4K4B0zvlj1ur3JocjxpuBLccl94JTo/+I9ZbS8ptUqLw
LBUkgIQJzzIH4G5NZsQ3FpzSWGRFVa7etqTv9BfUMUmJxhEoobQ/ZWxyZXBvLm9y
ZyAoUlBNIFNpZ25pbmcgS2V5IGZvciBlbHJlcG8ub3JnKSA8c2VjdXJlQGVscmVw
by5vcmc+iGAEExECACAFAkm+/6QCGwMGCwkIBwMCBBUCCAMEFgIDAQIeAQIXgAAK
CRAwm8MFuq2uUlgWAKCGWOpyodbzxS7Xy/0X9m9qVnHq+ACfUHrQzYAtFRpT07Sg
giosE+mvAKu5Ag0ESb7/pxAIALgT0q0HhwugE717a7N+gAtCbFu8pCXOZcrAnJpG
cMA9VWmsODZStPTxXYM2ggCMSzUnNis8pPZOPIP5C+t2IYtVjLshM4C9UiY7u5ET
jErWCxWmF+2QLO50K56E4qxj0wufZt9P+Ih0USUM5L2oyrQG51uj/2v3Qq3igc8Z
NTtmEOfis3losusQbAfZtTBmNQ0570kkhMxiyavgAUxLenXHYrkDJFuL7XdBCmna
kykTn2dzU81rIDZ+QPxII4V/eZ5xGiRY/EDUIAysEV2m0NNZgWi/twUnZICm7zYp
VRviJrBnFTvNEPMhiGRnJgQp/Krv4WIHQ67N8lQg3q5RJX8AAwUH/0UBjBgbsuWR
dB+ZYWjKPBy+bJY/6HefPUuLrt3QDNINMW8kY7VzWRMWyGc4IlPJDW0nwOn/vT5H
Dgc3YmA3tm7cKj5wpFijzff61Db8eq+CUKGscKxDBGzHq6oirM5U7DQLmipCs5Eb
efwHIjE3aOUSnoQmniEnBWI2hm/rftmY9oJSi8xgns4wAokDPiMcucADtbV3fznx
ppuowtBi8bcGB1vJZjTySQcSKWv+IVp5ej06uZ9501BEm6HxUZkuAGPecP65kcQu
5bg7B7LQeI5AWyujqvfuWgAF34xhl9QU/sDWxM3wUog+bw7y8pyWCqnJhp70yx8o
SqzhFygT62eISQQYEQIACQUCSb7/pwIbDAAKCRAwm8MFuq2uUq8PAKC1+E2pSwiS
oHXkKYPYDwApsP1mVACfRe1YnggLYQtG9LMeweVQQC77rK8=
=qyRr
Version: GnuPG v1.2.6 (GNU/Linux)

mQGiBEIu6hwRBACOz2JFa1nW+seAKlVGOu0ykhdFVNI9E4/Abp2+8nsJIZyUwLAp
ei76rPD8WdptgIjtYOCsqz1TbP+eqeEG0LLihOdFRLUuAjQX4X7LLf5Qm+nvUB73
uLbSf9Ptps2CMUEtu7+0wVoTbuC19HXUhUr5sRdCnJbPJBH6aAHG7Pl9ZwCguN9o
V7IKTnIQiZg0nxSjZ4V9e6UD/R7KoMwH3NPQQF7T7rJaBjSZcVHUPhAcNPNn+ms/
Tw9mzHZ0mnQnOzSEW0ZUj9TkLN52VQ3WmGZKAv9yeVr0/230YIgmtH863lSystmk
LNO9brK0+3vKg5GRpV0/MSWSmf39WPAS1hXNXIFfYp1eGHUfed4FVNxrMTWHQozr
8JosA/wP+zGfM51bSAazLUqP/MEm7F9OFkuD7Sw97w55FyYlrPp1FQWrWczoiKHr
wS5NRCQbCGEEM/+j9id6CukxPLXxwMYCfeg5K0HxMaQT6hxbwjOzAzN3PBFytNel
09qdrdoSDa35twT0SAt+rzM+zvRI8ycizFG3lIih4UItWWve2bQ6S2FyYW5iaXIg
U2luZ2ggKGh0dHA6Ly93d3cua2FyYW4ub3JnLykgPGtic2luZ2hAa2FyYW4ub3Jn
PoheBBMRAgAeBQJCLuocAhsDBgsJCAcDAgMVAgMDFgIBAh4BAheAAAoJEDANvZ4+
E89b/P4AnjufrDCS+TAEL0KpkYDURePbDCHBAJ4+0iI1Td4YrcnLwmQ1+XDCJ3Zr
a7kBDQRCLuocEAQAjAl48FM9eGtP6M9FgswlSPAuCcJct6wOHmd/qZ923HckJPAD
zIFRMlM6H8P0bKoaIluv7agZM7Gsf8NeTg3NEeMKqnibIAyvjYeSkceRIwvBCQ3A
YwWk+B2zLUAFMxnE31oA10zjCKUo7Dc6XDUxSY/qdLymZzyG/Ndav+vMOVsAAwUD
/RCFDuW/GSM/s3DO7XxrOBRTGQmf9v9tCYdZZD615+s8ghaa5oZTvp1cbTTWiSq8
ybncfjVHz9HezDgQjJsFZtrYd4w2JD+7K0+8sZ+BUGo1dDSv4UgN8ACtaGJnShiq
s8pQWRZFqFa3waay8oUSTKHiTHdpxLi3x4HhK/8MTsxniEkEGBECAAkFAkIu6hwC
GwwACgkQMA29nj4Tz1tHSgCcDgKL4swEu7ShvI8nZt2JLmTKB5QAn0qZi2zbexbi
DX+bbalHM+xVnXZN
=rZT6
Version: GnuPG v1.2.6 (GNU/Linux)

mQINBEmkAzABEAC2/c7bP1lHQ3XScxbIk0LQWe1YOiibQBRLwf8Si5PktgtuPibT
kKpZjw8p4D+fM7jD1WUzUE0X7tXg2l/eUlMM4dw6XJAQ1AmEOtlwSg7rrMtTvM0A
BEtI7Km6fC6sU6RtBMdcqD1cH/6dbsfh8muznVA7UlX+PRBHVzdWzj6y8h84dBjo
gzcbYu9Hezqgj/lLzicqsSZPz9UdXiRTRAIhp8V30BD8uRaaa0KDDnD6IzJv3D9P
xQWbFM4Z12GN9LyeZqmD7bpKzZmXG/3drvfXVisXaXp3M07t3NlBa3Dt8NFIKZ0D
FRXBz5bvzxRVmdH6DtkDWXDPOt+Wdm1rZrCOrySFpBZQRpHw12eo1M1lirANIov7
Z+V1Qh/aBxj5EUu32u9ZpjAPPNtQF6F/KjaoHHHmEQAuj4DLex4LY646Hv1rcv2i
QFuCdvLKQGSiFBrfZH0j/IX3/0JXQlZzb3MuMFPxLXGAoAV9UP/Sw/WTmAuTzFVm
G13UYFeMwrToOiqcX2VcK0aC1FCcTP2z4JW3PsWvU8rUDRUYfoXovc7eg4Vn5wHt
0NBYsNhYiAAf320AUIHzQZYi38JgVwuJfFu43tJZE4Vig++RQq6tsEx9Ftz3EwRR
fJ9z9mEvEiieZm+vbOvMvIuimFVPSCmLH+bI649K8eZlVRWsx3EXCVb0nQARAQAB
tDBSZWQgSGF0LCBJbmMuIChiZXRhIGtleSAyKSA8c2VjdXJpdHlAcmVkaGF0LmNv
bT6JAjYEEwECACAFAkpSM+cCGwMGCwkIBwMCBBUCCAMEFgIDAQIeAQIXgAAKCRCT
ioDK8hVB6/9tEAC0+KmzeKceXQ/GTUoU6jy9vtkFCFrmv+c7ol4XpdTt0QhqBOwy
6m2mKWwmm8KfYfy0cADQ4y/EcoXl7FtFBwYmkCuEQGXhTDn9DvVjhooIq59LEMBQ
OW879RwwzRIZ8ebbjMUjDPF5MfPQqP2LBu9N4KvXlZp4voykwuuaJ+cbsKZR6pZ6
0RQKPHKP+NgUFC0fff7XY9cuOZZWFAeKRhLN2K7bnRHKxp+kELWb6R9ZfrYwZjWc
MIPbTd1khE53L4NTfpWfAnJRtkPSDOKEGVlVLtLq4HEAxQt07kbslqISRWyXER3u
QOJj64D1ZiIMz6t6uZ424VE4ry9rBR0Jz55cMMx5O/ni9x3xzFUgH8Su2yM0r3jE
Rf24+tbOaPf7tebyx4OKe+JW95hNVstWUDyGbs6K9qGfI/pICuO1nMMFTo6GqzQ6
DwLZvJ9QdXo7ujEtySZnfu42aycaQ9ZLC2DOCQCUBY350Hx6FLW3O546TAvpTfk0
B6x+DV7mJQH7MGmRXQsE7TLBJKjq28Cn4tVp04PmybQyTxZdGA/8zY6pPl6xyVMH
V68hSBKEVT/rlouOHuxfdmZva1DhVvUC6Xj7+iTMTVJUAq/4Uyn31P1OJmA2a0PT
CAqWkbJSgKFccsjPoTbLyxhuMSNkEZFHvlZrSK9vnPzmfiRH0Orx3wYpMQ==
=21pb
The following public key can be used to verify RPM packages built and
signed by Red Hat, Inc. for this beta using `rpm -K' using the GNU GPG
package.  Questions about this key should be sent to security@redhat.com.


Version: GnuPG v1.0.6 (GNU/Linux)
Comment: For info see http://www.gnupg.org

mQGiBDySTqsRBACzc7xuCIp10oj5B2PAV4XzDeVxprv/WTMreSNSK+iC0bEz0IBp
Vnn++qtyiXfH+bGIE9jqZgIEnpttWhUOaU5LhcLFzy+m8NWfngIFP9QfGmGAe9Gd
LFeAdhj4RmSG/vgr7vDd83Hz22dv403Ar/sliWO4vDOrMmZBG57WGYTWtwCgkMsi
UUQuJ6slbzKn82w+bYxOlL0EAIylWJGaTkKOTL5DqVR3ik9aT0Dt3FNVYiuhcKBe
II4E3KOIVA9kO8in1IZjx2gs6K2UV+GsoAVANdfKL7l9O+k+J8OxhE74oycvYJxW
QzCgXMZkNcvW5wyXwEMcr6TVd/5BGztcMw8oT3/l2MtAEG/vn1XaWToRSO1XDMDz
+AjUA/4m0mTkN8S4wjzJG8lqN7+quW3UOaiCe8J3SFrrrhE0XbY9cTJI/9nuXHU1
VjqOSmXQYH2Db7UOroFTBiWhlAedA4O4yuK52AJnvSsHbnJSEmn9rpo5z1Q8F+qI
mDlzriJdrIrVLeDiUeTlpH3kpG38D7007GhXBV72k1gpMoMcpbQ3UmVkIEhhdCwg
SW5jLiAoQmV0YSBUZXN0IFNvZnR3YXJlKSA8cmF3aGlkZUByZWRoYXQuY29tPohX
BBMRAgAXBQI8l5p/BQsHCgMEAxUDAgMWAgECF4AACgkQ/TcmiYl9oHqdeQCfZjw4
F9sir3XfRAjVe9kYNcQ8hnIAn0WgyT7H5RriWYTOCfauOmd+cAW4iEYEEBECAAYF
AjyXmqQACgkQIZGAzdtCpg5nDQCfepuRUyuVJvhuQkPWySETYvRw+WoAnjAWhx6q
0npMx4OE1JGFi8ymKXktuQENBDySTq4QBADKL/mK7S8E3synxISlu7R6fUvu07Oc
RoX96n0Di6T+BS99hC44XzHjMDhUX2ZzVvYS88EZXoUDDkB/8g7SwZrOJ/QE1zrI
JmSVciNhSYWwqeT40Evs88ajZUfDiNbS/cSC6oui98iS4vxd7sE7IPY+FSx9vuAR
xOa9vBnJY/dx0wADBQQAosm+Iltt2uigC6LJzxNOoIdB5r0GqTC1o5sHCeNqXJhU
ExAG8m74uzMlYVLOpGZi4y4NwwAWvCWC0MWWnnu+LGFy1wKiJKRjhv5F+WkFutY5
WHV5L44vp9jSIlBCRG+84jheTh8xqhndM9wOfPwWdYYu1vxrB8Tn6kA17PcYfHSI
RgQYEQIABgUCPJJergAKCRD9NyaJiX2geiCPAJ4nEM4NtI9Uj8lONDk6FU86PmoL
yACfb68fBd2pWEzLKsOk9imIobHHpzE=
=gpIn
The following public key can be used to verify RPM packages built and
signed by Red Hat, Inc.  This key is used for packages in Red Hat
products shipped prior to November 2006, and for all updates to those
products.

Questions about this key should be sent to security@redhat.com.

Version: GnuPG v1.0.0 (GNU/Linux)
Comment: For info see http://www.gnupg.org

mQGiBDfqVDgRBADBKr3Bl6PO8BQ0H8sJoD6p9U7Yyl7pjtZqioviPwXP+DCWd4u8
HQzcxAZ57m8ssA1LK1Fx93coJhDzM130+p5BG9mYSWShLabR3N1KXdXQYYcowTOM
GxdwYRGr1Spw8QydLhjVfU1VSl4xt6bupPbWJbyjkg5Z3P7BlUOUJmrx3wCgobNV
EDGaWYJcch5z5B1of/41G8kEAKii6q7Gu/vhXXnLS6m15oNnPVybyngiw/23dKjS
ZVG7rKANEK2mxg1VB+vc/uUc4k49UxJJfCZg1gu1sPFV3GSa+Y/7jsiLktQvCiLP
lncQt1dV+ENmHR5BdIDPWDzKBVbgWnSDnqQ6KrZ7T6AlZ74VMpjGxxkWU6vV2xsW
XCLPA/9P/vtImA8CZN3jxGgtK5GGtDNJ/cMhhuv5tnfwFg4b/VGo2Jr8mhLUqoIb
E6zeGAmZbUpdckDco8D5fiFmqTf5+++pCEpJLJkkzel/32N2w4qzPrcRMCiBURES
PjCLd4Y5rPoU8E4kOHc/4BuHN903tiCsCPloCrWsQZ7UdxfQ5LQiUmVkIEhhdCwg
SW5jIDxzZWN1cml0eUByZWRoYXQuY29tPohVBBMRAgAVBQI36lQ4AwsKAwMVAwID
FgIBAheAAAoJECGRgM3bQqYOsBQAnRVtg7B25Hm11PHcpa8FpeddKiq2AJ9aO8sB
XmLDmPOEFI75mpTrKYHF6rkCDQQ36lRyEAgAokgI2xJ+3bZsk8jRA8ORIX8DH05U
lMH27qFYzLbT6npXwXYIOtVn0K2/iMDj+oEB1Aa2au4OnddYaLWp06v3d+XyS0t+
5ab2ZfIQzdh7wCwxqRkzR+/H5TLYbMG+hvtTdylfqIX0WEfoOXMtWEGSVwyUsnM3
Jy3LOi48rQQSCKtCAUdV20FoIGWhwnb/gHU1BnmES6UdQujFBE6EANqPhp0coYoI
hHJ2oIO8ujQItvvNaU88j/s/izQv5e7MXOgVSjKe/WX3s2JtB/tW7utpy12wh1J+
JsFdbLV/t8CozUTpJgx5mVA3RKlxjTA+On+1IEUWioB+iVfT7Ov/0kcAzwADBQf9
E4SKCWRand8K0XloMYgmipxMhJNnWDMLkokvbMNTUoNpSfRoQJ9EheXDxwMpTPwK
ti/PYrrL2J11P2ed0x7zm8v3gLrY0cue1iSba+8glY+p31ZPOr5ogaJw7ZARgoS8
BwjyRymXQp+8Dete0TELKOL2/itDOPGHW07SsVWOR6cmX4VlRRcWB5KejaNvdrE5
4XFtOd04NMgWI63uqZc4zkRa+kwEZtmbz3tHSdRCCE+Y7YVP6IUf/w6YPQFQriWY
FiA6fD10eB+BlIUqIw80VgjsBKmCwvKkn4jg8kibXgj4/TzQSx77uYokw1EqQ2wk
OZoaEtcubsNMquuLCMWijYhGBBgRAgAGBQI36lRyAAoJECGRgM3bQqYOhyYAnj7h
VDY/FJAGqmtZpwVp9IlitW5tAJ4xQApr/jNFZCTksnI+4O1765F7tA==
=3AHZ
The following public key can be used to verify RPM packages built and
signed by Red Hat, Inc.  This key is used for packages in Red Hat
products shipped after November 2006, and for all updates to those
products.

Questions about this key should be sent to security@redhat.com.

Version: GnuPG v1.2.6 (GNU/Linux)

mQGiBEV2EyQRBAD4/SR69qoLzK4HIa6g9iS+baiX0o3NjkLftFHg/xy+IMOMg//i
4c5bUpLKDTMH3+yT0G8qpul/RALUFOESKFkZm3/SlkJKuroXcB8U6s2dh5XX9DDB
ISqRwL7M5qB8rfDPKHN+k/XwJ9CNpHMdNxnnc2WhnnmHNp6NrD/bUEH4vwCglMa0
rFRXPaN7407DARGHvW/jugsEANFaeZsFwos/sajL1XQRfHZUTnvDjJgz31IFY+OL
DlOVAOtV/NaECMwIJsMIhoisW4Luwp4m75Qh3ogq3bwqSWNLsfJ9WFnNqXOgamyD
h/F4q492z6FpyIb1JZLABBSH7LEQjHlR/s/Ct5JEWc5MyfzdjBi6J9qCh3y/IYL0
EbfRA/4yoJ/fH9uthDLZsZRWmnGJvb+VpRvcVs8IQ4aIAcOMbWu2Sp3U9pm6cxZF
N7tShmAwiiGj9UXVtlhpj3lnqulLMD9VqXGF0YgDOaQ7CP/99OEEhUjBj/8o8udF
gxc1i2WJjc7/sr8IMbDv/SNToi0bnZUxXa/BUjj92uaQ6/LupbQxUmVkIEhhdCwg
SW5jLiAocmVsZWFzZSBrZXkpIDxzZWN1cml0eUByZWRoYXQuY29tPohfBBMRAgAf
BQJFdhMkAhsDBgsJCAcDAgQVAggDAxYCAQIeAQIXgAAKCRBTJoEBNwFxhogXAKCD
TuYeyQrkYXjg9JmOdTZvsIVfZgCcCWKJXtfbC5dbv0piTHI/cdwVzJo=
=mhzo
Version: GnuPG v1.2.6 (GNU/Linux)

mQGiBEYk7/IRBACdWFJInc51/+0sqvadIvf0E+Vhv4aIqB76jWtIGqXnTeG6hEl/
9tJoLszBh4g/KBFVF3E4VxTHXKO/L7GZRa8JzoMtvV8XiP6BaYq6ykx6H7alKvoP
qzk7xBbvNbqsXJCO7keo+g7iIDdfAxvsSJYbhQBxDn5W4Hw7SnHcMmTDOQCg7vOj
UzaZG32yYMBZLjOAB/QzXgsD/1JRDnQ8cL6d17B1ie57ZuVOI3ziQJSmj0zbC0IX
OsxlcFjwydLk3TA88iCr0SO2mfXCsGTeDGFbrl2IRCoH91l3Ew49HI4OYtl+OPSt
pIYdFLSQ+RUPs9CFYwF9Ogjrwmi6jVptKq/+v0WgnCrbfz3DYxCWt/VB1PYDj5y6
Mv//BACKa2mUuQoukDvzqiwZXV/Z52MeDOzPbOFo6qhx+54nav9Inz1yziEjYrP/
ZrNJ4BT6fBgin/a6UmD5FqMtkrrhOCpHFQK2H+XYZ0vVJGZI7h74/fY8U2n+1Mle
xQ/ejWojF+H5nFUAwKHaNVNofKcw8c8msgGn2jsvrAISTSHshrQwUmVkIEhhdCwg
SW5jLiAoUkhYIGtleSkgPHJoeC1zdXBwb3J0QHJlZGhhdC5jb20+iF8EExECAB8F
AkYk7/ICGwMGCwkIBwMCBBUCCAMDFgIBAh4BAheAAAoJEDmhOhJCGT5r6FoAoLsB
+DOPmTc3P+77DnNhU460nmjQAKCI3BJ/SxqPqfp8jL6lTfVo2zxegQ==
=t0np
The following public key can be used to verify RPM packages built and
signed by Red Hat, Inc.  This key is used for packages in Red Hat
products shipped after November 2009, and for all updates to those
products.

Questions about this key should be sent to security@redhat.com.

pub  4096R/FD431D51 2009-10-22 Red Hat, Inc. (release key 2) <security@redhat.com>

Version: GnuPG v1.2.6 (GNU/Linux)

mQINBErgSTsBEACh2A4b0O9t+vzC9VrVtL1AKvUWi9OPCjkvR7Xd8DtJxeeMZ5eF
0HtzIG58qDRybwUe89FZprB1ffuUKzdE+HcL3FbNWSSOXVjZIersdXyH3NvnLLLF
0DNRB2ix3bXG9Rh/RXpFsNxDp2CEMdUvbYCzE79K1EnUTVh1L0Of023FtPSZXX0c
u7Pb5DI5lX5YeoXO6RoodrIGYJsVBQWnrWw4xNTconUfNPk0EGZtEnzvH2zyPoJh
XGF+Ncu9XwbalnYde10OCvSWAZ5zTCpoLMTvQjWpbCdWXJzCm6G+/hx9upke546H
5IjtYm4dTIVTnc3wvDiODgBKRzOl9rEOCIgOuGtDxRxcQkjrC+xvg5Vkqn7vBUyW
9pHedOU+PoF3DGOM+dqv+eNKBvh9YF9ugFAQBkcG7viZgvGEMGGUpzNgN7XnS1gj
/DPo9mZESOYnKceve2tIC87p2hqjrxOHuI7fkZYeNIcAoa83rBltFXaBDYhWAKS1
PcXS1/7JzP0ky7d0L6Xbu/If5kqWQpKwUInXtySRkuraVfuK3Bpa+X1XecWi24JY
HVtlNX025xx1ewVzGNCTlWn1skQN2OOoQTV4C8/qFpTW6DTWYurd4+fE0OJFJZQF
buhfXYwmRlVOgN5i77NTIJZJQfYFj38c/Iv5vZBPokO6mffrOTv3MHWVgQARAQAB
tDNSZWQgSGF0LCBJbmMuIChyZWxlYXNlIGtleSAyKSA8c2VjdXJpdHlAcmVkaGF0
LmNvbT6JAjYEEwECACAFAkrgSTsCGwMGCwkIBwMCBBUCCAMEFgIDAQIeAQIXgAAK
CRAZni+R/UMdUWzpD/9s5SFR/ZF3yjY5VLUFLMXIKUztNN3oc45fyLdTI3+UClKC
2tEruzYjqNHhqAEXa2sN1fMrsuKec61Ll2NfvJjkLKDvgVIh7kM7aslNYVOP6BTf
C/JJ7/ufz3UZmyViH/WDl+AYdgk3JqCIO5w5ryrC9IyBzYv2m0HqYbWfphY3uHw5
un3ndLJcu8+BGP5F+ONQEGl+DRH58Il9Jp3HwbRa7dvkPgEhfFR+1hI+Btta2C7E
0/2NKzCxZw7Lx3PBRcU92YKyaEihfy/aQKZCAuyfKiMvsmzs+4poIX7I9NQCJpyE
IGfINoZ7VxqHwRn/d5mw2MZTJjbzSf+Um9YJyA0iEEyD6qjriWQRbuxpQXmlAJbh
8okZ4gbVFv1F8MzK+4R8VvWJ0XxgtikSo72fHjwha7MAjqFnOq6eo6fEC/75g3NL
Ght5VdpGuHk0vbdENHMC8wS99e5qXGNDued3hlTavDMlEAHl34q2H9nakTGRF5Ki
JUfNh3DVRGhg8cMIti21njiRh7gyFI2OccATY7bBSr79JhuNwelHuxLrCFpY7V25
OFktl15jZJaMxuQBqYdBgSay2G0U6D1+7VsWufpzd/Abx1/c3oi9ZaJvW22kAggq
dzdA27UUYjWvx42w9menJwh/0jeQcTecIUd0d0rFcw/c1pvgMMl/Q73yzKgKYw==
=zbHE
The following public key can be used to verify RPM packages built and
signed by Red Hat, Inc.  This key is a supporting (auxiliary) key for
Red Hat products shipped after November 2006 and for all updates to
those products.

Questions about this key should be sent to security@redhat.com.

Version: GnuPG v1.2.6 (GNU/Linux)

mQGiBEVwDGkRBACwPhZIpvkjI8wV9sFTDoqyPLx1ub8Sd/w+YuI5Ovm49mvvEQVT
VLg8FgE5JlST59AbsLDyVtRa9CxIvN5syBVrWWWtHtDnnylFBcqG/A6J3bI4E9/A
UtSL5Zxbav0+utP6f3wOpxQrxc+WIDVgpurdBKAQ3dsobGBqypeX6FXZ5wCgou6C
yZpGIBqosJaDWLzNeOfb/70D/1thLkQyhW3JJ6cHCYJHNfBShvbLWBf6S231mgmu
MyMlt8Kmipc9bw+saaAkSkVsQ/ZbfjrWB7e5kbMruKLVrH+nGhamlHYUGyAPtsPg
Uj/NUSj5BmrCsOkMpn43ngTLssE9MLhSPj2nIHGFv9B+iVLvomDdwnaBRgQ1aK8z
z6MAA/406yf5yVJ/MlTWs1/68VwDhosc9BtU1V5IE0NXgZUAfBJzzfVzzKQq6zJ2
eZsMLhr96wbsW13zUZt1ing+ulwh2ee4meuJq6h/971JspFY/XBhcfq4qCNqVjsq
SZnWoGdCO6J8CxPIemD2IUHzjoyyeEj3RVydup6pcWZAmhzkKrQzUmVkIEhhdCwg
SW5jLiAoYXV4aWxpYXJ5IGtleSkgPHNlY3VyaXR5QHJlZGhhdC5jb20+iF4EExEC
AB4FAkVwDGkCGwMGCwkIBwMCAxUCAwMWAgECHgECF4AACgkQRWiciC+mWOC1rQCg
ooNLCFOzNPcvhd9Za8C801HmnsYAniCw3yzrCqtjYnxDDxlufH0FVTwX
=d/bm
Version: GnuPG v1.4.7 (GNU/Linux)

mQGiBEJny1wRBACRnbQgZ6qLmJSuGvi/EwrRL6aW610BbdpLQRL3dnwy5wI5t9T3
/JEiEJ7GTvAwfiisEHifMfk2sRlWRf2EDQFttHyrrYXfY5L6UAF2IxixK5FL7PWA
/2a7tkw1IbCbt4IGG0aZJ6/xgQejrOLi4ewniqWuXCc+tLuWBZrGpE2QfwCggZ+L
0e6KPTHMP97T4xV81e3Ba5MD/3NwOQh0pVvZlW66Em8IJnBgM+eQh7pl4xq7nVOh
dEMJwVU0wDRKkXqQVghOxALOSAMapj5mDppEDzGLZHZNSRcvGEs2iPwo9vmY+Qhp
AyEBzE4blNR8pwPtAwL0W3cBKUx7ZhqmHr2FbNGYNO/hP4tO2ochCn5CxSwAfN1B
Qs5pBACOkTZMNC7CLsSUT5P4+64t04x/STlAFczEBcJBLF1T16oItDITJmAsPxbY
iee6JRfXmZKqmDP04fRdboWMcRjfDfCciSdIeGqP7vMcO25bDZB6x6++fOcmQpyD
1Fag3ZUq2yojgXWqVrgFHs/HB3QE7UQkykNp1fjQGbKK+5mWTrQkUmVtaSBDb2xs
ZXQgPFJQTVNARmFtaWxsZUNvbGxldC5jb20+iGAEExECACAFAkZ+MYoCGwMGCwkI
BwMCBBUCCAMEFgIDAQIeAQIXgAAKCRAATm9HAPl/Vv/UAJ9EL8ioMTsz/2EPbNuQ
MP5Xx/qPLACeK5rk2hb8VFubnEsbVxnxfxatGZ25AQ0EQmfLXRAEANwGvY+mIZzj
C1L5Nm2LbSGZNTN3NMbPFoqlMfmym8XFDXbdqjAHutGYEZH/PxRI6GC8YW5YK4E0
HoBAH0b0F97JQEkKquahCakj0P5mGuH6Q8gDOfi6pHimnsSAGf+D+6ZwAn8bHnAa
o+HVmEITYi6s+Csrs+saYUcjhu9zhyBfAAMFA/9Rmfj9/URdHfD1u0RXuvFCaeOw
CYfH2/nvkx+bAcSIcbVm+tShA66ybdZ/gNnkFQKyGD9O8unSXqiELGcP8pcHTHsv
JzdD1k8DhdFNhux/WPRwbo/es6QcpIPa2JPjBCzfOTn9GXVdT4pn5tLG2gHayudK
8Sj1OI2vqGLMQzhxw4hJBBgRAgAJBQJCZ8tdAhsMAAoJEABOb0cA+X9WcSAAn11i
gC5ns/82kSprzBOU0BNwUeXZAJ0cvNmY7rvbyiJydyLsSxh/la6HKw==
=6Rbg
The following public key can be used to verify RPM packages
downloaded from  http://dag.wieers.com/apt/  using 'rpm -K'
if you have the GNU GPG package.
Questions about this key should be sent to:
Dag Wieers <dag@wieers.com>

Version: GnuPG v1.2.1 (GNU/Linux)

mQGiBD9JMT0RBAC9Q2B0AloUMTxaK73sD0cOu1MMdD8yuDagbMlDtUYA1aGeJVO6
TV02JLGr67OBY+UkYuC1c3PUwmb3+jakZd5bW1L8E2L705wS0129xQOZPz6J+alF
5rTzVkiefg8ch1yEcMayK20NdyOmhDGXQXNQS8OJFLTIC6bJs+7MZL83/wCg3cG3
3q7MWHm3IpJb+6QKpB9YH58D/2WjPDK+7YIky/JbFBT4JPgTSBy611+bLqHA6PXq
39tzY6un8KDznAMNtm+NAsr6FEG8PHe406+tbgd7tBkecz3HPX8nR5v0JtDT+gzN
8fM3kAiAzjCHUAFWVAMAZLr5TXuoq4lGTTxvZbwTjZfyjCm7gIieCu8+qnPWh6hm
30NgA/0ZyEHG6I4rOWqPks4vZuD+wlp5XL8moBXEKfEVOMh2MCNDRGnvVHu1P3eD
oHOooVMt9sWrGcgxpYuupPNL4Uf6B6smiLlH6D4tEg+qCxC17zABI5572XJTJ170
JklZJrPGtnkPrrKMamnN9MU4RjGmjh9JZPa7rKjZHyWP/z/CBrQ1RGFnIFdpZWVy
cyAoRGFnIEFwdCBSZXBvc2l0b3J5IHYxLjApIDxkYWdAd2llZXJzLmNvbT6IWQQT
EQIAGQUCP0kxPQQLBwMCAxUCAwMWAgECHgECF4AACgkQog5SFGuNeeYvDQCeKHST
hIq/WzFBXtJOnQkJGSqAoHoAnRtsJVWYmzYKHqzkRx1qAzL18Sd0iEYEEBECAAYF
Aj9JMWAACgkQoj2iXPqnmevnOACfRQaageMcESHVE1+RSuP3txPUvoEAoJAtOHon
g+3SzVNSZLn/g7/Ljfw+uQENBD9JMT8QBACj1QzRptL6hbpWl5DdQ2T+3ekEjJGt
llCwt4Mwt/yOHDhzLe8SzUNyYxTXUL4TPfFvVW9/j8WOkNGvffbs7g84k7a5h/+l
IJTTlP9V9NruDt1dlrBe+mWF6eCY55OFHjb6nOIkcJwKxRd3nGlWnLsz0ce9Hjrg
6lMrn0lPsMV6swADBQP9H42sss6mlqnJEFA97Fl3V9s+7UVJoAIA5uSVXxEOwVoh
Vq7uECQRvWzif6tzOY+vHkUxOBRvD6oIU6tlmuG3WByKyA1d0MTqMr3eWieSYf/L
n5VA9NuD7NwjFA1kLkoDwfSbsF51LppTMkUggzwgvwE46MB6yyuqAVI1kReAWw+I
RgQYEQIABgUCP0kxPwAKCRCiDlIUa4155oktAKDAzm9QYbDpk6SrQhkSFy016BjE
BACeJU1hpElFnUZCL4yKj4EuLnlo8kc=
=mqUt
Version: GnuPG v1.4.5 (GNU/Linux)

mQGiBEpXadARBACHhOfMUuT/4iDvBRmm6bEsvnMN++L79aYhEUMNlrZ2TjKPjPvG
Y0vGk+I0JhUJWutkQRZVbqgVDsNjmnELnACK+xvdryvtxh50wCI9WUl7CT5EV7BS
/jD7JxTFbXyC/Xv0ixMB9vj6U9cySyE8PxONp0HzO6LTIr1OMPgDUsP4lwCgh8De
fmY8TN2m9a0huLdNrnmKw0cD/2bkt6rJAi3+BGHWNgQ9Nb/4wQff8BKGDtL/8acp
3yH91axuD2iYCKw0ZP5akBpRGv+4e30Plmbi1f5NaEDo9Ga1c4TDPopwgiYhrVLj
56efoTfP2AiZl3iBKFPI83/YOhrVZF8UiYoAoUnOFpOg8vmtCzgvYip5UZLTgbfJ
lcWvA/9vMb8By+1pHjW98d7GkzvZqzyMtWlbO7PXCn8P7bGQYjwvyTGiRNz3q22c
2Z29qQw4r1L1L1JGsUwuOMahkczWVdD4TRHc8mhVJEUEA6AkNAZc+Ymsfr/ip0kX
nSZLE3pYVifOhBRO8EbT0WhCMScmZNpwvZU//HKL/p+n3LArUrRZU2NpZW50aWZp
YyBMaW51eCAoUlBNIHNpZ25pbmcga2V5IGZvciBTY2llbnRpZmljIExpbnV4KSA8
c2NpZW50aWZpYy1saW51eC1kZXZlbEBmbmFsLmdvdj6IYAQTEQIAIAUCSldp0AIb
AwYLCQgHAwIEFQIIAwQWAgMBAh4BAheAAAoJELC0GD8ZKn19cXIAnA5R+EbaYr4/
IL6It/UxHXlBFIajAJ9bwmNDF14uvDnFigg1PLevLTBnTIhGBBARAgAGBQJKV6lf
AAoJENpq0AiC/ReyKLQAmwVC/Ii3sAKsptwZKHw/uk1kbupCAJ0eIzSaUo1hSa1V
fP7O/dqigu6JAbkCDQRKV2nZEAgAzAcaC7unRNdrIwAGGKqOIvI8WNwpftHY50Y5
zPSl7vtWVkp3N+2fynJR+tW4G/2xDChBbPzPz/TavRyBc21LKzAlym8qIGEE02cZ
U/YJAYnbAkNNiGMOAnAIjBw1KUcQamAxdk0glE7MP1JiXY1MO4tTW38UEcvQbSvg
Mh/eECqFOwiQXJmkPpZhPUwnwmZRCV4vlCZQM3CMExZ9pDV/V+kuhefw2WeheXyh
g4DC88gcrv2mO0I3sVmpxn3JLMayiMlQbOSYLQuNVKN/EFDwuAbS9Ane7vm6wF9X
NswMX0I/vO1IVvSN1fi5ZM71QzeYUGKBQv97kLO20hbRWZ1V+wADBggAys+jhlYH
mtFZQxV4an1ucqnVauKnstj0zF88Hiy7yivT3W5h3Zd067uOfcBQCJUlt7y8sYD2
q9htm5Rrxx+J29bl0zxwrEatnv0gLzprSa7Ei3wR6IrvBM3Ic0mGSzlsSxlzaFtt
Pwak5C47vX9+PwKEKXFdM1gVzHTuD6PXEYxA4YMlQGeGVA68FvTHxMHpf8POQWTV
QtjoI0flvFT7d4ozqUJdjJZxJDFQ7GO2YdIfF3sUdfn5kFxK0SUzqrmCYXeheniS
LKC4mpAR0PetWJ7r1gY5khHb2eHW1vdEBYUXlHjB+jLaOBns05MHMZYd4CHe8q/Q
gzMeVlh8YLSdZYhJBBgRAgAJBQJKV2nZAhsMAAoJELC0GD8ZKn19iU8AniUIFu32
VeRJ+VKL2vBQMVbFVZOMAJ434Bi99fN2CSh7T62oxtQvhw70fw==
=eL9H
Version: GnuPG v1.4.5 (GNU/Linux)

mQGiBE1e+1MRBAD8j+KyOIpGNRN39gNy2E/1HG4ZoLFuxIOxI5/1FEuZB/GjYF5m
DvJerZukd0QCqCs72J6J+uWnfD/52t2XWTw4IHPpCWeyr9TWex3uOYmrYzY+0l0l
qsCsrhT0XGkAE0+/20oEP2+t/d+1q0yRcYZRwWK/ME2rUUX0jOa/B3Bc6wCg3blw
XdZNrv1wVNd1PCOUI79k0V0D+wfbybos8Cmdv2f8dD746fSR/hmp4SzpBDmPRRQu
0gtJAKI6ycTdotGq5zHfZj76kDQBudeIgdbWtqfckP2lK47i8lIENAyC4MK8dxh9
Ts+b1LqXlbcPyixzImf4qoT5DT1lSEUPwoMRX8W/29GAcvnZpOwQ8g7DNmRBpFFY
8U2GBADz6uEeP3YwJAuL7pi77AalxR0WQAADMR59pGltQdXaZvANXoioU0W519Pb
nl3gKWDiTuwUDrwaSPoBbNLyX4s0AE7/0HSG02/eRjLB8toQpAH9xkK/u2WPe/do
erZg5yg1qhoCbEM7kJ2I/GBl6VbPedt2ORdsC4ZTWTnZJh6tYLQhQW5keSBUaG9t
cHNvbiA8YW5keUB3ZWJ0YXRpYy5jb20+iGAEExECACAFAk1e+1MCGwMGCwkIBwMC
BBUCCAMEFgIDAQIeAQIXgAAKCRC3Q0sGz0xP+TA0AJwJf5ZPeub8v+5CtZwdcZhV
LU0sjgCgrP3y54heBjF1vhZQ3rJywTmRLHe5Ag0ETV77UxAIAIQPLVFbqheJ90Kf
NF8TYt3ZIMpP5chw25OYq4tuZMzVJxKjUlM7KPQxUKquY/F9WpjH980LmICTb4Fz
txzn2bshIsGyg8pDUSnVK0NPY5uaq9bK4oht8wkr3FNFT2FpeqDIJyn+phIuEpIi
qt1LJyzzjobh9csaaGmNHvtrlkIggBj2n/ZQuGNhcYnKUZ/WGmkItCTSOfA++G+C
dCo1aPEymfbnJvaLB/mLyzA+r/r7LQM10cZEtqh5JdclJEh3CzZmx9HsRxCDZF8W
X/C4MmCwmIxmuU4vkVNhHFTQimQEUR8vg9ltiz8+xBjyE1Iav4MxfOYh3xjdJk1d
zlovyUcAAwUH/2KPgf0UQ1o+4IjOYinEEbNlrD1pKw5anUKwaaeQi0vm/oRG0E2F
ZCJ73OHxW/0hMrwbrGwXcm4NBARnAppg+/CecOVpkBgD5hrM+11DPhxdd1bjjfza
Pq8GmPp8SSsiTPUCoSlzojxL3Z05RNbvKVzxzxbYdx5h5XOTflI7bAHTY4AzGSDf
WaFljjCucht/d7u5empAd02haldUXWjT9RvY5RwnRZ+hjI47e+wUA0FMLHYtA1/0
cwEIvpp2xwF/jpH3ODmnIGEeNoLyzAV7X0KAlSN8VRsh7igZRB9TRGI67aTjRgk8
ayf/QNxAzwEk1MeDv67IFKNYVolxHCt4CtqISQQYEQIACQUCTV77UwIbDAAKCRC3
Q0sGz0xP+dPiAKDUNJ5rkB9CRoMH9BC35d0fqXXeugCgwl/HYv52dWgatbyEGLet
etv5Qeg=
=nIAo
Version: GnuPG v1.2.1 (GNU/Linux)

mQGiBEGP+skRBACyZz7muj2OgWc9FxK+Hj7tWPnrfxEN+0PE+n8MtqH+dxwQpMTd
gDpOXxJa45GM5pEwB6CFSFK7Fb/faniF9fDbm1Ga7MpBupIBYLactkoOTZMuTlGB
T0O5ha4h26YLqFfQOtlEi7d0+BDDdfHRQw3o67ycgRnLgYSA79DISc3MywCgk2TR
yd5sRfZAG23b4EDl+D0+oaMEAK73J7zuxf6F6V5EaxLd/w4JVB2xW0Glcn0fACOe
8FV9lzcZuo2xPpdGuyj02f/xlqvEav3XqTfFU2no61mA2pamaRNhlo+CEfGc7qde
/1twfSgOYqzeCx7+aybyPo8Th41b80FT19mfkjBf6+5NbUHffRabFFh1FmcPVNBn
F3FoA/95nRIzqDMItdTRitaZn02dIGNjdwllBD75bSVEvaR9O5hjBo0VMc25DB7f
DM2qEO52wCQbAKw9zFC284ekZVDaK4aHYt7iobHaqJEpKHgsDut5WWuMiSLR+SsF
aBHIZ9HvrKWLSUQKHU6A1Hva0P0r3GnoCMc/VCVfrLl721SjPbQzQXRvbWljIFJv
Y2tldCBUdXJ0bGUgPGFkbWluQGF0b21pY3JvY2tldHR1cnRsZS5jb20+iFkEExEC
ABkFAkGP+skECwcDAgMVAgMDFgIBAh4BAheAAAoJEDKpURRevSdEzcQAn1hSHqTO
jwv/z/picpOnR+mgycwHAKCBex2ciyXo5xeaQ9w7OMf7Jsmon7kBDQRBj/rMEAQA
6JvRndqE4koK0e49fUkICm1X0ZEzsVg9VmUW+Zft5guCRxmGlYTmtlC7oJCToRP/
m/xH5uIevGiJycRKB0Ix+Csl6f9QuTkQ7tSTHcaIKbI3tL1x6CCBoWeTGYaOJlvk
ubrmajiMFaBfopLH2firoSToDGoUvv4e7bImIHEgNr8AAwUEAND0YR9DOEZvc+Lq
Ta/PQyxkdZ75o+Ty/O64E3OmO1Tuw2ciSQXCcwrbrMSE6EHHetxtGCnOdkjjjtmH
AnxsxdONv/EJuQmLcoNcsigZZ4tfRdmtXgcbnOmXBgmy1ea1KvWcsmecNSAMJHwR
7vDDKzbj4mSmudzjapHeeOewFF10iEYEGBECAAYFAkGP+swACgkQMqlRFF69J0Sq
nQCfa/q9Y/oY4dOTGj6MsdmRIQkKZhYAoIscjinFwTru4FVi2MIEzUUMToDK
=NOIx
Version: GnuPG v1.4.6 (GNU/Linux)

mQGiBD5gtCgRBACKIvjMF+20r9k/Uw2Hq6Y/qn1nM0AZEFalhglXP5pMm5bMgkcI
1vCWqJxSbhQhk8hSEenoszes8hyUxHj4hFFUDiRtAxOpCpGCsCnUddgQtHAQd+tm
aQsM6J3Jm/EZPtwR0lvwvRGvz2x6Rr95G8+42KK9x+mBYhLk0y3gAbBzhwCgnkDH
a97MGBT7gRLrmtFqiHrWlPkD/2tBaH6IEuoJhcAbNj9MukbhDOYJ6ic9Nzf6sR3t
ZG+XgQLLS2DNy8+HWcYJOjpJDEe8zWFDdUv3cL1D0U2f2e85FuJaMucHn+816iw8
mNjZXJEoDE4LJ8Vv53fkevNZpdWmO2VtRwI+woDnIHYHukDLj2sWhVt+5W+uOKAE
OippA/9OzuWrwBtTR+Np8ApZGkxhxU1z0iEStV+kQNqJE7YoR4SGMuzEa3bFzrPx
k4qIU+rw4YgFgHrs1x08lXxNOZkq6avvbl60HqN2qF2UQL/YdU+5X3ixaJVaYYk8
yuK+hp0Hx2DdBWmVhq6rEzIfpnFhF4qspwMWEiiBGjYDL62W7LQ0QVRycG1zLm5l
dCAocnBtIHNpZ25pbmcga2V5KSA8QXhlbC5UaGltbUBBVHJwbXMubmV0PohnBBMR
AgAnAhsDBgsJCAcDAgMVAgMDFgIBAh4BAheAAhkBBQJFfF9PBQkJGI4nAAoJEFCM
5eZmU0wrJ0IAnA0BdyRlq2S8ess55R8YMFnWAWXEAJ9Fa7cEHku4j4B83shCODps
+DYUZohnBBMRAgAnAhsDBQkDdMLsBgsJCAcDAgMVAgMDFgIBAh4BAheABQJAKteu
AhkBAAoJEFCM5eZmU0wrMMUAnRjS2PXQp0tsC/69IGMMxqU+8xeAAJ9XQjVAo+mU
kg/3AeBlMBIlFe5hDQ==
=23Fz
Version: GnuPG v1.2.6 (GNU/Linux)

mQGiBEY5QQ0RBACfC1NbAdGFMOS/Y7P9hmNph2Wh3TJTh6IZpL+lTJBuZSEa6rp0
CghS/yU3gGXUPaxAy91M7PXMv5p7S3U/SusZHATLhFdU5J4LuWMf4IiBy9FOB/aj
Q1s5vZ/i3YFaqolXsRP8TgIu4Lzp/j3+KAxFb3gF7lz64J/Et2Jil0OQzwCgkn9i
SoPEM6d9SCFOidhUuTHUhM0D/3UXl/FKPVFrFzjslFpaN9NgArRrmXKTOBWEqMLy
12pbTzOtv+p17Ot51q4h0ebEWrmVJ/h/7Is6QT6AKHuOIW+1/88fcSrmef//0Scz
wtEwVudkYA+kOGt1pwhapVYf1lWE9Z6L3V/MVdxXUesylGO6jJjOjpUB+ZBItwl7
exkhA/4iemhq4D5Jp6r1Kv3aKSPNENdhTORyfZz4UfyOsUfYncaprP5IZja0j+rd
tQLIsH8hXvCT2kSAUY6nMGmzPgpgGamtHI6gH1ZmoNX2gEF7tzGNgKMbbUmwO89B
N56U7wm68AreXE8XviRjGjAtZWnouqe5X+EiUurdJkzRwU0c2rQpVGhvdWdodFdv
cmtzIDxydWJ5d29ya3NAdGhvdWdodHdvcmtzLmNvbT6IYAQTEQIAIAUCRjlBDQIb
AwYLCQgHAwIEFQIIAwQWAgMBAh4BAheAAAoJEHM/KlUQbeB0SSYAn0sgAx5ZK975
wZiChkIqOCyFZ9PLAJ9laivkzqT2y+Kh9FGe3TP/CAhRTbkCDQRGOUEVEAgAqxJI
MFrYV3JKyeXHVKXHNd5Nf1WdqKi37VOdSTBftiehzZdR9hxkGEknYxnbBLGJR9YD
/uJ2+DRwNBcw2RrrEmb0DCZxcLQLZ3xYa7+WvcR4/Nir/3858SGJ+wmGCHKyX2So
M2TurmKu5bqyUUaBgf+IhKfwOr9zeK3rIRhUq/aiYkw8sWA8ruUvxXwLnbkK1aP9
hfvSqScwjkfUVk6CQ6GFUD+4N4mNRtRcZz3gYa+0jSNeEJZQOJxRuE/gBHav3eyN
dm4VAFPF20BobvBVEcMhO0KaR/X4jW1G1eFAKLxI7cdx3+vLeNPaFwHiSMSknsNs
UiucI9oV+I5S/50ZrwADBwf/StYTK9KvPnY9ZqmirBpSh0Zl0xylMtAiMblG7pKv
qKTPNr9zXooheQBpAbnhOfju0DB/OtE4V21HqnbMws2aFvHecEbO5EmjwT7ZTltH
5vlbiPrXOc7SpP22FdkOYdunM2+nsA6398mpYFEiFFNAzX6pReN2tbbmXf6zxS9n
nHjMAgl5nMuOASLZrTrUX/7yu6ySS1hy0ZVfEoAFeILy4MV8y0lVjBQa2kNOCNpO
Cc+y1+4EHLS3fuN0x+tho3rhjKAzj8KOt4XnALn8OouRMx9G7ItC2U8kNzHHFRg5
adT/+nEthVd9q9pYLrUaze7aMQyl+7cD1KzmSe34X9B6W4hJBBgRAgAJBQJGOUEV
AhsMAAoJEHM/KlUQbeB0O7QAn09h4qrKPhWD9eaiyMRS5YeARTYgAJ9WxLcQEvkA
yOSLb33CweehCrlTnQ==
=scSy
# File Managed by Puppet
[main]
# how often to check for new updates (in seconds)
run_interval = 3600
# how often to allow checking on request (in seconds)
updaterefresh = 600

# how to send notifications (valid: dbus, email, syslog)
emit_via = dbus
# should we listen via dbus to give out update information/check for
# new updates 
dbus_listener = yes

# automatically install updates
do_update = yes
# automatically download updates
do_download = no
# automatically download deps of updates
do_download_deps = no

# = Class yum::cron
#
#
class yum::cron {

  $manage_update_package = $yum::bool_update_disable ? {
    true    => absent,
    default => present,
  }

  $manage_update_service_ensure = $yum::bool_update_disable ? {
    true    => stopped,
    default => running,
  }

  $manage_update_service_enable = $yum::bool_update_disable ? {
    true    => false,
    default => true,
  }

  $manage_update_file = $yum::bool_update_disable ? {
    true    => absent,
    default => present,
  }

  package { 'yum-cron':
    ensure => $manage_update_package,
  }

  service { 'yum-cron':
    ensure     => $manage_update_service_ensure,
    name       => $yum::service,
    enable     => $manage_update_service_enable,
    hasstatus  => true,
    hasrestart => true,
    require    => Package['yum-cron'],
  }

  file { 'yum-cron':
    ensure   => $manage_update_file,
    path     => '/etc/sysconfig/yum-cron',
    content  => template($yum::update_template),
    require  => Package['yum-cron'],
    notify   => Service['yum-cron'],
  }

}
# = Class: yum::defaults
#
# This class manages default yum repositories for RedHat based distros:
# RHEL, Centos, Scientific Linux
#
class yum::defaults ( ) inherits yum::params {

  $osver = split($::operatingsystemrelease, '[.]')

  if $yum::extrarepo =~ /epel/ { include yum::repo::epel }
  if $yum::extrarepo =~ /rpmforge/ { include yum::repo::rpmforge }
  if $yum::extrarepo =~ /jpackage5/ { include yum::repo::jpackage5 }
  if $yum::extrarepo =~ /jpackage6/ { include yum::repo::jpackage6 }
  if $yum::extrarepo =~ /remi/ { include yum::repo::remi }
  if $yum::extrarepo =~ /remi_php55/ { include yum::repo::remi_php55 }
  if $yum::extrarepo =~ /tmz/ and $osver[0] != '4' { include yum::repo::tmz }
  if $yum::extrarepo =~ /webtatic/ { include yum::repo::webtatic }
  if $yum::extrarepo =~ /puppetlabs/ and $osver[0] != '4' { include yum::repo::puppetlabs }
  if $yum::extrarepo =~ /puppetdevel/ and $osver[0] != '4' { include yum::repo::puppetdevel }
  if $yum::extrarepo =~ /nginx/ and $osver[0] != '4' { include yum::repo::nginx }
  if $yum::extrarepo =~ /mongodb/ and $osver[0] != '4' { include yum::repo::mongodb }
  if $yum::extrarepo =~ /repoforge/ { include yum::repo::repoforge }
  if $yum::extrarepo =~ /repoforgeextras/ { include yum::repo::repoforgeextras }
  if $yum::extrarepo =~ /integ_ganeti/ { include yum::repo::integ_ganeti }
  if $yum::extrarepo =~ /elrepo/ { include yum::repo::elrepo }
  if $yum::extrarepo =~ /centalt/ { include yum::repo::centalt }

  if $yum::bool_defaultrepo {
    case $::operatingsystem {
      centos: {
        if $osver[0] == '6' { include yum::repo::centos6 }
        if $osver[0] == '5' { include yum::repo::centos5 }
        if $osver[0] == '4' { include yum::repo::centos4 }
        if $yum::extrarepo =~ /centos-testing/ { include yum::repo::centos_testing }
        if $yum::extrarepo =~ /karan/ { include yum::repo::karan }
        if $yum::extrarepo =~ /atomic/ { include yum::repo::atomic }
      }
      redhat: {
      }
      scientific: {
        if $osver[0] == '6' { include yum::repo::sl6 }
        if $osver[0] == '5' { include yum::repo::sl5 }
        if $yum::extrarepo =~ /centos-testing/ { include yum::repo::centos_testing }
        if $yum::extrarepo =~ /karan/ { include yum::repo::karan }
      }
      default: { }
    }
  }
}
# = Class: yum
#
# This class manages yum repositories for RedHat based distros:
# RHEL, Centos, Scientific Linux
#
# Copyright 2008, admin(at)immerda.ch
# Copyright 2008, Puzzle ITC GmbH
# Marcel Harry haerry+puppet(at)puzzle.ch
# Simon Josi josi+puppet(at)puzzle.ch
#
# This program is free software; you can redistribute
# it and/or modify it under the terms of the GNU
# General Public License version 3 as published by
# the Free Software Foundation.
#
# Apapted for Example42 by Alessandro Franceschi
#
# == Parameters
#
# [*install_all_keys*]
#   If to provide all the module's known rpm gpgp keys.
#   Default true, set to false to keep backwards compatibility
#
# [*update*]
#   If you want yum automatic updates. Possibile values:
#   cron - Updates in a cronjob
#   updatesd - Updates via updatesd (Only on Centos/RedHat/SL 5)
#   false/no - Automatic updates disabled (Default)
#
# [*update_disable*]
#   Set to true if you have enabled updates and now wish to disable
#   Defaults to false.  Logic pertaining to this parameter is only applied
#   when the update method parameter (immediately above) is set.
#
# [*defaultrepo*]
#   If you want to enable default repositories for supported OS
#   Default: true
#   Note: This variable is ignored if you provide a custom source_repo_dir
#
# [*extrarepo*]
#   If you want to enable some (supported) extra repositories
#   Can be an array. Default: 'epel'
#   (Epel is used by many modules)
#   Note: This variable is ignored if you provide a custom source_repo_dir
#
# [*plugins_source_dir*]
#   The path of the plugins configuration directory
#
# [*repo_dir*]
#   The path of the yum.repos.d directory
#
# [*source_repo_dir*]
#   The source path to use to populate the yum.repos.d directory
#
# [*clean_repos*]
#   Boolean. Defines if you want to cleanup the yum.repos.d dir
#   and be sure that it contains only files managed by Puppet
#   Default: false
#
# [*my_class*]
#   Name of a custom class to autoload to manage module's customizations
#   If defined, yum class will automatically "include $my_class"
#   Can be defined also by the (top scope) variable $yum_myclass
#
# [*source*]
#   Sets the content of source parameter for main configuration file
#   If defined, yum main config file will have the param: source => $source
#   Can be defined also by the (top scope) variable $yum_source
#
# [*source_dir*]
#   If defined, the whole yum configuration directory content is retrieved
#   recursively from the specified source
#   (source => $source_dir , recurse => true)
#   Can be defined also by the (top scope) variable $yum_source_dir
#
# [*source_dir_purge*]
#   If set to true (default false) the existing configuration directory is
#   mirrored with the content retrieved from source_dir
#   (source => $source_dir , recurse => true , purge => true)
#   Can be defined also by the (top scope) variable $yum_source_dir_purge
#
# [*template*]
#   Sets the path to the template to use as content for main configuration file
#   If defined, yum main config file has: content => content("$template")
#   Note source and template parameters are mutually exclusive: don't use both
#   Can be defined also by the (top scope) variable $yum_template
#
# [*options*]
#   An hash of custom options to be used in templates for arbitrary settings.
#   Can be defined also by the (top scope) variable $yum_options
#
# [*absent*]
#   Set to 'true' to remove package(s) installed by module
#   Can be defined also by the (top scope) variable $yum_absent
#
# [*disable*]
#   Set to 'true' to disable service(s) managed by module
#   Can be defined also by the (top scope) variable $yum_disable
#
# [*disableboot*]
#   Set to 'true' to disable service(s) at boot, without checks if it's running
#   Use this when the service is managed by a tool like a cluster software
#   Can be defined also by the (top scope) variable $yum_disableboot
#
# [*puppi*]
#   Set to 'true' to enable creation of module data files that are used by puppi
#   Can be defined also by the (top scope) variables $yum_puppi and $puppi
#
# [*puppi_helper*]
#   Specify the helper to use for puppi commands. The default for this module
#   is specified in params.pp and is generally a good choice.
#   You can customize the output of puppi commands for this module using another
#   puppi helper. Use the define puppi::helper to create a new custom helper
#   Can be defined also by the (top scope) variables $yum_puppi_helper
#   and $puppi_helper
#
# [*debug*]
#   Set to 'true' to enable modules debugging
#   Can be defined also by the (top scope) variables $yum_debug and $debug
#
# [*audit_only*]
#   Set to 'true' if you don't intend to override existing configuration files
#   and want to audit the difference between existing files and the ones
#   managed by Puppet.
#   Can be defined also by the (top scope) variables $yum_audit_only
#   and $audit_only
#
# [*config_dir*]
#   Main configuration directory. Used by puppi
#
# [*config_file*]
#   Main configuration file path
#
# [*config_file_mode*]
#   Main configuration file path mode
#
# [*config_file_owner*]
#   Main configuration file path owner
#
# [*config_file_group*]
#   Main configuration file path group
#
# [*cron_params*]
#   Optional extra arguments for $update = cron ONLY
#
# [*cron_mailto*]
#   Optional mail addres to send update reports for $update = cron ONLY
#
# [*cron_dotw*]
#   Days of the week to perform yum updates by cron
#   0123456 (default)
#
# [*log_file*]
#   Log file(s). Used by puppi
#
class yum (
  $install_all_keys    = params_lookup( 'install_all_keys' ),
  $update              = params_lookup( 'update' ),
  $update_disable      = params_lookup( 'update_disable' ),
  $defaultrepo         = params_lookup( 'defaultrepo' ),
  $extrarepo           = params_lookup( 'extrarepo' ),
  $plugins_source_dir  = params_lookup( 'plugins_source_dir' ),
  $repo_dir            = params_lookup( 'repo_dir' ),
  $source_repo_dir     = params_lookup( 'source_repo_dir' ),
  $clean_repos         = params_lookup( 'clean_repos' ),
  $my_class            = params_lookup( 'my_class' ),
  $source              = params_lookup( 'source' ),
  $source_dir          = params_lookup( 'source_dir' ),
  $source_dir_purge    = params_lookup( 'source_dir_purge' ),
  $template            = params_lookup( 'template' ),
  $options             = params_lookup( 'options' ),
  $absent              = params_lookup( 'absent' ),
  $disable             = params_lookup( 'disable' ),
  $disableboot         = params_lookup( 'disableboot' ),
  $puppi               = params_lookup( 'puppi' , 'global' ),
  $puppi_helper        = params_lookup( 'puppi_helper' , 'global' ),
  $debug               = params_lookup( 'debug' , 'global' ),
  $audit_only          = params_lookup( 'audit_only' , 'global' ),
  $config_dir          = params_lookup( 'config_dir' ),
  $config_file         = params_lookup( 'config_file' ),
  $config_file_mode    = params_lookup( 'config_file_mode' ),
  $config_file_owner   = params_lookup( 'config_file_owner' ),
  $config_file_group   = params_lookup( 'config_file_group' ),
  $update_template     = params_lookup( 'update_template' ),
  $cron_param          = params_lookup( 'cron_param' ),
  $cron_mailto         = params_lookup( 'cron_mailto' ),
  $cron_dotw           = params_lookup( 'cron_dotw' ),
  $log_file            = params_lookup( 'log_file' )
  ) inherits yum::params {

  $bool_install_all_keys=any2bool($install_all_keys)
  $bool_defaultrepo=any2bool($defaultrepo)
  $bool_clean_repos=any2bool($clean_repos)
  $bool_source_dir_purge=any2bool($source_dir_purge)
  $bool_absent=any2bool($absent)
  $bool_disable=any2bool($disable)
  $bool_disableboot=any2bool($disableboot)
  $bool_puppi=any2bool($puppi)
  $bool_debug=any2bool($debug)
  $bool_audit_only=any2bool($audit_only)
  $bool_update_disable=any2bool($update_disable)

  $osver = split($::operatingsystemrelease, '[.]')

  $manage_service_enable = $yum::bool_disableboot ? {
    true    => false,
    default => $yum::bool_disable ? {
      true    => false,
      default => $yum::bool_absent ? {
        true  => false,
        false => true,
      },
    },
  }

  $manage_service_ensure = $yum::bool_disable ? {
    true    => 'stopped',
    default =>  $yum::bool_absent ? {
      true    => 'stopped',
      default => 'running',
    },
  }

  $manage_file = $yum::bool_absent ? {
    true    => 'absent',
    default => 'present',
  }

  $manage_audit = $yum::bool_audit_only ? {
    true  => 'all',
    false => undef,
  }

  $manage_file_replace = $yum::bool_audit_only ? {
    true  => false,
    false => true,
  }

  $manage_file_source = $yum::source ? {
    ''        => undef,
    default   => $yum::source,
  }

  $manage_file_content = $yum::template ? {
    ''        => undef,
    default   => template($yum::template),
  }

  $manage_updates = $yum::update ? {
    'cron'     => true,
    'updatesd' => true,
    default    => false,
  }

  file { 'yum.repo_dir':
    ensure  => directory,
    path    => $yum::repo_dir,
    source  => $yum::source_repo_dir,
    recurse => true,
    purge   => $yum::bool_clean_repos,
    replace => $yum::manage_file_replace,
    audit   => $yum::manage_audit,
  }

  if $yum::source_repo_dir == undef {
    include yum::defaults
  }

  # Yum Configuration file
  file { 'yum.conf':
    ensure  => $yum::manage_file,
    path    => $yum::config_file,
    mode    => $yum::config_file_mode,
    owner   => $yum::config_file_owner,
    group   => $yum::config_file_group,
    source  => $yum::manage_file_source,
    content => $yum::manage_file_content,
    replace => $yum::manage_file_replace,
    audit   => $yum::manage_audit,
  }

  # The whole yum configuration directory can be recursively overriden
  if $yum::source_dir {
    file { 'yum.dir':
      ensure  => directory,
      path    => $yum::config_dir,
      source  => $yum::source_dir,
      recurse => true,
      purge   => $yum::source_dir_purge,
      replace => $yum::manage_file_replace,
      audit   => $yum::manage_audit,
    }
  }

  ### Manage Automatic Updates
  if $yum::manage_updates {
    include $yum::update
  }

  ### Include custom class if $my_class is set
  if $yum::my_class {
    include $yum::my_class
  }


  ### Provide puppi data, if enabled ( puppi => true )
  if $yum::bool_puppi == true {
    $classvars=get_class_args()
    puppi::ze { 'yum':
      ensure    => $yum::manage_file,
      variables => $classvars,
      helper    => $yum::puppi_helper,
    }
  }

  ### Debugging, if enabled ( debug => true )
  if $yum::bool_debug == true {
    file { 'debug_yum':
      ensure  => $yum::manage_file,
      path    => "${settings::vardir}/debug-yum",
      mode    => '0640',
      owner   => 'root',
      group   => 'root',
      content => inline_template('<%= scope.to_hash.reject { |k,v| k.to_s =~ /(uptime.*|path|timestamp|free|.*password.*|.*psk.*|.*key)/ }.to_yaml %>'),
    }
  }


}
# = Define yum::managed_yumrepo
#
define yum::managed_yumrepo (
  $descr          = 'absent',
  $baseurl        = 'absent',
  $mirrorlist     = 'absent',
  $enabled        = 0,
  $gpgcheck       = 0,
  $gpgkey         = 'absent',
  $gpgkey_source  = '',
  $gpgkey_name    = '',
  $failovermethod = 'absent',
  $priority       = 99,
  $protect        = 'absent',
  $exclude        = 'absent',
  $autokeyimport  = 'no',
  $includepkgs    = 'absent') {

  # ensure that everything is setup
  include yum::prerequisites

  if $protect != 'absent' {
    if ! defined(Yum::Plugin['protectbase']) {
      yum::plugin { 'protectbase': }
    }
  }

  file { "/etc/yum.repos.d/${name}.repo":
    ensure  => file,
    replace => false,
    before  => Yumrepo[ $name ],
    mode    => '0644',
    owner   => 'root',
    group   => 0,
  }

  $gpgkey_real_name = $gpgkey_name ? {
    ''      => url_parse($gpgkey_source,'filename'),
    default => $gpgkey_name,
  }

  if $gpgkey_source != '' {
    if ! defined(File["/etc/pki/rpm-gpg/${gpgkey_real_name}"]) {
      file { "/etc/pki/rpm-gpg/${gpgkey_real_name}":
        ensure  => file,
        replace => false,
        before  => Yumrepo[ $name ],
        source  => $gpgkey_source,
        mode    => '0644',
        owner   => 'root',
        group   => 0,
      }
    }
  }
  yumrepo { $name:
    descr          => $descr,
    baseurl        => $baseurl,
    mirrorlist     => $mirrorlist,
    enabled        => $enabled,
    gpgcheck       => $gpgcheck,
    gpgkey         => $gpgkey,
    failovermethod => $failovermethod,
    priority       => $priority,
    protect        => $protect,
    exclude        => $exclude,
    includepkgs    => $includepkgs,
  }

  if $autokeyimport == 'yes' and $gpgkey != '' {
    exec { "rpmkey_add_${gpgkey}":
      command     => "rpm --import ${gpgkey}",
      before      => Yumrepo[ $name ],
      refreshonly => true,
      path        => '/sbin:/bin:/usr/sbin:/usr/bin',
    }
  }
}
# = Class yum::params
#
class yum::params  {

  $install_all_keys = false

  $update = false

  $defaultrepo = true

  $extrarepo = 'epel'

  $clean_repos = false

  $plugins_config_dir = '/etc/yum/pluginconf.d'

  $source_repo_dir = undef

  $repo_dir = '/etc/yum.repos.d'

  $config_dir = '/etc/yum'

  $config_file = '/etc/yum.conf'

  $config_file_mode = '0644'

  $config_file_owner = 'root'

  $config_file_group = 'root'

  $log_file = '/var/log/yum.log'

  # parameters for the auto-update classes cron.pp/updatesd.pp
  $update_disable = false

  $update_template = $::operatingsystemrelease ? {
    /6.*/ => 'yum/yum-cron.erb',
    default => undef,
  }

  # The following two params are for cron.pp only

  $cron_param = ''

  $cron_mailto = ''

  $cron_dotw = '0123456'

  $source = ''
  $source_dir = ''
  $source_dir_purge = false
  $template = ''
  $options = ''
  $absent = false
  $disable = false
  $disableboot = false
  $puppi = false
  $puppi_helper = 'standard'
  $debug = false
  $audit_only = false

}
# Define: pagios::plugin
#
# Adds a yum plugin
#
# Usage:
# With standard source package:
# yum::plugin { 'priorities': }
#
# With custom config file source
# yum::plugin { 'priorities':
#   source => 'puppet:///modules/example42/yum/plugin-priorities'
# }
#
# With custom package name (default is taken from $name)
# yum::plugin { 'priorities':
#   package_name => 'yum-priorities'
# }
#
define yum::plugin (
  $package_name = '',
  $source       = '',
  $enable       = true
  ) {

  include yum

  $ensure = bool2ensure( $enable )

  $yum_plugins_prefix = $yum::osver[0] ? {
    5       => 'yum',
    6       => 'yum-plugin',
    default => 'yum-plugin',
  }

  $real_package_name = $package_name ? {
    ''      => "${yum_plugins_prefix}-${name}",
    default => $package_name,
  }

  package { $real_package_name :
    ensure => $ensure
  }

  if ( $source != '' ) {
    file { "yum_plugin_conf_${name}":
      ensure  => $ensure,
      path    => "${yum::plugins_config_dir}/${name}.conf",
      owner   => root,
      group   => root,
      mode    => '0755',
      source  => $source,
    }
  }
}
# = Class yum::prerequisites
#
class yum::prerequisites {

  require yum

  yum::plugin { 'priorities': }
#  yum::plugin { 'security': }

  if $yum::bool_install_all_keys == true {
    file { 'rpm_gpg':
      path    => '/etc/pki/rpm-gpg/',
      source  => "puppet:///modules/yum/${::operatingsystem}.${yum::osver[0]}/rpm-gpg/",
      recurse => true,
      ignore  => '.svn',
      mode    => '0644',
      owner   => root,
      group   => 0,
    }
  }
}
# = Class: yum::repo::10gen
#
# This class installs the 10gen repo for MongoDB
#
class yum::repo::10gen {
  yum::managed_yumrepo { '10gen':
    descr       => '10gen Repository',
    baseurl     => "http://downloads-distro.mongodb.org/repo/redhat/os/${::architecture}",
    enabled     => 1,
    gpgcheck    => 0,
  }
}
# = Class: yum::repo::atomic
#
# This class installs the atomic repo
#
class yum::repo::atomic {
  yum::managed_yumrepo { 'atomic':
    descr          => 'CentOS / Red Hat Enterprise Linux $releasever - atomicrocketturtle.com',
    mirrorlist     => 'http://www.atomicorp.com/channels/mirrorlist/atomic/centos-$releasever-$basearch',
    enabled        => 1,
    gpgcheck       => 1,
    gpgkey         => 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY.art',
    gpgkey_source  => 'puppet:///modules/yum/rpm-gpg/RPM-GPG-KEY.art',
    priority       => 1,
    exclude        => 'nmap-ncat',
  }
}
# = Class: yum::repo::atrpms
#
# This class installs the atrpms repo
#
class yum::repo::atrpms {

  yum::managed_yumrepo { 'centos5-atrpms':
    descr          => 'CentOS $releasever - $basearch - ATrpms',
    baseurl        => 'http://dl.atrpms.net/el$releasever-$basearch/atrpms/stable',
    enabled        => 1,
    gpgcheck       => 1,
    gpgkey         => 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY.atrpms',
    gpgkey_source  => 'puppet:///modules/yum/rpm-gpg/RPM-GPG-KEY.atrpms',
    priority       => 30,
  }

}
# = Class: yum::repo::centalt
#
# This class installs the centalt repo
#
class yum::repo::centalt {
  $osver = split($::operatingsystemrelease, '[.]')
  $release = $::operatingsystem ? {
    /(?i:Centos|RedHat|Scientific)/ => $osver[0],
    default                         => '6',
  }

  yum::managed_yumrepo { 'centalt':
    descr          => 'CentALT RPM Repository',
    baseurl        => "http://centos.alt.ru/repository/centos/${release}/\$basearch/",
    enabled        => 1,
    gpgcheck       => 1,
    failovermethod => 'priority',
    gpgkey         => 'http://centos.alt.ru/repository/centos/RPM-GPG-KEY-CentALT',
    priority       => 1,
  }
}
# = Class: yum::repo::centos4
#
# Base Centos4 repos
#
class yum::repo::centos4 {

  yum::managed_yumrepo { 'base':
    descr      => 'CentOS-$releasever - Base',
    mirrorlist => 'http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=os',
    enabled    => 1,
    gpgcheck   => 1,
    gpgkey     => 'http://mirror.centos.org/centos/RPM-GPG-KEY-centos4',
    priority   => 1,
  }

  yum::managed_yumrepo { 'updates':
    descr      => 'CentOS-$releasever - Updates',
    mirrorlist => 'http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=updates',
    enabled    => 1,
    gpgcheck   => 1,
    gpgkey     => 'http://mirror.centos.org/centos/RPM-GPG-KEY-centos4',
    priority   => 1,
  }

  yum::managed_yumrepo { 'addons':
    descr      => 'CentOS-$releasever - Addons',
    mirrorlist => 'http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=addons',
    enabled    => 1,
    gpgcheck   => 1,
    gpgkey     => 'http://mirror.centos.org/centos/RPM-GPG-KEY-centos4',
    priority   => 1,
  }

  yum::managed_yumrepo { 'extras':
    descr      => 'CentOS-$releasever - Extras',
    mirrorlist => 'http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=extras',
    enabled    => 1,
    gpgcheck   => 1,
    gpgkey     => 'http://mirror.centos.org/centos/RPM-GPG-KEY-centos4',
    priority   => 1,
  }

  yum::managed_yumrepo { 'centosplus':
    descr      => 'CentOS-$releasever - Centosplus',
    mirrorlist => 'http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=centosplus',
    enabled    => 0,
    gpgcheck   => 1,
    gpgkey     => 'http://mirror.centos.org/centos/RPM-GPG-KEY-centos4',
    priority   => 2,
  }

  yum::managed_yumrepo { 'contrib':
    descr      => 'CentOS-$releasever - Contrib',
    mirrorlist => 'http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=contrib',
    enabled    => 0,
    gpgcheck   => 1,
    gpgkey     => 'http://mirror.centos.org/centos/RPM-GPG-KEY-centos4',
    priority   => 2,
  }

}
# = Class: yum::repo::centos5
#
# Base Centos5 repos
#
# == Parameters:
#
# [*mirror_url*]
#   A clean URL to a mirror of `rsync://msync.centos.org::CentOS`.
#   The paramater is interpolated with the known directory structure to
#   create a the final baseurl parameter for each yumrepo so it must be
#   "clean", i.e., without a query string like `?key1=valA&key2=valB`.
#   Additionally, it may not contain a trailing slash.
#   Example: `http://mirror.example.com/pub/rpm/centos`
#   Default: `undef`
#
class yum::repo::centos5 (
  $mirror_url = undef,
) {

  if $mirror_url {
    validate_re(
      $mirror_url,
      '^(?:https?|ftp):\/\/[\da-zA-Z-][\da-zA-Z\.-]*\.[a-zA-Z]{2,6}\.?(?:\/[\w~-]*)*$',
      '$mirror must be a Clean URL with no query-string, a fully-qualified hostname and no trailing slash.'
    )
  }

  $baseurl_base = $mirror_url ? {
    undef   => undef,
    default => "${mirror_url}/\$releasever/os/\$basearch/",
  }

  $baseurl_updates = $mirror_url ? {
    undef   => undef,
    default => "${mirror_url}/\$releasever/updates/\$basearch/",
  }

  $baseurl_addons = $mirror_url ? {
    undef   => undef,
    default => "${mirror_url}/\$releasever/addons/\$basearch/",
  }

  $baseurl_extras = $mirror_url ? {
    undef   => undef,
    default => "${mirror_url}/\$releasever/extras/\$basearch/",
  }

  $baseurl_centosplus = $mirror_url ? {
    undef   => undef,
    default => "${mirror_url}/\$releasever/centosplus/\$basearch/",
  }

  $baseurl_contrib = $mirror_url ? {
    undef   => undef,
    default => "${mirror_url}/\$releasever/contrib/\$basearch/",
  }

  yum::managed_yumrepo { 'base':
    descr          => 'CentOS-$releasever - Base',
    baseurl        => $baseurl_base,
    mirrorlist     => 'http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=os',
    failovermethod => 'priority',
    enabled        => 1,
    gpgcheck       => 1,
    gpgkey         => 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-5',
    gpgkey_source  => 'puppet:///modules/yum/rpm-gpg/RPM-GPG-KEY-CentOS-5',
    priority       => 1,
  }

  yum::managed_yumrepo { 'updates':
    descr          => 'CentOS-$releasever - Updates',
    baseurl        => $baseurl_updates,
    mirrorlist     => 'http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=updates',
    failovermethod => 'priority',
    enabled        => 1,
    gpgcheck       => 1,
    gpgkey         => 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-5',
    priority       => 1,
  }

  yum::managed_yumrepo { 'addons':
    descr          => 'CentOS-$releasever - Addons',
    baseurl        => $baseurl_addons,
    mirrorlist     => 'http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=addons',
    failovermethod => 'priority',
    enabled        => 1,
    gpgcheck       => 1,
    gpgkey         => 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-5',
    priority       => 1,
  }

  yum::managed_yumrepo { 'extras':
    descr          => 'CentOS-$releasever - Extras',
    baseurl        => $baseurl_extras,
    mirrorlist     => 'http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=extras',
    failovermethod => 'priority',
    enabled        => 1,
    gpgcheck       => 1,
    gpgkey         => 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-5',
    priority       => 1,
  }

  yum::managed_yumrepo { 'centosplus':
    descr          => 'CentOS-$releasever - Centosplus',
    baseurl        => $baseurl_centosplus,
    mirrorlist     => 'http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=centosplus',
    failovermethod => 'priority',
    enabled        => 1,
    gpgcheck       => 1,
    gpgkey         => 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-5',
    priority       => 2,
  }

  yum::managed_yumrepo { 'contrib':
    descr          => 'CentOS-$releasever - Contrib',
    baseurl        => $baseurl_contrib,
    mirrorlist     => 'http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=contrib',
    failovermethod => 'priority',
    gpgcheck       => 1,
    gpgkey         => 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-5',
    priority       => 10,
  }

}
# = Class: yum::repo::centos6
#
# Base Centos6 repos
#
# == Parameters:
#
# [*mirror_url*]
#   A clean URL to a mirror of `rsync://msync.centos.org::CentOS`.
#   The paramater is interpolated with the known directory structure to
#   create a the final baseurl parameter for each yumrepo so it must be
#   "clean", i.e., without a query string like `?key1=valA&key2=valB`.
#   Additionally, it may not contain a trailing slash.
#   Example: `http://mirror.example.com/pub/rpm/centos`
#   Default: `undef`
#
class yum::repo::centos6 (
  $mirror_url = undef,
) {

  if $mirror_url {
    validate_re(
      $mirror_url,
      '^(?:https?|ftp):\/\/[\da-zA-Z-][\da-zA-Z\.-]*\.[a-zA-Z]{2,6}\.?(?:\/[\w~-]*)*$',
      '$mirror must be a Clean URL with no query-string, a fully-qualified hostname and no trailing slash.'
    )
  }

  $baseurl_base = $mirror_url ? {
    undef   => undef,
    default => "${mirror_url}/\$releasever/os/\$basearch/",
  }

  $baseurl_updates = $mirror_url ? {
    undef   => undef,
    default => "${mirror_url}/\$releasever/updates/\$basearch/",
  }

  $baseurl_extras = $mirror_url ? {
    undef   => undef,
    default => "${mirror_url}/\$releasever/extras/\$basearch/",
  }

  $baseurl_centosplus = $mirror_url ? {
    undef   => undef,
    default => "${mirror_url}/\$releasever/centosplus/\$basearch/",
  }

  $baseurl_contrib = $mirror_url ? {
    undef   => undef,
    default => "${mirror_url}/\$releasever/contrib/\$basearch/",
  }

  yum::managed_yumrepo { 'base':
    descr          => 'CentOS-$releasever - Base',
    baseurl        => $baseurl_base,
    mirrorlist     => 'http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=os',
    failovermethod => 'priority',
    enabled        => 1,
    gpgcheck       => 1,
    gpgkey         => 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6',
    gpgkey_source  => 'puppet:///modules/yum/rpm-gpg/RPM-GPG-KEY-CentOS-6',
    priority       => 1,
  }

  yum::managed_yumrepo { 'updates':
    descr          => 'CentOS-$releasever - Updates',
    baseurl        => $baseurl_updates,
    mirrorlist     => 'http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=updates',
    failovermethod => 'priority',
    enabled        => 1,
    gpgcheck       => 1,
    gpgkey         => 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6',
    priority       => 1,
  }

  yum::managed_yumrepo { 'extras':
    descr          => 'CentOS-$releasever - Extras',
    baseurl        => $baseurl_extras,
    mirrorlist     => 'http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=extras',
    failovermethod => 'priority',
    enabled        => 1,
    gpgcheck       => 1,
    gpgkey         => 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6',
    priority       => 1,
  }

  yum::managed_yumrepo { 'centosplus':
    descr          => 'CentOS-$releasever - Centosplus',
    baseurl        => $baseurl_centosplus,
    mirrorlist     => 'http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=centosplus',
    failovermethod => 'priority',
    enabled        => 1,
    gpgcheck       => 1,
    gpgkey         => 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6',
    priority       => 2,
  }

  yum::managed_yumrepo { 'contrib':
    descr          => 'CentOS-$releasever - Contrib',
    baseurl        => $baseurl_contrib,
    mirrorlist     => 'http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=contrib',
    failovermethod => 'priority',
    gpgcheck       => 1,
    gpgkey         => 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6',
    priority       => 10,
  }

}
# = Class: yum::repo::centos_testing
#
# Centos Testing
#
class yum::repo::centos_testing (
  $include_pkgs = '',
  $exclude_pkgs = undef
  ) {
  if $include_pkgs == '' {
    fail('Please configure $include_pkgs as we run the testing repo with highest repository')
  }

  yum::managed_yumrepo{'centos5-testing':
    descr       => 'CentOS-$releasever - Testing',
    baseurl     => 'http://dev.centos.org/centos/$releasever/testing/$basearch',
    enabled     => 1,
    gpgcheck    => 1,
    gpgkey      => 'http://dev.centos.org/centos/RPM-GPG-KEY-CentOS-testing',
    priority    => 1,
    includepkgs => $include_pkgs,
    exclude     => $exclude_pkgs,
  }
}
# = Class: yum::repo::ceph
#
# This class installs the official ceph repo
#
class yum::repo::ceph (
  $release = 'emperor'
) {

  yum::managed_yumrepo { 'ceph':
    descr          => "Ceph ${release} repository",
    baseurl        => "http://ceph.com/rpm-${release}/\$releasever/\$basearch",
    enabled        => 1,
    gpgcheck       => 1,
    failovermethod => 'priority',
    gpgkey         => 'https://ceph.com/git/?p=ceph.git;a=blob_plain;f=keys/release.asc',
    autokeyimport  => 'yes',
    priority       => 5,
  }

}
# = Class: yum::repo::elasticsearch10
#
# This class installs the elasticsearch10 repo
#
class yum::repo::elasticsearch10 {

  yum::managed_yumrepo { 'elasticsearch-1.0':
    descr          => 'Elasticsearch repository for 1.0.x packages',
    baseurl        => 'http://packages.elasticsearch.org/elasticsearch/1.0/centos',
    enabled        => 1,
    gpgcheck       => 1,
    gpgkey         => 'http://packages.elasticsearch.org/GPG-KEY-elasticsearch',
  }

}
# = Class: yum::repo::elasticsearch90
#
# This class installs the elasticsearch90 repo
#
class yum::repo::elasticsearch90 {

  yum::managed_yumrepo { 'elasticsearch-0.90':
    descr          => 'Elasticsearch repository for 0.90.x packages',
    baseurl        => 'http://packages.elasticsearch.org/elasticsearch/0.90/centos',
    enabled        => 1,
    gpgcheck       => 1,
    gpgkey         => 'http://packages.elasticsearch.org/GPG-KEY-elasticsearch',
  }

}
# = Class: yum::repo::elrepo
#
# This class installs the ELRepo repository
#
# == Parameters:
#
# [*mirror_url*]
#   A clean URL to a mirror of `http://elrepo.org/linux/`.
#   The paramater is interpolated with the known directory structure to
#   create a the final baseurl parameter for each yumrepo so it must be
#   "clean", i.e., without a query string like `?key1=valA&key2=valB`.
#   Additionally, it may not contain a trailing slash.
#   Example: `http://elrepo.org/linux/`
#   Default: `undef`
#
class yum::repo::elrepo (
  $mirror_url = undef,
) {

  if $mirror_url {
    validate_re(
      $mirror_url,
      '^(?:https?|ftp):\/\/[\da-zA-Z-][\da-zA-Z\.-]*\.[a-zA-Z]{2,6}\.?(?:\/[\w~-]*)*$',
      '$mirror must be a Clean URL with no query-string, a fully-qualified hostname and no trailing slash.'
    )
  }

  # Workaround for Facter < 1.7.0
  $osver = split($::operatingsystemrelease, '[.]')

  case $::operatingsystem {
    'RedHat','CentOS','Scientific': {
      $release = "el${osver[0]}"
    }
    default: {
      fail("${title}: Operating system '${::operatingsystem}' is not currently supported")
    }
  }

  $baseurl_elrepo = $mirror_url ? {
    undef   => undef,
    default => "${mirror_url}/elrepo/${release}/\$basearch",
  }

  $baseurl_elrepo_testing = $mirror_url ? {
    undef   => undef,
    default => "${mirror_url}/testing/${release}/\$basearch",
  }

  $baseurl_elrepo_kernel = $mirror_url ? {
    undef   => undef,
    default => "${mirror_url}/kernel/${release}/\$basearch",
  }

  $baseurl_elrepo_extras = $mirror_url ? {
    undef   => undef,
    default => "${mirror_url}/extras/${release}/\$basearch",
  }

  yum::managed_yumrepo { 'elrepo':
    descr          => "ELRepo.org Community Enterprise Linux Repository - ${release}",
    baseurl        => $baseurl_elrepo,
    mirrorlist     => "http://elrepo.org/mirrors-elrepo.${release}",
    enabled        => 1,
    gpgcheck       => 1,
    gpgkey         => 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-elrepo.org',
    gpgkey_source  => 'puppet:///modules/yum/rpm-gpg/RPM-GPG-KEY-elrepo.org',
    failovermethod => 'priority',
    priority       => 17,
  }

  yum::managed_yumrepo { 'elrepo-testing':
    descr          => "ELRepo.org Community Enterprise Linux Testing Repository - ${release}",
    baseurl        => $baseurl_elrepo_testing,
    mirrorlist     => "http://elrepo.org/mirrors-elrepo-testing.${release}",
    enabled        => 0,
    gpgcheck       => 1,
    gpgkey         => 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-elrepo.org',
    failovermethod => 'priority',
    priority       => 17,
  }

  yum::managed_yumrepo { 'elrepo-kernel':
    descr          => "ELRepo.org Community Enterprise Linux Kernel Repository - ${release}",
    baseurl        => $baseurl_elrepo_kernel,
    mirrorlist     => "http://elrepo.org/mirrors-elrepo-kernel.${release}",
    enabled        => 0,
    gpgcheck       => 1,
    gpgkey         => 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-elrepo.org',
    failovermethod => 'priority',
    priority       => 17,
  }

  yum::managed_yumrepo { 'elrepo-extras':
    descr          => "ELRepo.org Community Enterprise Linux Extras Repository - ${release}",
    baseurl        => $baseurl_elrepo_extras,
    mirrorlist     => "http://elrepo.org/mirrors-elrepo-extras.${release}",
    enabled        => 0,
    gpgcheck       => 1,
    gpgkey         => 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-elrepo.org',
    failovermethod => 'priority',
    priority       => 17,
  }

}
# = Class: yum::repo::epel
#
# This class installs the epel repo
#
# == Parameters:
#
# [*mirror_url*]
#   A clean URL to a mirror of `http://dl.fedoraproject.org/pub/epel/`.
#   The paramater is interpolated with the known directory structure to
#   create a the final baseurl parameter for each yumrepo so it must be
#   "clean", i.e., without a query string like `?key1=valA&key2=valB`.
#   Additionally, it may not contain a trailing slash.
#   Example: `http://mirror.example.com/pub/rpm/epel`
#   Default: `undef`
#
class yum::repo::epel (
  $mirror_url = undef,
) {

  if $mirror_url {
    validate_re(
      $mirror_url,
      '^(?:https?|ftp):\/\/[\da-zA-Z-][\da-zA-Z\.-]*\.[a-zA-Z]{2,6}\.?(?:\/[\w~-]*)*$',
      '$mirror must be a Clean URL with no query-string, a fully-qualified hostname and no trailing slash.'
    )
  }

  if $::operatingsystem == 'Amazon' {
    $osver = [ '6' ]
  } else {
    $osver = split($::operatingsystemrelease, '[.]')
  }

  $baseurl_epel = $mirror_url ? {
    undef   => undef,
    default => "${mirror_url}/${osver[0]}/\$basearch/",
  }

  $baseurl_epel_debuginfo = $mirror_url ? {
    undef   => undef,
    default => "${mirror_url}/${osver[0]}/\$basearch/debug",
  }

  $baseurl_epel_source = $mirror_url ? {
    undef   => undef,
    default => "${mirror_url}/${osver[0]}/SRPMS/",
  }

  $baseurl_epel_testing = $mirror_url ? {
    undef   => undef,
    default => "${mirror_url}/testing/${osver[0]}/\$basearch/",
  }

  $baseurl_epel_testing_debuginfo = $mirror_url ? {
    undef   => undef,
    default => "${mirror_url}/testing/${osver[0]}/\$basearch/debug",
  }

  $baseurl_epel_testing_source = $mirror_url ? {
    undef   => undef,
    default => "${mirror_url}/testing/${osver[0]}/SRPMS/",
  }

  yum::managed_yumrepo { 'epel':
    descr          => "Extra Packages for Enterprise Linux ${osver[0]} - \$basearch",
    baseurl        => $baseurl_epel,
    mirrorlist     => "http://mirrors.fedoraproject.org/mirrorlist?repo=epel-${osver[0]}&arch=\$basearch",
    enabled        => 1,
    gpgcheck       => 1,
    failovermethod => 'priority',
    gpgkey         => "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-${osver[0]}",
    gpgkey_source  => "puppet:///modules/yum/rpm-gpg/RPM-GPG-KEY-EPEL-${osver[0]}",
    priority       => 16,
  }

  yum::managed_yumrepo { 'epel-debuginfo':
    descr          => "Extra Packages for Enterprise Linux ${osver[0]} - \$basearch - Debug",
    baseurl        => $baseurl_epel_debuginfo,
    mirrorlist     => "http://mirrors.fedoraproject.org/mirrorlist?repo=epel-${osver[0]}&arch=\$basearch",
    enabled        => 0,
    gpgcheck       => 1,
    failovermethod => 'priority',
    gpgkey         => "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-${osver[0]}",
    priority       => 16,
  }

  yum::managed_yumrepo { 'epel-source':
    descr          => "Extra Packages for Enterprise Linux ${osver[0]} - \$basearch - Source",
    baseurl        => $baseurl_epel_source,
    mirrorlist     => "http://mirrors.fedoraproject.org/mirrorlist?repo=epel-source-${osver[0]}&arch=\$basearch",
    enabled        => 0,
    gpgcheck       => 1,
    failovermethod => 'priority',
    gpgkey         => "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-${osver[0]}",
    priority       => 16,
  }

  yum::managed_yumrepo { 'epel-testing':
    descr          => "Extra Packages for Enterprise Linux ${osver[0]} - Testing - \$basearch",
    baseurl        => $baseurl_epel_testing,
    mirrorlist     => "http://mirrors.fedoraproject.org/mirrorlist?repo=testing-epel${osver[0]}&arch=\$basearch",
    enabled        => 0,
    gpgcheck       => 1,
    failovermethod => 'priority',
    gpgkey         => "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-${osver[0]}",
    priority       => 17,
  }

  yum::managed_yumrepo { 'epel-testing-debuginfo':
    descr          => "Extra Packages for Enterprise Linux ${osver[0]} - Testing - \$basearch - Debug",
    baseurl        => $baseurl_epel_testing_debuginfo,
    mirrorlist     => "http://mirrors.fedoraproject.org/mirrorlist?repo=testing-debug-epel${osver[0]}&arch=\$basearch",
    enabled        => 0,
    gpgcheck       => 1,
    failovermethod => 'priority',
    gpgkey         => "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-${osver[0]}",
    priority       => 17,
  }

  yum::managed_yumrepo { 'epel-testing-source':
    descr          => "Extra Packages for Enterprise Linux ${osver[0]} - Testing - \$basearch - Source",
    baseurl        => $baseurl_epel_testing_source,
    mirrorlist     => "http://mirrors.fedoraproject.org/mirrorlist?repo=testing-source-epel${osver[0]}&arch=\$basearch",
    enabled        => 0,
    gpgcheck       => 1,
    failovermethod => 'priority',
    gpgkey         => "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-${osver[0]}",
    priority       => 17,
  }

}

# = Class: yum::repo::foreman
#
# This class installs the foreman repo
#
class yum::repo::foreman {

  yum::managed_yumrepo { 'foreman':
    descr          => 'Foreman Repo',
    baseurl        => 'http://yum.theforeman.org/stable/',
    enabled        => 1,
    gpgcheck       => 0,
    failovermethod => 'priority',
    # gpgkey       => 'http://yum.theforeman.org/RPM-GPG-KEY-foreman',
    priority       => 1,
  }

}

# = Class: yum::repo::integ_ganeti
#
# This class installs the Integ Ganeti Yum repo
#
# == Parameters:
#
# [*mirror_url*]
#   A clean URL to a mirror of `http://jfut.integ.jp/linux/ganeti/`.
#   The paramater is interpolated with the known directory structure to
#   create a the final baseurl parameter for each yumrepo so it must be
#   "clean", i.e., without a query string like `?key1=valA&key2=valB`.
#   Additionally, it may not contain a trailing slash.
#   Example: `http://mirror.example.com/pub/rpm/ganeti`
#   Default: `undef`
#
class yum::repo::integ_ganeti (
  $mirror_url = undef,
) {

  if $mirror_url {
    validate_re(
      $mirror_url,
      '^(?:https?|ftp):\/\/[\da-zA-Z-][\da-zA-Z\.-]*\.[a-zA-Z]{2,6}\.?(?:\/[\w~-]*)*$',
      '$mirror must be a Clean URL with no query-string, a fully-qualified hostname and no trailing slash.'
    )
  }

  # Workaround for Facter < 1.7.0
  $osver = split($::operatingsystemrelease, '[.]')

  case $::operatingsystem {
    'Fedora': {
      $release = 'fedora'
    }
    'RedHat','CentOS','Scientific': {
      $release = $osver[0]
    }
    default: {
      fail("${title}: Operating system '${::operatingsystem}' is not currently supported")
    }
  }

  $baseurl_integ_ganeti = $mirror_url ? {
    undef   => "http://jfut.integ.jp/linux/ganeti/${release}/\$basearch",
    default => "${mirror_url}/${release}/\$basearch",
  }

  $baseurl_integ_ganeti_source = $mirror_url ? {
    undef   => "http://jfut.integ.jp/linux/ganeti/${release}/SRPMS",
    default => "${mirror_url}/${release}/SRPMS",
  }

  yum::managed_yumrepo { 'integ-ganeti':
    descr          => "Integ Ganeti Packages ${osver[0]} - \$basearch",
    baseurl        => $baseurl_integ_ganeti,
    enabled        => 1,
    gpgcheck       => 0,
    priority       => 15,
  }

  yum::managed_yumrepo { 'integ-ganeti-source':
    descr          => "Integ Ganeti Packages ${osver[0]} - Source",
    baseurl        => $baseurl_integ_ganeti_source,
    enabled        => 0,
    gpgcheck       => 0,
    priority       => 15,
  }

}
# = Class: yum::repo::jpackage5
#
# This class installs the jpackage5 repo
#
class yum::repo::jpackage5 {

  include yum

  yum::managed_yumrepo { 'jpackage-generic-5.0':
    descr          => 'JPackage (free), generic',
    mirrorlist     => 'http://www.jpackage.org/mirrorlist.php?dist=generic&type=free&release=5.0',
    failovermethod => 'priority',
    gpgcheck       => 1,
    gpgkey         => 'http://www.jpackage.org/jpackage.asc',
    enabled        => 1,
    priority       => 10,
  }

  yum::managed_yumrepo { 'jpackage-generic-5.0-updates':
    descr          => 'JPackage (free), generic updates',
    mirrorlist     => 'http://www.jpackage.org/mirrorlist.php?dist=generic&type=free&release=5.0-updates',
    failovermethod => 'priority',
    gpgcheck       => 1,
    gpgkey         => 'http://www.jpackage.org/jpackage.asc',
    enabled        => 1,
    priority       => 10,
  }

  yum::managed_yumrepo { 'jpackage-rhel':
    descr          => 'JPackage (free) for Red Hat Enterprise Linux $releasever',
    mirrorlist     => 'http://www.jpackage.org/mirrorlist.php?dist=redhat-el-$releasever&type=free&release=5.0',
    failovermethod => 'priority',
    gpgcheck       => 1,
    gpgkey         => 'http://www.jpackage.org/jpackage.asc',
    enabled        => 1,
    priority       => 10,
  }

  yum::managed_yumrepo { 'jpackage-generic-5.0-devel':
    descr          => 'JPackage (free), generic',
    baseurl        => 'http://mirrors.dotsrc.org/jpackage/5.0/generic/devel',
    failovermethod => 'priority',
    gpgcheck       => 1,
    gpgkey         => 'http://www.jpackage.org/jpackage.asc',
    enabled        => 0,
    priority       => 10,
  }

}
# = Class: yum::repo::jpackage6
#
# This class installs the jpackage6 repo
#
class yum::repo::jpackage6 {

  yum::managed_yumrepo { 'jpackage':
    descr          => 'JPackage 6 generic',
    mirrorlist     => 'http://www.jpackage.org/mirrorlist.php?dist=generic&type=free&release=6.0',
    failovermethod => 'priority',
    gpgcheck       => 1,
    gpgkey         => 'http://www.jpackage.org/jpackage.asc',
    enabled        => 1,
    priority       => 1,
  }

}
# = Class: yum::repo::karan
#
# This class installs the karan repo
#
class yum::repo::karan {

  yum::managed_yumrepo { 'kbs-CentOS-Extras':
    descr          => 'CentOS.Karan.Org-EL$releasever - Stable',
    baseurl        => 'http://centos.karan.org/el$releasever/extras/stable/$basearch/RPMS/',
    enabled        => 1,
    gpgcheck       => 1,
    gpgkey         => 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-kbsingh',
    gpgkey_source  => 'puppet:///modules/yum/rpm-gpg/RPM-GPG-KEY-kbsingh',
    priority       => 20,
  }

  yum::managed_yumrepo { 'kbs-CentOS-Extras-Testing':
    descr    => 'CentOS.Karan.Org-EL$releasever - Testing',
    baseurl  => 'http://centos.karan.org/el$releasever/extras/testing/$basearch/RPMS/',
    enabled  => 0,
    gpgcheck => 1,
    gpgkey   => 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-kbsingh',
    priority => 20,
  }

  yum::managed_yumrepo { 'kbs-CentOS-Misc':
    descr    => 'CentOS.Karan.Org-EL$releasever - Stable',
    baseurl  => 'http://centos.karan.org/el$releasever/misc/stable/$basearch/RPMS/',
    enabled  => 1,
    gpgcheck => 1,
    gpgkey   => 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-kbsingh',
    priority => 20,
  }

  yum::managed_yumrepo { 'kbs-CentOS-Misc-Testing':
    descr    => 'CentOS.Karan.Org-EL$releasever - Testing',
    baseurl  => 'http://centos.karan.org/el$releasever/misc/testing/$basearch/RPMS/',
    enabled  => 0,
    gpgcheck => 1,
    gpgkey   => 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-kbsingh',
    priority => 20,
  }

}
# = Class: yum::repo::logstash13
#
# This class installs the logstash13 repo
#
class yum::repo::logstash13 {

  yum::managed_yumrepo { 'logstash-1.3':
    descr          => 'logstash repository for 1.3.x packages',
    baseurl        => 'http://packages.elasticsearch.org/logstash/1.3/centos',
    enabled        => 1,
    gpgcheck       => 1,
    gpgkey         => 'http://packages.elasticsearch.org/GPG-KEY-elasticsearch',
  }

}
# = Class: yum::repo::mongodb
#
# This class installs the mongodb repo
#
class yum::repo::mongodb {

  yum::managed_yumrepo { 'mongodb':
    descr     => '10gen MongoDB Repo',
    baseurl   => 'http://downloads-distro.mongodb.org/repo/redhat/os/x86_64',
    enabled   => 1,
    gpgcheck  => 0,
  }

}

# = Class: yum::repo::monitoringsucks
#
# This class installs the monitoringsucks repo
#
class yum::repo::monitoringsucks {

  yum::managed_yumrepo { 'monitoringsucks':
    descr          => 'MonitoringSuck at Inuits',
    baseurl        => 'http://pulp.inuits.eu/pulp/repos/monitoring',
    enabled        => 1,
    gpgcheck       => 0,
    failovermethod => 'priority',
    priority       => 99,
  }

}
# = Class: yum::repo::newrelic
#
# This class installs the newrelic repo
#
class yum::repo::newrelic {

  yum::managed_yumrepo { 'newrelic':
    descr     => 'Newrelic official release packages',
    baseurl   => 'http://yum.newrelic.com/pub/newrelic/el5/$basearch/',
    enabled   => 1,
    gpgcheck  => 0,
    priority  => 1,
  }

}
# = Class: yum::repo::nginx
#
# This class installs the nginx repo
#
class yum::repo::nginx {
  $osver = split($::operatingsystemrelease, '[.]')

  yum::managed_yumrepo { 'nginx':
    descr    => 'Nginx official release packages',
    baseurl  => "http://nginx.org/packages/rhel/${osver[0]}/\$basearch/",
    enabled  => 1,
    gpgcheck => 0,
    priority => 1,
  }

}
# = Class: yum::repo::openstack_grizzly
#
# This class installs the EPEL-6 repo for OpenStack Grizzly
#
class yum::repo::openstack_grizzly {

  yum::managed_yumrepo { 'epel-openstack-grizzly':
    descr          => 'OpenStack Grizzly Repository for EPEL 6',
    baseurl        => 'http://repos.fedorapeople.org/repos/openstack/openstack-grizzly/epel-6',
    enabled        => 1,
    gpgcheck       => 0,
    failovermethod => 'priority',
    priority       => 1,
  }
}
# = Class: yum::repo::passenger
#
# This class installs the passenger repo
#
class yum::repo::passenger {

  yum::managed_yumrepo { 'passenger':
    descr          => 'Red Hat Enterprise $releasever - Phusion Passenger',
    baseurl        => 'http://passenger.stealthymonkeys.com/rhel/$releasever/$basearch',
    mirrorlist     => 'http://passenger.stealthymonkeys.com/rhel/mirrors',
    enabled        => 1 ,
    gpgcheck       => 0, # To fix key autoimport
    failovermethod => 'priority',
    gpgkey         => 'http://passenger.stealthymonkeys.com/RPM-GPG-KEY-stealthymonkeys.asc',
    autokeyimport  => 'yes',
    priority       => 20,
  }

}

# = Class: yum::repo::pdgd91
#
# This class installs the postgresql 9.1 repo
#
class yum::repo::pgdg91 {

  yum::managed_yumrepo { 'pgdg91':
    descr          => 'PostgreSQL 9.1 $releasever - $basearch',
    baseurl        => 'http://yum.postgresql.org/9.1/redhat/rhel-$releasever-$basearch',
    enabled        => 1,
    gpgcheck       => 1,
    gpgkey         => 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-PGDG',
    gpgkey_source  => 'puppet:///modules/yum/rpm-gpg/RPM-GPG-KEY-PGDG',
    priority       => 20,
  }

}

# = Class: yum::repo::pdgd92
#
# This class installs the postgresql 9.2 repo
#
class yum::repo::pgdg92 {

  yum::managed_yumrepo { 'pgdg92':
    descr          => 'PostgreSQL 9.2 $releasever - $basearch',
    baseurl        => 'http://yum.postgresql.org/9.2/redhat/rhel-$releasever-$basearch',
    enabled        => 1,
    gpgcheck       => 1,
    gpgkey         => 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-PGDG',
    gpgkey_source  => 'puppet:///modules/yum/rpm-gpg/RPM-GPG-KEY-PGDG',
    priority       => 20,
  }

}

# = Class: yum::repo::pdgd93
#
# This class installs the postgresql 9.3 repo
#
class yum::repo::pgdg93 {

  yum::managed_yumrepo { 'pgdg93':
    descr          => 'PostgreSQL 9.3 $releasever - $basearch',
    baseurl        => 'http://yum.postgresql.org/9.3/redhat/rhel-$releasever-$basearch',
    enabled        => 1,
    gpgcheck       => 1,
    gpgkey         => 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-PGDG',
    gpgkey_source  => 'puppet:///modules/yum/rpm-gpg/RPM-GPG-KEY-PGDG',
    priority       => 20,
  }

}

# = Class: yum::repo::puppetdevel
#
# This class installs the puppetdevel repo
#
class yum::repo::puppetdevel {

  yum::managed_yumrepo { 'puppetlabs_devel':
    descr          => 'Puppet Labs Packages - Devel',
    baseurl        => 'http://yum.puppetlabs.com/el/$releasever/devel/$basearch',
    enabled        => 1,
    gpgcheck       => 1,
    failovermethod => 'priority',
    gpgkey         => 'http://yum.puppetlabs.com/RPM-GPG-KEY-puppetlabs',
    priority       => 15,
  }

  yum::managed_yumrepo { 'puppetlabs_dependencies':
    descr          => 'Puppet Labs Packages - Dependencies',
    baseurl        => 'http://yum.puppetlabs.com/el/$releasever/dependencies/$basearch',
    enabled        => 1,
    gpgcheck       => 1,
    failovermethod => 'priority',
    gpgkey         => 'http://yum.puppetlabs.com/RPM-GPG-KEY-puppetlabs',
    priority       => 15,
  }

}
# = Class: yum::repo::puppetlabs
#
# This class installs the puppetlabs repo
#
class yum::repo::puppetlabs {
  $osver = split($::operatingsystemrelease, '[.]')
  $release = $::operatingsystem ? {
    /(?i:Centos|RedHat|Scientific)/ => $osver[0],
    default                         => '6',
  }

  yum::managed_yumrepo { 'puppetlabs':
    descr          => 'Puppet Labs Packages',
    baseurl        => "http://yum.puppetlabs.com/el/${release}/products/\$basearch",
    enabled        => 1,
    gpgcheck       => 1,
    failovermethod => 'priority',
    gpgkey         => 'http://yum.puppetlabs.com/RPM-GPG-KEY-puppetlabs',
    priority       => 1,
  }

  # The dependencies repo has the same priority as base,
  # because it needs to override base packages.
  # E.g. puppet-3.0 requires Ruby => 1.8.7, but EL5 ships with 1.8.5.
  #
  yum::managed_yumrepo { 'puppetlabs_dependencies':
    descr          => 'Puppet Labs Packages',
    baseurl        => "http://yum.puppetlabs.com/el/${release}/dependencies/\$basearch",
    enabled        => 1,
    gpgcheck       => 1,
    failovermethod => 'priority',
    gpgkey         => 'http://yum.puppetlabs.com/RPM-GPG-KEY-puppetlabs',
    priority       => 1,
  }

}
# = Class: yum::repo::rbel
#
# This class installs the rbel repo
#
class yum::repo::rbel {

  $osver = split($::operatingsystemrelease, '[.]')
  yum::managed_yumrepo { 'rbel':
    descr          => 'RBEL Repo',
    baseurl        => "http://rbel.frameos.org/stable/el${osver[0]}/\$basearch",
    enabled        => 1,
    gpgcheck       => 0,
    failovermethod => 'priority',
    gpgkey         => 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-RBEL' ,
    gpgkey_source  => 'puppet:///modules/yum/rpm-gpg/RPM-GPG-KEY-RBEL',
    priority       => 16,
  }

}

# = Class: yum::repo::remi
#
# This class installs the remi repo
#
class yum::repo::remi {
  yum::managed_yumrepo { 'remi':
    descr          => 'Les RPM de remi pour Enterpise Linux $releasever - $basearch',
    mirrorlist     => 'http://rpms.famillecollet.com/enterprise/$releasever/remi/mirror',
    enabled        => 1,
    gpgcheck       => 1,
    gpgkey         => 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-remi',
    gpgkey_source  => 'puppet:///modules/yum/rpm-gpg/RPM-GPG-KEY-remi',
    priority       => 1,
  }

  yum::managed_yumrepo { 'remi-test':
    descr          => 'Les RPM de remi pour Enterpise Linux $releasever - $basearch - Test',
    mirrorlist     => 'http://rpms.famillecollet.com/enterprise/$releasever/test/mirror',
    enabled        => 0,
    gpgcheck       => 1,
    gpgkey         => 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-remi',
    gpgkey_source  => 'puppet:///modules/yum/rpm-gpg/RPM-GPG-KEY-remi',
    priority       => 1,
  }
}
# = Class: yum::repo::remi_php55
#
# This class installs the remi-php55 repo
#
class yum::repo::remi_php55 {
  yum::managed_yumrepo { 'remi-php55':
    descr          => 'Les RPM de remi pour Enterpise Linux $releasever - $basearch - PHP 5.5',
    mirrorlist     => 'http://rpms.famillecollet.com/enterprise/$releasever/php55/mirror',
    enabled        => 1,
    gpgcheck       => 1,
    gpgkey         => 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-remi',
    gpgkey_source  => 'puppet:///modules/yum/rpm-gpg/RPM-GPG-KEY-remi',
    priority       => 1,
  }
}
# = Class: yum::repo::repoforge
#
# This class installs the repoforge repo
#
class yum::repo::repoforge {

  yum::managed_yumrepo { 'repoforge':
    descr          => 'RepoForge packages',
    baseurl        => 'http://mirror.team-cymru.org/repoforge/redhat/el$releasever/en/$basearch/rpmforge',
    enabled        => 1,
    gpgcheck       => 1,
    gpgkey         => 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-rpmforge-dag',
    gpgkey_source  => 'puppet:///modules/yum/rpm-gpg/RPM-GPG-KEY-rpmforge-dag',
    priority       => 1,
    exclude        => 'nagios-*',
  }

}
# = Class: yum::repo::repoforgeextras
#
# This class installs the repoforge extras repo
#
class yum::repo::repoforgeextras {

  yum::managed_yumrepo { 'repoforgeextras':
    descr    => 'RepoForge extra packages',
    baseurl  => 'http://mirror.team-cymru.org/repoforge/redhat/el$releasever/en/$basearch/extras',
    enabled  => 1,
    gpgcheck => 1,
    gpgkey   => 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-rpmforge-dag',
    priority => 1,
    exclude  => 'perl-IO-Compress-* perl-DBD-MySQL',
  }

}
# = Class: yum::repo::rpmforge
#
# This class installs the rpmforce repo
#
class yum::repo::rpmforge {

  yum::managed_yumrepo { 'rpmforge-rhel5':
    descr          => 'RPMForge RHEL5 packages',
    baseurl        => 'http://wftp.tu-chemnitz.de/pub/linux/dag/redhat/el$releasever/en/$basearch/dag',
    enabled        => 1,
    gpgcheck       => 1,
    gpgkey         => 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-rpmforge-dag',
    gpgkey_source  => 'puppet:///modules/yum/rpm-gpg/RPM-GPG-KEY-rpmforge-dag',
    priority       => 30,
  }

}
# = Class: yum::repo::sl5
#
# Base Scientific Linux 5 repos
#
# == Parameters:
#
# [*mirror_url*]
#   A clean URL to a mirror of `http://ftp.scientificlinux.org/linux/scientific/`.
#   The paramater is interpolated with the known directory structure to
#   create a the final baseurl parameter for each yumrepo so it must be
#   "clean", i.e., without a query string like `?key1=valA&key2=valB`.
#   Additionally, it may not contain a trailing slash.
#   Example: `http://mirror.example.com/pub/rpm/scientific`
#   Default: `undef`
#
class yum::repo::sl5 (
  $mirror_url = undef,
) {

  if $mirror_url {
    validate_re(
      $mirror_url,
      '^(?:https?|ftp):\/\/[\da-zA-Z-][\da-zA-Z\.-]*\.[a-zA-Z]{2,6}\.?(?:\/[\w~-]*)*$',
      '$mirror must be a Clean URL with no query-string, a fully-qualified hostname and no trailing slash.'
    )
  }

  $baseurl_sl5x = $mirror_url ? {
    undef   => undef,
    default => "${mirror_url}/5x/\$basearch/os/",
  }

  $baseurl_sl5x_security = $mirror_url ? {
    undef   => undef,
    default => "${mirror_url}/5x/\$basearch/updates/security/",
  }

  $baseurl_sl5x_fastbugs = $mirror_url ? {
    undef   => undef,
    default => "${mirror_url}/5x/\$basearch/updates/fastbugs/",
  }

  yum::managed_yumrepo { 'sl5x':
    descr          => 'Scientific Linux 5x - $basearch',
    baseurl        => $baseurl_sl5x,
    mirrorlist     => 'http://ftp.scientificlinux.org/linux/scientific/mirrorlist/sl-base-5x.txt',
    failovermethod => 'priority',
    enabled        => 1,
    gpgcheck       => 1,
    gpgkey         => 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-sl file:///etc/pki/rpm-gpg/RPM-GPG-KEY-dawson',
    gpgkey_source  => 'puppet:///modules/yum/rpm-gpg/RPM-GPG-KEY-sl',
    priority       => 10,
  }

  yum::managed_yumrepo { 'sl5x-security':
    descr          => 'Scientific Linux 5x - $basearch - security updates',
    baseurl        => $baseurl_sl5x_security,
    mirrorlist     => 'http://ftp.scientificlinux.org/linux/scientific/mirrorlist/sl-security-5x.txt',
    failovermethod => 'priority',
    enabled        => 1,
    gpgcheck       => 1,
    gpgkey         => 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-sl file:///etc/pki/rpm-gpg/RPM-GPG-KEY-dawson',
    priority       => 10,
  }

  yum::managed_yumrepo { 'sl5x-fastbugs':
    descr          => 'Scientific Linux 5x - $basearch - fastbug updates',
    baseurl        => $baseurl_sl5x_fastbugs,
    mirrorlist     => 'http://ftp.scientificlinux.org/linux/scientific/mirrorlist/sl-fastbugs-5x.txt',
    failovermethod => 'priority',
    enabled        => 0,
    gpgcheck       => 1,
    gpgkey         => 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-sl file:///etc/pki/rpm-gpg/RPM-GPG-KEY-dawson',
    priority       => 10,
  }

}
# = Class: yum::repo::sl6
#
# Base Scientific Linux 6 repos
#
# == Parameters:
#
# [*mirror_url*]
#   A clean URL to a mirror of `http://ftp.scientificlinux.org/linux/scientific/`.
#   The paramater is interpolated with the known directory structure to
#   create a the final baseurl parameter for each yumrepo so it must be
#   "clean", i.e., without a query string like `?key1=valA&key2=valB`.
#   Additionally, it may not contain a trailing slash.
#   Example: `http://mirror.example.com/pub/rpm/scientific`
#   Default: `undef`
#
class yum::repo::sl6 (
  $mirror_url = undef,
) {

  if $mirror_url {
    validate_re(
      $mirror_url,
      '^(?:https?|ftp):\/\/[\da-zA-Z-][\da-zA-Z\.-]*\.[a-zA-Z]{2,6}\.?(?:\/[\w~-]*)*$',
      '$mirror must be a Clean URL with no query-string, a fully-qualified hostname and no trailing slash.'
    )
  }

  $baseurl_sl6x = $mirror_url ? {
    undef   => undef,
    default => "${mirror_url}/6x/\$basearch/os/",
  }

  $baseurl_sl6x_security = $mirror_url ? {
    undef   => undef,
    default => "${mirror_url}/6x/\$basearch/updates/security/",
  }

  $baseurl_sl6x_fastbugs = $mirror_url ? {
    undef   => undef,
    default => "${mirror_url}/6x/\$basearch/updates/fastbugs/",
  }

  yum::managed_yumrepo { 'sl6x':
    descr          => 'Scientific Linux 6x - $basearch',
    baseurl        => $baseurl_sl6x,
    mirrorlist     => 'http://ftp.scientificlinux.org/linux/scientific/mirrorlist/sl-base-6x.txt',
    failovermethod => 'priority',
    enabled        => 1,
    gpgcheck       => 1,
    gpgkey         => 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-sl file:///etc/pki/rpm-gpg/RPM-GPG-KEY-dawson',
    gpgkey_source  => 'puppet:///modules/yum/rpm-gpg/RPM-GPG-KEY-sl',
  }

  yum::managed_yumrepo { 'sl6x-security':
    descr          => 'Scientific Linux 6x - $basearch - security updates',
    baseurl        => $baseurl_sl6x_security,
    mirrorlist     => 'http://ftp.scientificlinux.org/linux/scientific/mirrorlist/sl-security-6x.txt',
    failovermethod => 'priority',
    enabled        => 1,
    gpgcheck       => 1,
    gpgkey         => 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-sl file:///etc/pki/rpm-gpg/RPM-GPG-KEY-dawson',
  }

  yum::managed_yumrepo { 'sl6x-fastbugs':
    descr          => 'Scientific Linux 6x - $basearch - fastbug updates',
    baseurl        => $baseurl_sl6x_fastbugs,
    mirrorlist     => 'http://ftp.scientificlinux.org/linux/scientific/mirrorlist/sl-fastbugs-6x.txt',
    failovermethod => 'priority',
    enabled        => 0,
    gpgcheck       => 1,
    gpgkey         => 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-sl file:///etc/pki/rpm-gpg/RPM-GPG-KEY-dawson',
  }

}
# = Class: yum::repo::tmz
#
# This class installs the tmz repo
#
class yum::repo::tmz {

  yum::managed_yumrepo { 'tmz-puppet':
    descr          => 'Puppet for EL $releasever - $basearch',
    baseurl        => 'http://tmz.fedorapeople.org/repo/puppet/epel/$releasever/$basearch',
    enabled        => 1,
    gpgcheck       => 1,
    failovermethod => 'priority',
    gpgkey         => 'http://tmz.fedorapeople.org/repo/RPM-GPG-KEY-tmz',
    priority       => 16,
  }

  yum::managed_yumrepo { 'tmz-puppet-source':
    descr          => 'Puppet for EL $releasever - Source',
    baseurl        => 'http://tmz.fedorapeople.org/repo/puppet/epel/$releasever/SRPMS',
    enabled        => 0,
    gpgcheck       => 1,
    failovermethod => 'priority',
    gpgkey         => 'http://tmz.fedorapeople.org/repo/RPM-GPG-KEY-tmz',
    priority       => 16,
  }

}
# = Class: yum::repo::varnish
#
# This class installs the varnish 3.0 repo
#
class yum::repo::varnish {

  yum::managed_yumrepo { 'varnish':
    descr          => 'Varnish 3.0 for Enterprise Linux 5 - $basearch',
    baseurl        => 'http://repo.varnish-cache.org/redhat/varnish-3.0/el5/$basearch',
    enabled        => 1,
    gpgcheck       => 0,
    failovermethod => 'priority',
    # gpgkey       => 'http://yum.theforeman.org/RPM-GPG-KEY-VARNISH',
    priority       => 26,
  }

}
# = Class: yum::repo::vfabric
#
# This class installs the vfabric repo
#
class yum::repo::vfabric {

  $osver = split($::operatingsystemrelease, '[.]')

  yum::managed_yumrepo { 'vfabric':
    descr          => 'vFabric 5.2 Repo - $basesearch',
    baseurl        => "http://repo.vmware.com/pub/rhel${osver[0]}/vfabric/5.2/\$basearch",
    enabled        => 1,
    gpgcheck       => 1,
    failovermethod => 'priority',
    gpgkey         => "http://repo.vmware.com/pub/rhel${osver[0]}/vfabric/5.2/RPM-GPG-KEY-VFABRIC-5.2-EL${osver[0]}",
    priority       => 1,
  }

}

# = Class: yum::repo::virtualbox
#
# This class installs the virtualbox repo
#
class yum::repo::virtualbox {

  yum::managed_yumrepo { 'virtualbox':
    descr          => 'RHEL/CentOS-$releasever / $basearch - VirtualBox',
    baseurl        => 'http://download.virtualbox.org/virtualbox/rpm/rhel/$releasever/$basearch',
    enabled        => 1,
    gpgcheck       => 1,
    failovermethod => 'priority',
    gpgkey         => 'http://download.virtualbox.org/virtualbox/debian/oracle_vbox.asc',
    autokeyimport  => 'yes',
    priority       => 18,
  }

}
# = Class: yum::repo::webtatic
#
# This class installs the webtatic repo
#
class yum::repo::webtatic {
  $osver = split($::operatingsystemrelease, '[.]')
  yum::managed_yumrepo { 'webtatic':
    descr          => 'Webtatic Repository $releasever - $basearch',
    mirrorlist     => $osver[0] ? {
      5 => 'http://repo.webtatic.com/yum/centos/5/$basearch/mirrorlist',
      6 => 'http://repo.webtatic.com/yum/el6/$basearch/mirrorlist',
    },
    enabled        => 1,
    gpgcheck       => 1,
    gpgkey         => 'file:///etc/pki/rpm-gpg/RPM-GPG-KEY-webtatic-andy',
    gpgkey_source  => 'puppet:///modules/yum/rpm-gpg/RPM-GPG-KEY-webtatic-andy',
    priority       => 1,
  }
}
# Class yum::updatesd
#
# Installs and enables yum updatesd
#
#
class yum::updatesd {

  require yum

  $manage_update_package = $yum::bool_update_disable ? {
    true    => absent,
    default => present,
  }

  $manage_update_service_ensure = $yum::bool_update_disable ? {
    true    => stopped,
    default => running,
  }

  $manage_update_service_enable = $yum::bool_update_disable ? {
    true    => false,
    default => true,
  }

  $manage_update_file = $yum::bool_update_disable ? {
    true    => absent,
    default => present,
  }

  package { 'yum-updatesd':
    ensure => $manage_update_package,
    name   => 'yum-updatesd',
  }

  service { 'yum-updatesd':
    ensure     => $manage_update_service_ensure,
    enable     => $manage_update_service_enable,
    hasstatus  => true,
    hasrestart => true,
    require    => Package['yum-updatesd'],
  }

  file { 'yum-updatesd.conf':
    ensure  => $manage_update_file,
    path    => '/etc/yum/yum-updatesd.conf',
    source  => 'puppet:///modules/yum/yum-updatesd.conf',
    require => Package['yum-updatesd'],
  }

}
require "#{File.join(File.dirname(__FILE__),'..','spec_helper.rb')}"

describe 'yum' do

  let(:title) { 'yum' }
  let(:node) { 'rspec.example42.com' }
  let(:facts) { { :ipaddress => '10.42.42.42' } }

  describe 'Test minimal installation' do
    it { should contain_file('yum.conf').with_ensure('present') }
  end

  describe 'Test decommissioning - absent' do
    let(:params) { {:absent => true } }
    it 'should remove yum configuration file' do should contain_file('yum.conf').with_ensure('absent') end
  end

  describe 'Test customizations - source' do
    let(:params) { {:source => "puppet:///modules/yum/spec"} }
    it { should contain_file('yum.conf').with_source('puppet:///modules/yum/spec') }
  end

end
require 'puppetlabs_spec_helper/module_spec_helper'
#
# File Managed by Puppet
#
# Pass any given paramter to yum, as run in all the scripts invoked
# by this package.  Be aware that this is global, and yum is invoked in 
# several modes by these scripts for which your own parameter might not
# be appropriate
YUM_PARAMETER=<%= scope.lookupvar('yum::cron_param') %>

# Don't install, just check (valid: yes|no)
CHECK_ONLY=no

# Check to see if you can reach the repos before updating (valid: yes|no)
CHECK_FIRST=no

# Don't install, just check and download (valid: yes|no)
# Implies CHECK_ONLY=yes (gotta check first to see what to download)
DOWNLOAD_ONLY=no

# Error level, practical range 0-10, 0 means print only critical errors which
# you must be told, 1 means print all errors, even ones that are not important
# Level 0 is the default
# ERROR_LEVEL=0

# Debug level, practical range 0-10, higher number means more output
# Level 1 is a useful level if you want to see what's been done and
# don't want to read /var/log/yum.log
# Level 0 is the default
# DEBUG_LEVEL=1

# randomwait is used by yum to wait random time
# default is 60 so yum waits random time from 1 to 60 minutes
# the value must not be zero
RANDOMWAIT="60"

# if MAILTO is set and the mail command is available, the mail command 
# is used to deliver yum output

# by default MAILTO is unset, so crond mails the output by itself
# example:  MAILTO=root
MAILTO=<%= scope.lookupvar('yum::cron_mailto') %>

# you may set SYSTEMNAME if you want your yum emails tagged differently
# default is output of hostname command 
# this variable is used only if MAILTO is set too
#SYSTEMNAME="" 

# you may set DAYS_OF_WEEK to the days of the week you want to run 
# default is every day 
#DAYS_OF_WEEK="0123456" 
DAYS_OF_WEEK=<%= scope.lookupvar('yum::cron_dotw') %>

# which day should it do cleanup on?  defaults to 0 (Sunday).  If this day isn't in the 
# DAYS_OF_WEEK above, it'll never happen
CLEANDAY="0"

# set to yes to make the yum-cron service to wait for transactions to complete
SERVICE_WAITS=yes

# set maximum time period (in seconds) for the yum-cron service to wait for
# transactions to complete.  The default is 300 seconds (5 minutes)
SERVICE_WAIT_TIME=300
if $yaml_values == undef { $yaml_values = loadyaml('/vagrant/puphpet/config.yaml') }
if $apache_values == undef { $apache_values = $yaml_values['apache'] }
if $php_values == undef { $php_values = hiera_hash('php', false) }
if $hhvm_values == undef { $hhvm_values = hiera_hash('hhvm', false) }

include puphpet::params

if hash_key_equals($apache_values, 'install', 1) {
  include apache::params

  if hash_key_equals($php_values, 'install', 1) and hash_key_equals($php_values, 'mod_php', 1) {
    $require_mod_php = true
    $apache_version  = $apache::version::default
  } else {
    $require_mod_php = false
    $apache_version  = '2.4'
  }

  if ! $require_mod_php {
    if $::operatingsystem == 'debian' {
      apache_debian_repo{ 'do': }
    } elsif $::operatingsystem == 'ubuntu' and $::lsbdistcodename == 'precise' {
      apt::ppa { 'ppa:ondrej/apache2': require => Apt::Key['4F4EA0AAE5267A6C'] }
    } elsif $::osfamily == 'redhat' {
      apache_centos{ 'do': }
    }
  }

  $webroot_location      = $puphpet::params::apache_webroot_location
  $apache_provider_types = [
    'virtualbox',
    'vmware_fusion',
    'vmware_desktop',
    'parallels'
  ]

  exec { "mkdir -p ${webroot_location}":
    creates => $webroot_location,
  }

  if downcase($::provisioner_type) in $apache_provider_types {
    $webroot_location_group = 'www-data'
    $vhost_docroot_group    = undef
  } else {
    $webroot_location_group = undef
    $vhost_docroot_group    = 'www-user'
  }

  if ! defined(File[$webroot_location]) {
    file { $webroot_location:
      ensure  => directory,
      group   => $webroot_location_group,
      mode    => 0775,
      require => [
        Exec["mkdir -p ${webroot_location}"],
        Group['www-data']
      ],
    }
  }

  if $require_mod_php {
    $mpm_module           = 'prefork'
    $disallowed_modules   = []
    $apache_php_package   = 'php'
    $fcgi_string          = ''
  } elsif hash_key_equals($hhvm_values, 'install', 1) {
    $mpm_module           = 'worker'
    $disallowed_modules   = ['php']
    $apache_php_package   = 'hhvm'
    $fcgi_string          = "127.0.0.1:${hhvm_values['settings']['port']}"
  } elsif hash_key_equals($php_values, 'install', 1) {
    $mpm_module           = 'worker'
    $disallowed_modules   = ['php']
    $apache_php_package   = 'php-fpm'
    $fcgi_string          = '127.0.0.1:9000'
  } else {
    $mpm_module           = 'prefork'
    $disallowed_modules   = []
    $apache_php_package   = ''
    $fcgi_string          = ''
  }

  $sendfile = $apache_values['settings']['sendfile'] ? {
    1       => 'On',
    default => 'Off'
  }

  $apache_settings = merge($apache_values['settings'], {
    'default_vhost'  => false,
    'mpm_module'     => $mpm_module,
    'conf_template'  => $apache::params::conf_template,
    'sendfile'       => $sendfile,
    'apache_version' => $apache_version
  })

  create_resources('class', { 'apache' => $apache_settings })

  if $require_mod_php and ! defined(Class['apache::mod::php']) {
    include apache::mod::php
  } elsif ! $require_mod_php {
    include puphpet::apache::fpm
  }

  if hash_key_equals($apache_values, 'mod_pagespeed', 1) {
    class { 'puphpet::apache::modpagespeed': }
  }

  if hash_key_equals($hhvm_values, 'install', 1)
    or hash_key_equals($php_values, 'install', 1)
  {
    $default_vhost_engine = 'php'
  } else {
    $default_vhost_engine = undef
  }

  if $apache_values['settings']['default_vhost'] == true {
    $apache_vhosts = merge($apache_values['vhosts'], {
      'default_vhost_80'  => {
        'servername'    => 'default',
        'docroot'       => '/var/www/default',
        'port'          => 80,
        'default_vhost' => true,
        'engine'        => $default_vhost_engine,
      },
      'default_vhost_443' => {
        'servername'    => 'default',
        'docroot'       => '/var/www/default',
        'port'          => 443,
        'default_vhost' => true,
        'ssl'           => 1,
        'engine'        => $default_vhost_engine,
      },
    })
  } else {
    $apache_vhosts = $apache_values['vhosts']
  }

  if count($apache_vhosts) > 0 {
    each( $apache_vhosts ) |$key, $vhost| {
      exec { "exec mkdir -p ${vhost['docroot']} @ key ${key}":
        command => "mkdir -p ${vhost['docroot']}",
        creates => $vhost['docroot'],
      }

      if ! defined(File[$vhost['docroot']]) {
        file { $vhost['docroot']:
          ensure  => directory,
          group   => $vhost_docroot_group,
          mode    => 0765,
          require => [
            Exec["exec mkdir -p ${vhost['docroot']} @ key ${key}"],
            Group['www-user']
          ]
        }
      }

      $vhost_merged = delete(merge($vhost, {
        'custom_fragment' => template('puphpet/apache/custom_fragment.erb'),
        'ssl'             => 'ssl' in $vhost and str2bool($vhost['ssl']) ? { true => true, default => false },
        'ssl_cert'        => hash_key_true($vhost, 'ssl_cert')      ? { true => $vhost['ssl_cert'],      default => $puphpet::params::ssl_cert_location },
        'ssl_key'         => hash_key_true($vhost, 'ssl_key')       ? { true => $vhost['ssl_key'],       default => $puphpet::params::ssl_key_location },
        'ssl_chain'       => hash_key_true($vhost, 'ssl_chain')     ? { true => $vhost['ssl_chain'],     default => undef },
        'ssl_certs_dir'   => hash_key_true($vhost, 'ssl_certs_dir') ? { true => $vhost['ssl_certs_dir'], default => undef }
      }), 'engine')

      create_resources(apache::vhost, { "${key}" => $vhost_merged })

      if ! defined(Firewall["100 tcp/${vhost['port']}"]) {
        firewall { "100 tcp/${vhost['port']}":
          port   => $vhost['port'],
          proto  => tcp,
          action => 'accept',
        }
      }
    }
  }


  if $::osfamily == 'debian' and ! $require_mod_php {
    file { ['/var/run/apache2/ssl_mutex']:
      ensure  => directory,
      group   => 'www-data',
      mode    => 0775,
      require => Class['apache'],
      notify  => Service['httpd'],
    }
  }

  if ! defined(Firewall['100 tcp/443']) {
    firewall { '100 tcp/443':
      port   => 443,
      proto  => tcp,
      action => 'accept',
    }
  }

  if count($apache_values['modules']) > 0 {
    apache_mod { $apache_values['modules']: }
  }

  class { 'puphpet::ssl_cert':
    require => Class['apache'],
    notify  => Service['httpd'],
  }
}

define apache_debian_repo {
  apt::source { 'd7031.de':
    location          => 'http://www.d7031.de/debian/',
    release           => 'wheezy-experimental',
    repos             => 'main',
    required_packages => 'debian-keyring debian-archive-keyring',
    key               => '9EB5E8A3DF17D0B3',
    key_server        => 'keys.gnupg.net',
    include_src       => true
  }
}

define apache_centos {
  $httpd_url               = 'http://repo.puphpet.com/centos/httpd24/httpd-2.4.10-RPM-full.x86_64.tgz'
  $httpd_download_location = '/.puphpet-stuff/httpd-2.4.10-RPM-full.x86_64.tgz'
  $httpd_tar               = "tar xzvf '${httpd_download_location}'"
  $extract_location        = '/.puphpet-stuff/httpd-2.4.10-RPM-full.x86_64'

  exec { 'download httpd-2.4.10':
    creates => $httpd_download_location,
    command => "wget --quiet --tries=5 --connect-timeout=10 -O '${httpd_download_location}' '${httpd_url}'",
    timeout => 3600,
    path    => '/usr/bin',
  } ->
  exec { 'untar httpd-2.4.10':
    creates => $extract_location,
    command => $httpd_tar,
    cwd     => '/.puphpet-stuff',
    path    => '/bin',
  } ->
  exec { 'install httpd-2.4.10':
    creates => '/etc/httpd',
    command => 'yum -y localinstall * --skip-broken',
    cwd     => $extract_location,
    path    => '/usr/bin',
  }

  exec { 'rm /etc/httpd/conf.d/systemd.load':
    path    => ['/usr/bin', '/usr/sbin', '/bin'],
    onlyif  => 'test -f /etc/httpd/conf.d/systemd.load',
    require => Class['apache'],
    notify  => Service['httpd'],
  }
}

define apache_mod {
  if ! defined(Class["apache::mod::${name}"]) and !($name in $disallowed_modules) {
    class { "apache::mod::${name}": }
  }
}
if $beanstalkd_values == undef { $beanstalkd_values = hiera_hash('beanstalkd', false) }
if $php_values == undef { $php_values = hiera_hash('php', false) }
if $hhvm_values == undef { $hhvm_values = hiera_hash('hhvm', false) }
if $apache_values == undef { $apache_values = hiera_hash('apache', false) }
if $nginx_values == undef { $nginx_values = hiera_hash('nginx', false) }

include puphpet::params

if hash_key_equals($apache_values, 'install', 1) {
  $beanstalk_console_webroot_location = '/var/www/default/beanstalk_console'
} elsif hash_key_equals($nginx_values, 'install', 1) {
  $beanstalk_console_webroot_location = "${puphpet::params::nginx_webroot_location}/beanstalk_console"
} else {
  $beanstalk_console_webroot_location = undef
}

if hash_key_equals($php_values, 'install', 1) or hash_key_equals($hhvm_values, 'install', 1) {
  $beanstalkd_php_installed = true
} else {
  $beanstalkd_php_installed = false
}

if hash_key_equals($beanstalkd_values, 'install', 1) {
  create_resources(beanstalkd::config, { 'beanstalkd' => $beanstalkd_values['settings'] })

  if hash_key_equals($beanstalkd_values, 'beanstalk_console', 1)
    and $beanstalk_console_webroot_location != undef
    and $beanstalkd_php_installed
  {
    exec { 'delete-beanstalk_console-path-if-not-git-repo':
      command => "rm -rf ${beanstalk_console_webroot_location}",
      onlyif  => "test ! -d ${beanstalk_console_webroot_location}/.git"
    }

    vcsrepo { $beanstalk_console_webroot_location:
      ensure   => present,
      provider => git,
      source   => 'https://github.com/ptrofimov/beanstalk_console.git',
      require  => Exec['delete-beanstalk_console-path-if-not-git-repo']
    }

    file { "${beanstalk_console_webroot_location}/storage.json":
      ensure  => present,
      group   => 'www-data',
      mode    => 0775,
      require => Vcsrepo[$beanstalk_console_webroot_location]
    }
  }
}
if $drush_values == undef { $drush_values = hiera_hash('drush', false) }
if $php_values == undef { $php_values = hiera_hash('php', false) }
if $hhvm_values == undef { $hhvm_values = hiera_hash('hhvm', false) }

include puphpet::params

if hash_key_equals($drush_values, 'install', 1) {
  if $drush_values['version'] != undef
    and (hash_key_equals($php_values, 'install', 1)
          or hash_key_equals($hhvm_values, 'install', 1))
    and (hash_key_equals($php_values, 'composer', 1)
          or hash_key_equals($hhvm_values, 'composer', 1))
  {
    $drush_github   = 'https://github.com/drush-ops/drush.git'
    $drush_location = '/usr/share/drush'

    exec { 'delete-drush-path-if-not-git-repo':
      command => "rm -rf ${drush_location}",
      onlyif  => "test ! -d ${drush_location}/.git",
      path    => [ '/bin/', '/sbin/', '/usr/bin/', '/usr/sbin/' ],
    } ->
    vcsrepo { $drush_location:
      ensure   => present,
      provider => git,
      source   => $drush_github,
      revision => $drush_values['version'],
    } ->
    composer::exec { 'drush':
      cmd     => 'install',
      cwd     => $drush_location,
      require => Vcsrepo[$drush_location],
    } ->
    exec { 'first drush run':
      command => 'drush cache-clear drush',
      path    => [ '/bin/', '/sbin/', '/usr/bin/', '/usr/sbin/', $drush_location ],
    } ->
    file { 'symlink drush':
      ensure => link,
      path   => '/usr/bin/drush',
      target => "${drush_location}/drush",
    }
  }
}
if $elasticsearch_values == undef { $elasticsearch_values = hiera_hash('elastic_search', false) }

include puphpet::params

if hash_key_equals($elasticsearch_values, 'install', 1) {
  $es_version = $elasticsearch_values['settings']['version']

  case $::osfamily {
    'debian': { $elasticsearch_package_url = "https://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-${es_version}.deb" }
    'redhat': { $elasticsearch_package_url = "https://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-${es_version}.noarch.rpm" }
    default:  { fail('Unrecognized operating system for Elastic Search') }
  }

  if ! defined(Class['java']) and $elasticsearch_values['settings']['java_install'] {
    class { 'java':
      distribution => 'jre',
    }
  }

  $elasticsearch_settings = delete(merge($elasticsearch_values['settings'], {
    'java_install' => false,
    'package_url'  => $elasticsearch_package_url,
    require        => Class['my_fw::post'],
  }), 'version')

  create_resources('class', { 'elasticsearch' => $elasticsearch_settings })
}
if $firewall_values == undef { $firewall_values = hiera_hash('firewall', false) }
if $vm_values == undef { $vm_values = hiera_hash($::vm_target_key, false) }

include puphpet::params

Firewall {
  before  => Class['my_fw::post'],
  require => Class['my_fw::pre'],
}

class { ['my_fw::pre', 'my_fw::post']: }

class { 'firewall': }

class my_fw::pre {
  Firewall {
    require => undef,
  }

  # Default firewall rules
  firewall { '000 accept all icmp':
    proto  => 'icmp',
    action => 'accept',
  }->
  firewall { '001 accept all to lo interface':
    proto   => 'all',
    iniface => 'lo',
    action  => 'accept',
  }->
  firewall { '002 accept related established rules':
    proto  => 'all',
    state  => ['RELATED', 'ESTABLISHED'],
    action => 'accept',
  }
}

class my_fw::post {
  firewall { '999 drop all':
    proto   => 'all',
    action  => 'drop',
    before  => undef,
  }
}

if is_hash($firewall_values['rules']) and count($firewall_values['rules']) > 0 {
  each( $firewall_values['rules'] ) |$key, $rule| {
    if ! defined(Firewall["${rule['priority']} ${rule['proto']}/${rule['port']}"]) {
      firewall { "${rule['priority']} ${rule['proto']}/${rule['port']}":
        port   => $rule['port'],
        proto  => $rule['proto'],
        action => $rule['action'],
      }
    }
  }
}

if has_key($vm_values, 'ssh') and has_key($vm_values['ssh'], 'port') {
  $vm_values_ssh_port = $vm_values['ssh']['port'] ? {
    ''      => 22,
    undef   => 22,
    0       => 22,
    default => $vm_values['ssh']['port']
  }

  if ! defined(Firewall["100 tcp/${vm_values_ssh_port}"]) {
    firewall { "100 tcp/${vm_values_ssh_port}":
      port   => $vm_values_ssh_port,
      proto  => tcp,
      action => 'accept',
      before => Class['my_fw::post']
    }
  }
}

if has_key($vm_values, 'vm')
  and has_key($vm_values['vm'], 'network')
  and has_key($vm_values['vm']['network'], 'forwarded_port')
{
  create_resources( iptables_port, $vm_values['vm']['network']['forwarded_port'] )
}

define iptables_port (
  $host,
  $guest,
) {
  if ! defined(Firewall["100 tcp/${guest}"]) {
    firewall { "100 tcp/${guest}":
      port   => $guest,
      proto  => tcp,
      action => 'accept',
    }
  }
}
if $hhvm_values == undef { $hhvm_values = hiera_hash('hhvm', false) }
if $apache_values == undef { $apache_values = hiera_hash('apache', false) }
if $nginx_values == undef { $nginx_values = hiera_hash('nginx', false) }

include puphpet::params
include puphpet::supervisord

if hash_key_equals($hhvm_values, 'install', 1) {
  if hash_key_equals($apache_values, 'install', 1) {
    $hhvm_webserver         = 'httpd'
    $hhvm_webserver_restart = true
  } elsif hash_key_equals($nginx_values, 'install', 1) {
    $hhvm_webserver         = 'nginx'
    $hhvm_webserver_restart = true
  } else {
    $hhvm_webserver         = undef
    $hhvm_webserver_restart = true
  }

  class { 'puphpet::hhvm':
    nightly   => $hhvm_values['nightly'],
    webserver => $hhvm_webserver
  }

  if ! defined(User['hhvm']) {
    user { 'hhvm':
      home       => '/home/hhvm',
      groups     => 'www-data',
      ensure     => present,
      managehome => true,
      require    => Group['www-data']
    }
  }

  $supervisord_hhvm_cmd = "hhvm --mode server -vServer.Type=fastcgi -vServer.Port=${hhvm_values['settings']['port']}"

  supervisord::program { 'hhvm':
    command     => $supervisord_hhvm_cmd,
    priority    => '100',
    user        => 'hhvm',
    autostart   => true,
    autorestart => 'true',
    environment => { 'PATH' => '/bin:/sbin:/usr/bin:/usr/sbin' },
    require     => [
      User['hhvm'],
      Package['hhvm']
    ]
  }

  file { '/usr/bin/php':
    ensure  => 'link',
    target  => '/usr/bin/hhvm',
    require => Package['hhvm']
  }

  if count($hhvm_values['ini']) > 0 {
    $hhvm_inis = merge({
      'date.timezone' => $hhvm_values['timezone'],
    }, $hhvm_values['ini'])

    $hhvm_ini = '/etc/hhvm/php.ini'

    each( $hhvm_inis ) |$key, $value| {
      exec { "hhvm-php.ini@${key}/${value}":
        command => "perl -p -i -e 's#${key} = .*#${key} = ${value}#gi' ${hhvm_ini}",
        onlyif  => "test -f ${hhvm_ini}",
        unless  => "grep -x '${key} = ${value}' ${hhvm_ini}",
        path    => [ '/bin/', '/sbin/', '/usr/bin/', '/usr/sbin/' ],
        require => Package['hhvm'],
        notify  => Supervisord::Supervisorctl['restart_hhvm'],
      }
    }

    supervisord::supervisorctl { 'restart_hhvm':
      command     => 'restart',
      process     => 'hhvm',
      refreshonly => true,
    }
  }

  if hash_key_equals($hhvm_values, 'composer', 1)
    and ! defined(Class['puphpet::php::composer'])
  {
    class { 'puphpet::php::composer':
      php_package   => 'hhvm',
      composer_home => $hhvm_values['composer_home'],
    }
  }
}
if $mailcatcher_values == undef { $mailcatcher_values = hiera_hash('mailcatcher', false) }

include puphpet::params
include puphpet::supervisord

if hash_key_equals($mailcatcher_values, 'install', 1) {
  if ! defined(Package['tilt']) {
    package { 'tilt':
      ensure   => '1.3',
      provider => 'gem',
      before   => Class['mailcatcher']
    }
  }

  if $::operatingsystem == 'ubuntu' and $lsbdistcodename == 'trusty' {
    package { 'rubygems':
      ensure => absent,
    }
  }

  $mailcatcher_settings = delete($mailcatcher_values['settings'], 'from_email_method')

  create_resources('class', { 'mailcatcher' => $mailcatcher_settings })

  if ! defined(Firewall["100 tcp/${mailcatcher_settings['smtp_port']}, ${mailcatcher_settings['http_port']}"]) {
    firewall { "100 tcp/${mailcatcher_settings['smtp_port']}, ${mailcatcher_settings['http_port']}":
      port   => [$mailcatcher_settings['smtp_port'], $mailcatcher_settings['http_port']],
      proto  => tcp,
      action => 'accept',
    }
  }

  $mailcatcher_path = $mailcatcher_settings['mailcatcher_path']

  $mailcatcher_options = sort(join_keys_to_values({
    ' --smtp-ip'   => $mailcatcher_settings['smtp_ip'],
    ' --smtp-port' => $mailcatcher_settings['smtp_port'],
    ' --http-ip'   => $mailcatcher_settings['http_ip'],
    ' --http-port' => $mailcatcher_settings['http_port']
  }, ' '))

  supervisord::program { 'mailcatcher':
    command     => "${mailcatcher_path}/mailcatcher ${mailcatcher_options} -f",
    priority    => '100',
    user        => 'mailcatcher',
    autostart   => true,
    autorestart => 'true',
    environment => {
      'PATH' => "/bin:/sbin:/usr/bin:/usr/sbin:${mailcatcher_path}"
    },
    require => [
      Class['mailcatcher::config'],
      File['/var/log/mailcatcher']
    ],
  }
}
if $mariadb_values == undef { $mariadb_values = hiera_hash('mariadb', false) }
if $php_values == undef { $php_values = hiera_hash('php', false) }
if $hhvm_values == undef { $hhvm_values = hiera_hash('hhvm', false) }
if $apache_values == undef { $apache_values = hiera_hash('apache', false) }
if $nginx_values == undef { $nginx_values = hiera_hash('nginx', false) }

include puphpet::params

if hash_key_equals($mariadb_values, 'install', 1) {
  include mysql::params

  if hash_key_equals($apache_values, 'install', 1)
    or hash_key_equals($nginx_values, 'install', 1)
  {
    $mariadb_webserver_restart = true
  } else {
    $mariadb_webserver_restart = false
  }

  if hash_key_equals($php_values, 'install', 1) {
    $mariadb_php_installed = true
    $mariadb_php_package   = 'php'
  } elsif hash_key_equals($hhvm_values, 'install', 1) {
    $mariadb_php_installed = true
    $mariadb_php_package   = 'hhvm'
  } else {
    $mariadb_php_installed = false
  }

  if has_key($mariadb_values, 'root_password') and $mariadb_values['root_password'] {
    if ! defined(File[$mysql::params::datadir]) {
      file { $mysql::params::datadir:
        ensure => directory,
        group  => $mysql::params::root_group,
        before => Class['mysql::server']
      }
    }

    if ! defined(Group['mysql']) {
      group { 'mysql':
        ensure => present
      }
    }

    if ! defined(User['mysql']) {
      user { 'mysql':
        ensure => present,
      }
    }

    if (! defined(File['/var/run/mysqld'])) {
      file { '/var/run/mysqld' :
        ensure  => directory,
        group   => 'mysql',
        owner   => 'mysql',
        before  => Class['mysql::server'],
        require => [User['mysql'], Group['mysql']],
        notify  => Service['mysql'],
      }
    }

    if ! defined(File[$mysql::params::socket]) {
      file { $mysql::params::socket :
        ensure  => file,
        group   => $mysql::params::root_group,
        before  => Class['mysql::server'],
        require => File[$mysql::params::datadir]
      }
    }

    if ! defined(Package['mysql-libs']) {
      package { 'mysql-libs':
        ensure => purged,
        before => Class['mysql::server'],
      }
    }

    class { 'puphpet::mariadb':
      version => $mariadb_values['version']
    }

    $mariadb_override_options = empty($mariadb_values['override_options']) ? {
      true    => {},
      default => $mariadb_values['override_options']
    }

    class { 'mysql::server':
      package_name     => $puphpet::params::mariadb_package_server_name,
      root_password    => $mariadb_values['root_password'],
      service_name     => 'mysql',
      override_options => $mariadb_override_options
    }

    class { 'mysql::client':
      package_name => $puphpet::params::mariadb_package_client_name
    }

    if count($mariadb_values['databases']) > 0 {
      each( $mariadb_values['databases'] ) |$key, $database| {
        $database_merged = delete(merge($database, {
          'dbname' => $database['name'],
        }), 'name')

        create_resources( puphpet::mysql::db, {
          "${database['user']}@${database['name']}" => $database_merged
        })
      }
    }

    if $mariadb_php_installed and $mariadb_php_package == 'php' {
      if $::osfamily == 'redhat' and $php_values['version'] == '53' {
        $mariadb_php_module = 'mysql'
      } elsif $::lsbdistcodename == 'lucid' or $::lsbdistcodename == 'squeeze' {
        $mariadb_php_module = 'mysql'
      } else {
        $mariadb_php_module = 'mysqlnd'
      }

      if ! defined(Puphpet::Php::Module[$mariadb_php_module]) {
        puphpet::php::module { $mariadb_php_module:
          service_autorestart => $mariadb_webserver_restart,
        }
      }
    }
  }

  if hash_key_equals($mariadb_values, 'adminer', 1)
    and $mariadb_php_installed
    and ! defined(Class['puphpet::adminer'])
  {
    if hash_key_equals($apache_values, 'install', 1) {
      $mariadb_adminer_webroot_location = '/var/www/default'
    } elsif hash_key_equals($nginx_values, 'install', 1) {
      $mariadb_adminer_webroot_location = $puphpet::params::nginx_webroot_location
    } else {
      $mariadb_adminer_webroot_location = '/var/www/default'
    }

    class { 'puphpet::adminer':
      location    => "${mariadb_adminer_webroot_location}/adminer",
      owner       => 'www-data',
      php_package => $mariadb_php_package
    }
  }
}
if $mongodb_values == undef { $mongodb_values = hiera_hash('mongodb', false) }
if $php_values == undef { $php_values = hiera_hash('php', false) }
if $apache_values == undef { $apache_values = hiera_hash('apache', false) }
if $nginx_values == undef { $nginx_values = hiera_hash('nginx', false) }

include puphpet::params

if hash_key_equals($apache_values, 'install', 1)
  or hash_key_equals($nginx_values, 'install', 1)
{
  $mongodb_webserver_restart = true
} else {
  $mongodb_webserver_restart = false
}

if hash_key_equals($mongodb_values, 'install', 1) {
  file { ['/data', '/data/db']:
    ensure  => directory,
    mode    => 0775,
    before  => Class['mongodb::globals'],
  }

  Class['mongodb::globals']
  -> Class['mongodb::server']

  class { 'mongodb::globals':
    manage_package_repo => true,
  }

  create_resources('class', { 'mongodb::server' => $mongodb_values['settings'] })

  if $::osfamily == 'redhat' {
    class { 'mongodb::client':
      require => Class['mongodb::server']
    }
  }

  if count($mongodb_values['databases']) > 0 {
    each( $mongodb_values['databases'] ) |$key, $database| {
      $database_merged = delete(merge($database, {
        'dbname' => $database['name'],
      }), 'name')

      create_resources( mongodb_db, {
        "${database['user']}@${database['name']}" => $database_merged
      })
    }
  }

  if hash_key_equals($php_values, 'install', 1)
    and ! defined(Puphpet::Php::Pecl['mongo'])
  {
    puphpet::php::pecl { 'mongo':
      service_autorestart => $mongodb_webserver_restart,
      require             => Class['mongodb::server']
    }
  }
}

define mongodb_db (
  $dbname,
  $user,
  $password,
  $roles     = ['dbAdmin', 'readWrite', 'userAdmin'],
  $tries     = 10,
) {
  if ! value_true($name) or ! value_true($password) {
    fail( 'MongoDB requires that name and password be set. Please check your settings!' )
  }

  if ! defined(Mongodb_database[$dbname]) {
    mongodb_database { $dbname:
      ensure  => present,
      tries   => $tries,
      require => Class['mongodb::server'],
    }
  }

  $hash = mongodb_password($user, $password)

  if ! defined(Mongodb_user[$user]) {
    mongodb_user { $user:
      ensure        => present,
      password_hash => $hash,
      database      => $dbname,
      roles         => $roles,
      require       => Mongodb_database[$dbname],
    }
  }
}
if $mysql_values == undef { $mysql_values = hiera_hash('mysql', false) }
if $php_values == undef { $php_values = hiera_hash('php', false) }
if $apache_values == undef { $apache_values = hiera_hash('apache', false) }
if $nginx_values == undef { $nginx_values = hiera_hash('nginx', false) }

include puphpet::params

if hash_key_equals($mysql_values, 'install', 1) {
  include mysql::params

  if hash_key_equals($apache_values, 'install', 1)
    or hash_key_equals($nginx_values, 'install', 1)
  {
    $mysql_webserver_restart = true
  } else {
    $mysql_webserver_restart = false
  }

  if $::osfamily == 'redhat' {
    $rhel_mysql = 'http://dev.mysql.com/get/mysql-community-release-el6-5.noarch.rpm'
    exec { 'mysql-community-repo':
      command => "yum -y --nogpgcheck install '${rhel_mysql}' && touch /.puphpet-stuff/mysql-community-release",
      creates => '/.puphpet-stuff/mysql-community-release'
    }

    $mysql_server_require             = Exec['mysql-community-repo']
    $mysql_server_server_package_name = 'mysql-community-server'
    $mysql_server_client_package_name = 'mysql-community-client'
  } else {
    $mysql_server_require             = []
    $mysql_server_server_package_name = $mysql::params::server_package_name
    $mysql_server_client_package_name = $mysql::params::client_package_name
  }

  if hash_key_equals($php_values, 'install', 1) {
    $mysql_php_installed = true
    $mysql_php_package   = 'php'
  } elsif hash_key_equals($hhvm_values, 'install', 1) {
    $mysql_php_installed = true
    $mysql_php_package   = 'hhvm'
  } else {
    $mysql_php_installed = false
  }

  if $mysql_values['root_password'] {
    $mysql_override_options = empty($mysql_values['override_options']) ? {
      true    => {},
      default => $mysql_values['override_options']
    }

    class { 'mysql::server':
      package_name     => $mysql_server_server_package_name,
      root_password    => $mysql_values['root_password'],
      require          => $mysql_server_require,
      override_options => $mysql_override_options
    }

    class { 'mysql::client':
      package_name => $mysql_server_client_package_name,
      require      => $mysql_server_require
    }

    if count($mysql_values['databases']) > 0 {
      each( $mysql_values['databases'] ) |$key, $database| {
        $database_merged = delete(merge($database, {
          'dbname' => $database['name'],
        }), 'name')

        create_resources( puphpet::mysql::db, {
          "${key}" => $database_merged
        })
      }
    }

    if $mysql_php_installed and $mysql_php_package == 'php' {
      if $::osfamily == 'redhat' and $php_values['version'] == '53' {
        $mysql_php_module = 'mysql'
      } elsif $::lsbdistcodename == 'lucid' or $::lsbdistcodename == 'squeeze' {
        $mysql_php_module = 'mysql'
      } else {
        $mysql_php_module = 'mysqlnd'
      }

      if ! defined(Puphpet::Php::Module[$mysql_php_module]) {
        puphpet::php::module { $mysql_php_module:
          service_autorestart => $mysql_webserver_restart,
        }
      }
    }
  }

  if hash_key_equals($mysql_values, 'adminer', 1)
    and $mysql_php_installed
    and ! defined(Class['puphpet::adminer'])
  {
    if hash_key_equals($apache_values, 'install', 1) {
      $mysql_adminer_webroot_location = '/var/www/default'
    } elsif hash_key_equals($nginx_values, 'install', 1) {
      $mysql_adminer_webroot_location = $puphpet::params::nginx_webroot_location
    } else {
      $mysql_adminer_webroot_location = '/var/www/default'
    }

    class { 'puphpet::adminer':
      location    => "${mysql_adminer_webroot_location}/adminer",
      owner       => 'www-data',
      php_package => $mysql_php_package
    }
  }
}
if $yaml_values == undef { $yaml_values = loadyaml('/vagrant/puphpet/config.yaml') }
if $nginx_values == undef { $nginx_values = $yaml_values['nginx'] }
if $php_values == undef { $php_values = hiera_hash('php', false) }
if $hhvm_values == undef { $hhvm_values = hiera_hash('hhvm', false) }

include puphpet::params

if hash_key_equals($nginx_values, 'install', 1) {
  include nginx::params

  Class['puphpet::ssl_cert']
  -> Nginx::Resource::Vhost <| |>

  class { 'puphpet::ssl_cert': }

  $webroot_location     = $puphpet::params::nginx_webroot_location
  $nginx_provider_types = [
    'virtualbox',
    'vmware_fusion',
    'vmware_desktop',
    'parallels'
  ]

  exec { "mkdir -p ${webroot_location}":
    creates => $webroot_location,
  }

  if downcase($::provisioner_type) in $nginx_provider_types {
    $webroot_location_group = 'www-data'
    $vhost_docroot_group    = undef
  } else {
    $webroot_location_group = undef
    $vhost_docroot_group    = 'www-user'
  }

  if ! defined(File[$webroot_location]) {
    file { $webroot_location:
      ensure  => directory,
      group   => $webroot_location_group,
      mode    => 0775,
      require => [
        Exec["mkdir -p ${webroot_location}"],
        Group['www-data']
      ],
    }
  }

  if hash_key_equals($hhvm_values, 'install', 1) {
    $fcgi_string = "127.0.0.1:${hhvm_values['settings']['port']}"
  } elsif hash_key_equals($php_values, 'install', 1) {
    $fcgi_string = '127.0.0.1:9000'
  } else {
    $fcgi_string = false
  }

  if $::osfamily == 'redhat' {
    file { '/usr/share/nginx':
      ensure  => directory,
      mode    => 0775,
      owner   => 'www-data',
      group   => 'www-data',
      require => Group['www-data'],
      before  => Package['nginx']
    }
  }

  if hash_key_equals($hhvm_values, 'install', 1)
    or hash_key_equals($php_values, 'install', 1)
  {
    $default_vhost = {
      'server_name'          => '_',
      'server_aliases'       => [],
      'www_root'             => '/var/www/html',
      'proxy'                => '',
      'listen_port'          => 80,
      'location'             => '\.php$',
      'location_prepend'     => [],
      'location_append'      => [],
      'index_files'          => ['index', 'index.html', 'index.htm', 'index.php'],
      'envvars'              => [],
      'ssl'                  => '0',
      'ssl_cert'             => '',
      'ssl_key'              => '',
      'engine'               => 'php',
      'client_max_body_size' => '1m'
    }
  } else {
    $default_vhost = {
      'server_name'          => '_',
      'server_aliases'       => [],
      'www_root'             => '/var/www/html',
      'proxy'                => '',
      'listen_port'          => 80,
      'location'             => '/',
      'location_prepend'     => [],
      'location_append'      => [],
      'index_files'          => ['index', 'index.html', 'index.htm'],
      'envvars'              => [],
      'ssl'                  => '0',
      'ssl_cert'             => '',
      'ssl_key'              => '',
      'engine'               => false,
      'client_max_body_size' => '1m'
    }
  }

  class { 'nginx': }

  if hash_key_equals($nginx_values['settings'], 'default_vhost', 1) {
    $nginx_vhosts = merge($nginx_values['vhosts'], {
      'default' => $default_vhost,
    })

    if ! defined(File[$puphpet::params::nginx_default_conf_location]) {
      file { $puphpet::params::nginx_default_conf_location:
        ensure  => absent,
        require => Package['nginx'],
        notify  => Class['nginx::service'],
      }
    }
  } else {
    $nginx_vhosts = $nginx_values['vhosts']
  }

  if count($nginx_vhosts) > 0 {
    each( $nginx_vhosts ) |$key, $vhost| {
      if ! defined($vhost['proxy']) or $vhost['proxy'] == '' {
        exec { "exec mkdir -p ${vhost['www_root']} @ key ${key}":
          command => "mkdir -p ${vhost['www_root']}",
          creates => $vhost['www_root'],
        }

        if ! defined(File[$vhost['www_root']]) {
          file { $vhost['www_root']:
            ensure  => directory,
            group   => $vhost_docroot_group,
            mode    => 0765,
            require => [
              Exec["exec mkdir -p ${vhost['www_root']} @ key ${key}"],
              Group['www-user']
            ]
          }
        }
      }

      if ! defined(Firewall["100 tcp/${vhost['listen_port']}"]) {
        firewall { "100 tcp/${vhost['listen_port']}":
          port   => $vhost['listen_port'],
          proto  => tcp,
          action => 'accept',
        }
      }
    }

    create_resources(nginx_vhost, $nginx_vhosts)
  }

  if ! defined(Firewall['100 tcp/443']) {
    firewall { '100 tcp/443':
      port   => 443,
      proto  => tcp,
      action => 'accept',
    }
  }
}

if is_hash($nginx_values['upstreams']) and count($nginx_values['upstreams']) > 0 {
  notify{"Adding upstreams":}
  create_resources(nginx_upstream, $nginx_values['upstreams'])
}

define nginx_vhost (
  $server_name,
  $server_aliases       = [],
  $www_root,
  $listen_port,
  $location,
  $location_prepend     = [],
  $location_append      = [],
  $index_files,
  $envvars              = [],
  $ssl                  = false,
  $ssl_cert             = $puphpet::params::ssl_cert_location,
  $ssl_key              = $puphpet::params::ssl_key_location,
  $ssl_port             = '443',
  $rewrite_to_https     = false,
  $spdy                 = $nginx::params::nx_spdy,
  $engine               = false,
  $proxy                = undef,
  $client_max_body_size = '1m'
){
  $merged_server_name = concat([$server_name], $server_aliases)

  if is_array($index_files) and count($index_files) > 0 {
    $try_files_prepend = $index_files[count($index_files) - 1]
  } else {
    $try_files_prepend = ''
  }

  if $engine == 'php' {
    $try_files               = "${try_files_prepend} /index.php\$is_args\$args"
    $fastcgi_split_path_info = '^(.+\.php)(/.*)$'
    $fastcgi_index           = 'index.php'
    $fastcgi_param           = concat([
      'SCRIPT_FILENAME $request_filename'
    ], $envvars)
    $fastcgi_pass_hash       = value_true($fcgi_string) ? { true => {'fastcgi_pass' => $fcgi_string}, default => {} }
  } else {
    $try_files               = "${try_files_prepend} /index.html"
    $fastcgi_split_path_info = '^(.+\.html)(/.+)$'
    $fastcgi_index           = 'index.html'
    $fastcgi_param           = $envvars
    $fastcgi_pass_hash       = {}
  }

  $ssl_set              = value_true($ssl)              ? { true => true,      default => false, }
  $ssl_cert_set         = value_true($ssl_cert)         ? { true => $ssl_cert, default => $puphpet::params::ssl_cert_location, }
  $ssl_key_set          = value_true($ssl_key)          ? { true => $ssl_key,  default => $puphpet::params::ssl_key_location, }
  $ssl_port_set         = value_true($ssl_port)         ? { true => $ssl_port, default => '443', }
  $rewrite_to_https_set = value_true($rewrite_to_https) ? { true => true,      default => false, }
  $spdy_set             = value_true($spdy)             ? { true => on,        default => off, }
  $www_root_set         = value_true($proxy)            ? { true => undef, default => $www_root, }

  $location_cfg_append  = merge({
    'fastcgi_split_path_info' => $fastcgi_split_path_info,
    'fastcgi_param'           => $fastcgi_param,
    'fastcgi_index'           => $fastcgi_index,
    'include'                 => 'fastcgi_params'
  }, $fastcgi_pass_hash)

  nginx::resource::vhost { $server_name:
    server_name          => $merged_server_name,
    www_root             => $www_root_set,
    proxy                => $proxy,
    listen_port          => $listen_port,
    index_files          => $index_files,
    try_files            => ['$uri', '$uri/', "${try_files}"],
    ssl                  => $ssl_set,
    ssl_cert             => $ssl_cert_set,
    ssl_key              => $ssl_key_set,
    ssl_port             => $ssl_port_set,
    rewrite_to_https     => $rewrite_to_https_set,
    spdy                 => $spdy_set,
    vhost_cfg_append     => {sendfile => 'off'},
    client_max_body_size => $client_max_body_size
  }

  if $engine == 'php' and $www_root_set != undef {
    nginx::resource::location { "${server_name}-php":
      ensure                      => present,
      vhost                       => $server_name,
      location                    => "~ ${location}",
      proxy                       => undef,
      try_files                   => ['$uri', '$uri/', "/${try_files}\$is_args\$args"],
      ssl                         => $ssl_set,
      www_root                    => $www_root,
      location_cfg_append         => $location_cfg_append,
      location_custom_cfg_prepend => $location_prepend,
      location_custom_cfg_append  => $location_append,      
      notify                      => Class['nginx::service'],
    }
  }
}

define nginx_upstream (
  $name,
  $fail_timeout = '10s',
  $members      = []
) {
  $count = count($members);
  notify{"Adding nginx upstream for ${name} with ${count} members.": withpath => true}
  nginx::resource::upstream { $name:
    upstream_fail_timeout => $fail_timeout,
    members               => $members
  }
}
if $nodejs_values == undef { $nodejs_values = hiera_hash('nodejs', false) }

include puphpet::params

if hash_key_equals($nodejs_values, 'install', 1) {
  include puphpet::nodejs

  if is_array($nodejs_values['npm_packages']) and count($nodejs_values['npm_packages']) > 0 {
    each( $nodejs_values['npm_packages'] ) |$package| {
        $npm_array = split($package, '@')

        if count($npm_array) == 2 {
          $npm_ensure = $npm_array[1]
        } else {
          $npm_ensure = present
        }

      if ! defined(Package[$npm_array[0]]) {
        package { $npm_array[0]:
          ensure   => $npm_ensure,
          provider => npm,
        }
      }
    }
  }
}
if $php_values == undef { $php_values = hiera_hash('php', false) }
if $apache_values == undef { $apache_values = hiera_hash('apache', false) }
if $nginx_values == undef { $nginx_values = hiera_hash('nginx', false) }
if $mailcatcher_values == undef { $mailcatcher_values = hiera_hash('mailcatcher', false) }

include puphpet::params

if hash_key_equals($php_values, 'install', 1) {
  include php::params
  include apache::params
  include nginx::params

  class { 'puphpet::php::repos':
    php_version => $php_values['version']
  }

  Class['Php']
  -> Class['Php::Devel']
  -> Php::Module <| |>
  -> Php::Pear::Module <| |>
  -> Php::Pecl::Module <| |>

  $php_prefix = $::osfamily ? {
    'debian' => 'php5-',
    'redhat' => 'php-',
  }

  $php_fpm_ini = $::osfamily ? {
    'debian' => '/etc/php5/fpm/php.ini',
    'redhat' => '/etc/php.ini',
  }

  if hash_key_equals($apache_values, 'install', 1)
    and hash_key_equals($php_values, 'mod_php', 1)
  {
    $php_package                  = $php::params::package
    $php_webserver_service        = 'httpd'
    $php_webserver_service_ini    = $php_webserver_service
    $php_webserver_service_ensure = 'running'
    $php_webserver_restart        = true
    $php_config_file              = $php::params::config_file
    $php_manage_service           = false
  } elsif hash_key_equals($apache_values, 'install', 1)
    or hash_key_equals($nginx_values, 'install', 1)
  {
    $php_package                  = "${php_prefix}fpm"
    $php_webserver_service        = "${php_prefix}fpm"
    $php_webserver_service_ini    = $php_webserver_service
    $php_webserver_service_ensure = 'running'
    $php_webserver_restart        = true
    $php_config_file              = $php_fpm_ini
    $php_manage_service           = true

    exec { 'php_fpm-listen':
      command => "perl -p -i -e 's#listen = .*#listen = 127.0.0.1:9000#gi' ${puphpet::params::php_fpm_conf}",
      onlyif  => "test -f ${puphpet::params::php_fpm_conf}",
      unless  => "grep -x 'listen = 127.0.0.1:9000' ${puphpet::params::php_fpm_conf}",
      path    => [ '/bin/', '/sbin/', '/usr/bin/', '/usr/sbin/' ],
      require => Package[$php_package],
      notify  => Service[$php_webserver_service],
    }

    exec { 'php_fpm-security.limit_extensions':
      command => "perl -p -i -e 's#;security.limit_extensions = .*#security.limit_extensions = .php#gi' ${puphpet::params::php_fpm_conf}",
      onlyif  => "test -f ${puphpet::params::php_fpm_conf}",
      unless  => "grep -x 'security.limit_extensions = .php' ${puphpet::params::php_fpm_conf}",
      path    => [ '/bin/', '/sbin/', '/usr/bin/', '/usr/sbin/' ],
      require => Package[$php_package],
      notify  => Service[$php_webserver_service],
    }
  } else {
    $php_package                  = "${php_prefix}cli"
    $php_webserver_service        = undef
    $php_webserver_service_ini    = undef
    $php_webserver_service_ensure = undef
    $php_webserver_restart        = false
    $php_config_file              = $php::params::config_file
    $php_manage_service           = false
  }

  class { 'php':
    package             => $php_package,
    service             => $php_webserver_service,
    service_autorestart => false,
    config_file         => $php_config_file,
  }

  if $php_manage_service and $php_webserver_service and ! defined(Service[$php_webserver_service]) {
    service { $php_webserver_service:
      ensure     => $php_webserver_service_ensure,
      enable     => true,
      hasrestart => true,
      hasstatus  => true,
      require    => Package[$php_webserver_service]
    }
  }

  class { 'php::devel': }

  if count($php_values['modules']['php']) > 0 {
    php_mod { $php_values['modules']['php']:; }
  }
  if count($php_values['modules']['pear']) > 0 {
    php_pear_mod { $php_values['modules']['pear']:; }
  }
  if count($php_values['modules']['pecl']) > 0 {
    php_pecl_mod { $php_values['modules']['pecl']:; }
  }

  if count($php_values['ini']) > 0 {
    $php_inis = merge({
      'cgi.fix_pathinfo' => 1,
      'date.timezone'    => $php_values['timezone'],
    }, $php_values['ini'])

    each( $php_inis ) |$key, $value| {
      if is_array($value) {
        each( $php_values['ini'][$key] ) |$innerkey, $innervalue| {
          puphpet::php::ini { "${key}_${innerkey}":
            entry       => "CUSTOM_${innerkey}/${key}",
            value       => $innervalue,
            php_version => $php_values['version'],
            webserver   => $php_webserver_service_ini
          }
        }
      } else {
        puphpet::php::ini { $key:
          entry       => "CUSTOM/${key}",
          value       => $value,
          php_version => $php_values['version'],
          webserver   => $php_webserver_service_ini
        }
      }
    }

    if hash_key_true($php_values['ini'], 'session.save_path'){
      $php_sess_save_path = $php_values['ini']['session.save_path']

      exec {"mkdir -p ${php_sess_save_path}":
        creates => $php_sess_save_path,
        before  => Class['php']
      }
      -> file { $php_sess_save_path:
        ensure => directory,
        group  => 'www-data',
        owner  => 'www-data',
        mode   => 0775,
      }
    }
  }

  if hash_key_equals($php_values, 'composer', 1)
    and ! defined(Class['puphpet::php::composer'])
  {
    class { 'puphpet::php::composer':
      php_package   => "${php::params::module_prefix}cli",
      composer_home => $php_values['composer_home'],
    }
  }

  # Usually this would go within the library that needs in (Mailcatcher)
  # but the values required are sufficiently complex that it's easier to
  # add here
  if hash_key_equals($mailcatcher_values, 'install', 1)
    and ! defined(Puphpet::Php::Ini['sendmail_path'])
  {
    $mailcatcher_f_flag = $mailcatcher_values['settings']['from_email_method'] ? {
      'headers' => '',
      default   => ' -f',
    }

    puphpet::php::ini { 'sendmail_path':
      entry       => 'CUSTOM/sendmail_path',
      value       => "${mailcatcher_values['settings']['mailcatcher_path']}/catchmail${mailcatcher_f_flag}",
      php_version => $php_values['version'],
      webserver   => $php_webserver_service_ini
    }
  }
}

define php_mod {
  if ! defined(Puphpet::Php::Module[$name]) {
    puphpet::php::module { $name:
      service_autorestart => $php_webserver_restart,
    }
  }
}
define php_pear_mod {
  if ! defined(Puphpet::Php::Pear[$name]) {
    puphpet::php::pear { $name:
      service_autorestart => $php_webserver_restart,
    }
  }
}
define php_pecl_mod {
  if ! defined(Puphpet::Php::Extra_repos[$name]) {
    puphpet::php::extra_repos { $name:
      before => Puphpet::Php::Pecl[$name],
    }
  }

  if ! defined(Puphpet::Php::Pecl[$name]) {
    puphpet::php::pecl { $name:
      service_autorestart => $php_webserver_restart,
    }
  }
}
if $postgresql_values == undef { $postgresql_values = hiera_hash('postgresql', false) }
if $php_values == undef { $php_values = hiera_hash('php', false) }
if $hhvm_values == undef { $hhvm_values = hiera_hash('hhvm', false) }

include puphpet::params

if hash_key_equals($postgresql_values, 'install', 1) {
  if hash_key_equals($apache_values, 'install', 1)
    or hash_key_equals($nginx_values, 'install', 1)
  {
    $postgresql_webserver_restart = true
  } else {
    $postgresql_webserver_restart = false
  }

  if hash_key_equals($php_values, 'install', 1) {
    $postgresql_php_installed = true
    $postgresql_php_package   = 'php'
  } elsif hash_key_equals($hhvm_values, 'install', 1) {
    $postgresql_php_installed = true
    $postgresql_php_package   = 'hhvm'
  } else {
    $postgresql_php_installed = false
  }

  if $postgresql_values['settings']['root_password'] {
    group { $postgresql_values['settings']['user_group']:
      ensure => present
    }

    class { 'postgresql::globals':
      manage_package_repo => true,
      encoding            => $postgresql_values['settings']['encoding'],
      version             => $postgresql_values['settings']['version']
    }->
    class { 'postgresql::server':
      postgres_password => $postgresql_values['settings']['root_password'],
      version           => $postgresql_values['settings']['version'],
      require           => Group[$postgresql_values['settings']['user_group']]
    }

    if count($postgresql_values['databases']) > 0 {
      each( $postgresql_values['databases'] ) |$key, $database| {
        $database_merged = delete(merge($database, {
          'dbname' => $database['name'],
        }), 'name')

        create_resources( postgresql_db, {
          "${database['user']}@${database['name']}" => $database_merged
        })
      }
    }

    if $postgresql_php_installed
      and $postgresql_php_package == 'php'
      and ! defined(Puphpet::Php::Module['pgsql'])
    {
      puphpet::php::module { 'pgsql':
        service_autorestart => $postgresql_webserver_restart,
      }
    }
  }

  if hash_key_equals($postgresql_values, 'adminer', 1) and $postgresql_php_installed {
    if hash_key_equals($apache_values, 'install', 1) {
      $postgresql_adminer_webroot_location = '/var/www/default'
    } elsif hash_key_equals($nginx_values, 'install', 1) {
      $postgresql_adminer_webroot_location = $puphpet::params::nginx_webroot_location
    } else {
      $postgresql_adminer_webroot_location = '/var/www/default'
    }

    class { 'puphpet::adminer':
      location    => "${postgresql_adminer_webroot_location}/adminer",
      owner       => 'www-data',
      php_package => $postgresql_php_package
    }
  }
}

define postgresql_db (
  $dbname,
  $user,
  $password,
  $encoding   = $postgresql::server::encoding,
  $locale     = $postgresql::server::locale,
  $grant      = 'ALL',
  $tablespace = undef,
  $template   = 'template0',
  $istemplate = false,
  $owner      = undef,
  $sql_file   = false
) {
  if ! value_true($dbname) or ! value_true($user)
    or ! value_true($password)
  {
    fail( 'PostgreSQL DB requires that name, user, password and grant be set. Please check your settings!' )
  }

  if ! defined(Postgresql::Server::Database[$dbname]) {
    postgresql::server::database { $dbname:
      encoding   => $encoding,
      tablespace => $tablespace,
      template   => $template,
      locale     => $locale,
      istemplate => $istemplate,
      owner      => $owner,
    }
  }

  if ! defined(Postgresql::Server::Role[$user]) {
    postgresql::server::role { $user:
      password_hash => postgresql_password($user, $password),
    }
  }

  $grant_string = "GRANT ${user} - ${grant} - ${dbname}"

  if ! defined(Postgresql::Server::Database_grant[$grant_string]) {
    postgresql::server::database_grant { $grant_string:
      privilege => $grant,
      db        => $dbname,
      role      => $user,
    }
  }

  if($tablespace != undef and defined(Postgresql::Server::Tablespace[$tablespace])) {
    Postgresql::Server::Tablespace[$tablespace] -> Postgresql::Server::Database[$dbname]
  }

  if $sql_file {
    $table = "${dbname}.*"

    exec{ "${dbname}-import":
      command     => "sudo -u postgres psql ${dbname} < ${sql_file}",
      logoutput   => true,
      refreshonly => true,
      require     => Postgresql::Server::Database_grant[$grant_string],
      onlyif      => "test -f ${sql_file}",
      subscribe   => Postgresql::Server::Database[$dbname],
    }
  }
}
if $python_values == undef { $python_values = hiera_hash('python', false) }

include puphpet::params

if hash_key_equals($python_values, 'install', 1) {
  include pyenv::params

  install_python_packages { 'foo':
    before => Class['pyenv'],
  }

  class { 'pyenv':
    manage_packages => false,
  }

  if count($python_values['versions']) > 0 {
    create_resources(install_python, $python_values['versions'])
  }

  if count($python_values['packages']) > 0 {
    each( $python_values['packages'] ) |$key, $package| {
      $package_array = split($package, '@')
      $package_name = $package_array[0]

      if count($package_array) == 2 {
        $package_ensure = $package_array[1]
      } else {
        $package_ensure = present
      }

      if ! defined(Package[$package_name]) {
        package { $package_name:
          ensure   => $package_ensure,
          provider => pip,
        }
      }
    }
  }
}

define install_python (
  $version,
  $virtualenv = false,
) {

  $install_virtualenv = value_true($virtualenv) ? {
    true    => true,
    default => false,
  }

  if value_true($version) {
    pyenv_python { $version:
      keep       => true,
      virtualenv => $install_virtualenv,
      ensure     => present,
      require    => Class['pyenv'],
    } ->
    file { "python v${version} symlink":
      ensure => link,
      path   => "/usr/bin/python${version}",
      target => "/usr/local/pyenv/versions/${version}/bin/python",
    } ->
    file { "python v${version} virtualenv symlink":
      ensure => link,
      path   => "/usr/bin/virtualenv-${version}",
      target => "/usr/local/pyenv/versions/${version}/bin/virtualenv",
    }
  }

}

define install_python_packages {
  each( $pyenv::params::python_build_packages ) |$key, $package| {
    if ! defined(Package[$package]) {
      package { $package:
        ensure => present,
      }
    }
  }
}
if $rabbitmq_values == undef { $rabbitmq_values = hiera_hash('rabbitmq', false) }
if $php_values == undef { $php_values = hiera_hash('php', false) }
if $apache_values == undef { $apache_values = hiera_hash('apache', false) }
if $nginx_values == undef { $nginx_values = hiera_hash('nginx', false) }

include puphpet::params

if hash_key_equals($apache_values, 'install', 1)
  or hash_key_equals($nginx_values, 'install', 1)
{
  $rabbitmq_webserver_restart = true
} else {
  $rabbitmq_webserver_restart = false
}

if hash_key_equals($rabbitmq_values, 'install', 1) {
  if $::osfamily == 'redhat' {
    Class['erlang']
    -> Class['rabbitmq']

    include erlang
  }

  create_resources('class', { 'rabbitmq' => $rabbitmq_values['settings'] })

  if hash_key_equals($php_values, 'install', 1)
    and ! defined(Puphpet::Php::Pecl['amqp'])
  {
    puphpet::php::pecl { 'amqp':
      service_autorestart => $rabbitmq_webserver_restart,
      require             => Package['rabbitmq-server']
    }
  }

  if ! defined(Firewall['100 tcp/15672']) {
    firewall { '100 tcp/15672':
      port   => 15672,
      proto  => tcp,
      action => 'accept',
    }
  }
}
if $redis_values == undef { $redis_values = hiera_hash('redis', false) }
if $php_values == undef { $php_values = hiera_hash('php', false) }
if $apache_values == undef { $apache_values = hiera_hash('apache', false) }
if $nginx_values == undef { $nginx_values = hiera_hash('nginx', false) }

include puphpet::params

if hash_key_equals($apache_values, 'install', 1)
  or hash_key_equals($nginx_values, 'install', 1)
{
  $redis_webserver_restart = true
} else {
  $redis_webserver_restart = false
}

if hash_key_equals($redis_values, 'install', 1) {
  create_resources('class', { 'redis' => $redis_values['settings'] })

  if hash_key_equals($php_values, 'install', 1)
    and ! defined(Puphpet::Php::Pecl['redis'])
  {
    puphpet::php::pecl { 'redis':
      service_autorestart => $redis_webserver_restart,
      require             => Class['redis']
    }
  }
}
if $ruby_values == undef { $ruby_values = hiera_hash('ruby', false) }

include puphpet::params

if hash_key_true($ruby_values, 'versions') and count($ruby_values['versions']) > 0 {
  $rvm_has_default = false

  rvm_dotfile { 'do': }

  create_resources(install_ruby, $ruby_values['versions'])
}

define install_ruby (
  $version,
  $default = false,
  $bundler = false,
  $gems    = []
) {

  $default_true = value_true($default)
  $bundler_true = value_true($bundle)

  if value_true($version) {
    rvm_system_ruby { $version:
        default_use => $default_true,
        ensure      => present,
        require     => File_line['rvm_autoupdate_flag=0 >> ~/.rvmrc'],
    }

    if $bundler_true == true {
      $gems_merged = concat($gems, 'bundler')
    } else {
      $gems_merged = $gems
    }

    if count($gems_merged) > 0 {
      each( $gems_merged ) |$key, $gem| {
        $gem_array = split($gem, '@')

        if count($gem_array) == 2 {
          $gem_ensure = $gem_array[1]
        } else {
          $gem_ensure = present
        }

        rvm_gem { $gem_array[0]:
          name         => $gem_array[0],
          ruby_version => $version,
          ensure       => $gem_ensure,
          require      => Rvm_system_ruby[$version]
        }
      }
    }
  }

}

define rvm_dotfile {
  if $::ssh_username != 'root' {
    file { "/home/${::ssh_username}/.rvmrc":
      ensure => present,
      owner  => $::ssh_username,
      require => User[$::ssh_username]
    }
    file_line { 'rvm_autoupdate_flag=0 >> ~/.rvmrc':
      ensure  => present,
      line    => 'rvm_autoupdate_flag=0',
      path    => "/home/${::ssh_username}/.rvmrc",
      require => File["/home/${::ssh_username}/.rvmrc"],
    }
  }

  file { "/root/.rvmrc":
    ensure => present,
    owner  => 'root',
  }
  file_line { 'rvm_autoupdate_flag=0 >> /root/.rvmrc':
    ensure  => present,
    line    => 'rvm_autoupdate_flag=0',
    path    => "/root/.rvmrc",
    require => File["/root/.rvmrc"],
  }
}
if $server_values == undef { $server_values = hiera_hash('server', false) }

include ntp
include swap_file
include puphpet
include puphpet::params

Exec { path => [ '/bin/', '/sbin/', '/usr/bin/', '/usr/sbin/' ] }
group { 'puppet':   ensure => present }
group { 'www-data': ensure => present }
group { 'www-user': ensure => present }

case $::ssh_username {
  'root': {
    $user_home   = '/root'
    $manage_home = false
  }
  default: {
    $user_home   = "/home/${::ssh_username}"
    $manage_home = true
  }
}

user { $::ssh_username:
  shell      => '/bin/bash',
  home       => $user_home,
  managehome => $manage_home,
  ensure     => present,
  groups     => ['www-data', 'www-user'],
  require    => [Group['www-data'], Group['www-user']],
}

user { ['apache', 'nginx', 'httpd', 'www-data']:
  shell  => '/bin/bash',
  ensure => present,
  groups => 'www-data',
  require => Group['www-data']
}

# copy dot files to ssh user's home directory
exec { 'dotfiles':
  cwd     => $user_home,
  command => "cp -r /vagrant/puphpet/files/dot/.[a-zA-Z0-9]* ${user_home}/ \
              && chown -R ${::ssh_username} ${user_home}/.[a-zA-Z0-9]* \
              && cp -r /vagrant/puphpet/files/dot/.[a-zA-Z0-9]* /root/",
  onlyif  => 'test -d /vagrant/puphpet/files/dot',
  returns => [0, 1],
  require => User[$::ssh_username]
}

case $::osfamily {
  'debian': {
    include apt

    Class['apt::update'] -> Package <|
        title != 'python-software-properties'
    and title != 'software-properties-common'
    |>

    if ! defined(Package['augeas-tools']) {
      package { 'augeas-tools':
        ensure => present,
      }
    }
  }
  'redhat': {
    class { 'yum': extrarepo => ['epel'] }

    class { 'yum::repo::rpmforge': }
    class { 'yum::repo::repoforgeextras': }

    Class['::yum'] -> Yum::Managed_yumrepo <| |> -> Package <| |>

    if ! defined(Package['git']) {
      package { 'git':
        ensure  => latest,
        require => Class['yum::repo::repoforgeextras']
      }
    }

    if ! defined(Package['augeas']) {
      package { 'augeas':
        ensure => present,
      }
    }

    link_dot_files { 'do': }
  }
}

case $::operatingsystem {
  'debian': {
    include apt::backports

    add_dotdeb { 'packages.dotdeb.org': release => $::lsbdistcodename }

    $server_lsbdistcodename = downcase($::lsbdistcodename)

    apt::force { 'git':
      release => "${server_lsbdistcodename}-backports",
      timeout => 60
    }
  }
  'ubuntu': {
    if ! defined(Apt::Key['4F4EA0AAE5267A6C']){
      apt::key { '4F4EA0AAE5267A6C': key_server => 'hkp://keyserver.ubuntu.com:80' }
    }
    if ! defined(Apt::Key['4CBEDD5A']){
      apt::key { '4CBEDD5A': key_server => 'hkp://keyserver.ubuntu.com:80' }
    }

    if $::lsbdistcodename in ['lucid', 'precise'] {
      apt::ppa { 'ppa:pdoes/ppa': require => Apt::Key['4CBEDD5A'], options => '' }
    } else {
      apt::ppa { 'ppa:pdoes/ppa': require => Apt::Key['4CBEDD5A'] }
    }
  }
  'redhat', 'centos': {
  }
}

if is_array($server_values['packages']) and count($server_values['packages']) > 0 {
  each( $server_values['packages'] ) |$package| {
    if ! defined(Package[$package]) {
      package { $package:
        ensure => present,
      }
    }
  }
}

define add_dotdeb ($release){
   apt::source { "${name}-repo.puphpet":
    location          => 'http://repo.puphpet.com/dotdeb/',
    release           => $release,
    repos             => 'all',
    required_packages => 'debian-keyring debian-archive-keyring',
    key               => '89DF5277',
    key_server        => 'keys.gnupg.net',
    include_src       => true
  }
}

define link_dot_files {
  file_line { 'link ~/.bash_git':
    ensure  => present,
    line    => 'if [ -f ~/.bash_git ] ; then source ~/.bash_git; fi',
    path    => "${user_home}/.bash_profile",
    require => Exec['dotfiles'],
  }

  file_line { 'link ~/.bash_aliases':
    ensure  => present,
    line    => 'if [ -f ~/.bash_aliases ] ; then source ~/.bash_aliases; fi',
    path    => "${user_home}/.bash_profile",
    require => Exec['dotfiles'],
  }

  if $::ssh_username != 'root' {
    file_line { 'link ~/.bash_git for root':
      ensure  => present,
      line    => 'if [ -f ~/.bash_git ] ; then source ~/.bash_git; fi',
      path    => '/root/.bashrc',
      require => Exec['dotfiles'],
    }

    file_line { 'link ~/.bash_aliases for root':
      ensure  => present,
      line    => 'if [ -f ~/.bash_aliases ] ; then source ~/.bash_aliases; fi',
      path    => '/root/.bashrc',
      require => Exec['dotfiles'],
    }
  }
}
if $solr_values == undef { $solr_values = hiera_hash('solr', false) }

include solr::params

if hash_key_equals($solr_values, 'install', 1) {
  exec { 'create solr conf dir':
    command => "mkdir -p ${solr::params::config_dir}",
    creates => $solr::params::config_dir,
    path    => [ '/bin/', '/sbin/', '/usr/bin/', '/usr/sbin/' ],
  }

  if ! defined(Class['java']) {
    class { 'java':
      distribution => 'jre',
    }
  }

  class { 'solr':
    install        => 'source',
    install_source => "http://archive.apache.org/dist/lucene/solr/${solr_values['settings']['version']}/solr-${solr_values['settings']['version']}.tgz",
    require        => [
      Exec['create solr conf dir'],
      Class['java']
    ],
  }

  if ! defined(Firewall["100 tcp/${solr_values['settings']['port']}"]) {
    firewall { "100 tcp/${solr_values['port']}":
      port   => $solr_values['port'],
      proto  => tcp,
      action => 'accept',
    }
  }

  $solr_path = "${solr::params::install_destination}/solr-${solr_values['settings']['version']}/bin"

  supervisord::program { 'solr':
    command     => "${solr_path}/solr start -p ${solr_values['settings']['port']}",
    priority    => '100',
    user        => 'root',
    autostart   => true,
    autorestart => 'true',
    environment => {
      'PATH' => "/bin:/sbin:/usr/bin:/usr/sbin:${solr_path}"
    },
    require => Class['solr'],
  }
}
if $sqlite_values == undef { $sqlite_values = hiera_hash('sqlite', false) }
if $php_values == undef { $php_values = hiera_hash('php', false) }
if $apache_values == undef { $apache_values = hiera_hash('apache', false) }
if $nginx_values == undef { $nginx_values = hiera_hash('nginx', false) }
if $mailcatcher_values == undef { $mailcatcher_values = hiera_hash('mailcatcher', false) }

include puphpet::params

if hash_key_equals($sqlite_values, 'install', 1) {
  if hash_key_equals($php_values, 'install', 1) {
    $sqlite_php_installed = true
    $sqlite_php_package   = 'php'
  } elsif hash_key_equals($hhvm_values, 'install', 1) {
    $sqlite_php_installed = true
    $sqlite_php_package   = 'hhvm'
  } else {
    $sqlite_php_installed = false
  }

  # puppet manifests for mailcatcher and sqlite are not compatible.
  if hash_key_equals($mailcatcher_values, 'install', 0) {
    class { 'sqlite': }
  }

  if is_hash($sqlite_values['databases'])
    and count($sqlite_values['databases']) > 0
  {
    create_resources(sqlite_db, $sqlite_values['databases'])
  }

  if $sqlite_php_installed
    and $sqlite_php_package == 'php'
    and ! defined(Puphpet::Php::Pecl['sqlite'])
  {
    puphpet::php::pecl { 'sqlite':
      service_autorestart => true,
    }
  }

  if hash_key_equals($sqlite_values, 'adminer', 1) and $sqlite_php_installed {
    if hash_key_equals($apache_values, 'install', 1) {
      $sqlite_adminer_webroot_location = $puphpet::params::apache_webroot_location
    } elsif hash_key_equals($nginx_values, 'install', 1) {
      $sqlite_adminer_webroot_location = $puphpet::params::nginx_webroot_location
    } else {
      $sqlite_adminer_webroot_location = $puphpet::params::apache_webroot_location
    }

    class { 'puphpet::adminer':
      location    => "${sqlite_adminer_webroot_location}/adminer",
      owner       => 'www-data',
      php_package => $sqlite_php_package
    }
  }
}

define sqlite_db (
  $name,
  $owner,
  $group = 0,
  $mode = 0775,
  $sql_file = false
) {
  if $name == '' or $owner == '' or $mode == '' {
    fail( 'SQLite requires that name, owner, group, and mode be set. Please check your settings!' )
  }

  file { '/var/lib/sqlite':
    ensure  => directory,
    owner   => $owner,
    group   => $group,
    mode    => 0775,
    require => User[$owner]
  } ->
  sqlite::db { $name:
    owner => $owner,
    group => $group,
    mode  => $mode
  }

  if $sql_file {
    exec{ "${name}-import":
      command     => "cat ${sql_file} | sudo sqlite3 /var/lib/sqlite/${name}.db",
      logoutput   => true,
      refreshonly => $refresh,
      require     => Sqlite::Db[$name],
      onlyif      => "test -f ${sql_file}"
    }
  }
}
if $wpcli_values == undef { $wpcli_values = hiera_hash('wpcli', false) }
if $php_values == undef { $php_values = hiera_hash('php', false) }
if $hhvm_values == undef { $hhvm_values = hiera_hash('hhvm', false) }

include puphpet::params

if hash_key_equals($wpcli_values, 'install', 1) {
  if $wpcli_values['version'] != undef
    and (hash_key_equals($php_values, 'install', 1)
          or hash_key_equals($hhvm_values, 'install', 1))
    and (hash_key_equals($php_values, 'composer', 1)
          or hash_key_equals($hhvm_values, 'composer', 1))
  {
    $wpcli_github   = 'https://github.com/wp-cli/wp-cli.git'
    $wpcli_location = '/usr/share/wp-cli'

    exec { 'delete-wpcli-path-if-not-git-repo':
      command => "rm -rf ${wpcli_location}",
      onlyif  => "test ! -d ${wpcli_location}/.git",
      path    => [ '/bin/', '/sbin/', '/usr/bin/', '/usr/sbin/' ],
    } ->
    vcsrepo { $wpcli_location:
      ensure   => present,
      provider => git,
      source   => $wpcli_github,
      revision => $wpcli_values['version'],
    } ->
    composer::exec { 'wp-cli':
      cmd     => 'install',
      cwd     => $wpcli_location,
      require => Vcsrepo[$wpcli_location],
    } ->
    file { "${wpcli_location}/bin/wp":
      ensure => present,
      mode   => '+x',
    }
    file { 'symlink wp-cli':
      ensure => link,
      path   => '/usr/bin/wp',
      mode   => 0766,
      target => "${wpcli_location}/bin/wp",
    }
  }
}
if $xdebug_values == undef { $xdebug_values = hiera_hash('xdebug', false) }
if $php_values == undef { $php_values = hiera_hash('php', false) }
if $apache_values == undef { $apache_values = hiera_hash('apache', false) }
if $nginx_values == undef { $nginx_values = hiera_hash('nginx', false) }

include puphpet::params

if hash_key_equals($xdebug_values, 'install', 1)
  and hash_key_equals($php_values, 'install', 1)
{
  $xdebug_php_prefix = $::osfamily ? {
    'debian' => 'php5-',
    'redhat' => 'php-',
  }

  if hash_key_equals($apache_values, 'install', 1)
    and hash_key_equals($php_values, 'mod_php', 1)
  {
    $xdebug_webserver_service = 'httpd'
  } elsif hash_key_equals($apache_values, 'install', 1)
    or hash_key_equals($nginx_values, 'install', 1)
  {
    $xdebug_webserver_service = "${xdebug_php_prefix}fpm"
  } else {
    $xdebug_webserver_service = undef
  }

  $xdebug_compile = $php_values['version'] ? {
    '5.6'   => true,
    '56'    => true,
    default => false,
  }

  class { 'puphpet::php::xdebug':
    webserver => $xdebug_webserver_service,
    compile   => $xdebug_compile,
  }

  if is_hash($xdebug_values['settings']) and count($xdebug_values['settings']) > 0 {
    each( $xdebug_values['settings'] ) |$key, $value| {
      puphpet::php::ini { $key:
        entry       => "XDEBUG/${key}",
        value       => $value,
        php_version => $php_values['version'],
        webserver   => $xdebug_webserver_service
      }
    }
  }
}
if $php_values == undef { $php_values = hiera_hash('php', false) }
if $xhprof_values == undef { $xhprof_values = hiera_hash('xhprof', false) }
if $apache_values == undef { $apache_values = hiera_hash('apache', false) }
if $nginx_values == undef { $nginx_values = hiera_hash('nginx', false) }

include puphpet::params

if hash_key_equals($xhprof_values, 'install', 1)
  and hash_key_equals($php_values, 'install', 1)
{
  if $::operatingsystem == 'ubuntu'
    and $::lsbdistcodename in ['lucid', 'maverick', 'natty', 'oneiric', 'precise']
  {
    apt::key { '8D0DC64F': key_server => 'hkp://keyserver.ubuntu.com:80' }
    apt::ppa { 'ppa:brianmercer/php5-xhprof': require => Apt::Key['8D0DC64F'] }
  }

  $xhprof_php_prefix = $::osfamily ? {
    'debian' => 'php5-',
    'redhat' => 'php-',
  }

  if hash_key_equals($apache_values, 'install', 1)
    and hash_key_equals($php_values, 'mod_php', 1)
  {
    $xhprof_webserver_service = 'httpd'
  } elsif hash_key_equals($apache_values, 'install', 1)
    or hash_key_equals($nginx_values, 'install', 1)
  {
    $xhprof_webserver_service = "${xhprof_php_prefix}fpm"
  } else {
    $xhprof_webserver_service = undef
  }

  if hash_key_equals($apache_values, 'install', 1) {
    $xhprof_webroot_location = '/var/www/default'
  } elsif hash_key_equals($nginx_values, 'install', 1) {
    $xhprof_webroot_location = $puphpet::params::nginx_webroot_location
  } else {
    $xhprof_webroot_location = $xhprof_values['location']
  }

  if ! defined(Package['graphviz']) {
    package { 'graphviz':
      ensure => present,
    }
  }

  class { 'puphpet::php::xhprof':
    php_version       => $php_values['version'],
    webroot_location  => $xhprof_webroot_location,
    webserver_service => $xhprof_webserver_service
  }
}
import 'nodes/*.pp'
                                          _
                                         / )
                                    .--.; |    _...,-"""-,
                     .-""-.-""""-. /   _`'-._.'   /`      \
                    /'     \      \|  (/'-._/     )        ;
            .-""""-;       (       '--' /-'    _           |
          .'       |        ;    e     /       a  ,       ;
         /          \       |      __.'`-.__,    ;       /
        /            `._     ;    .-'     `--.,__.\    /`
       //|              \     \,-'                /\_.'
      // |               `;.___>              /,-'.
    /`|  /                |`\      _..---\    |    \
    |/  /     _,.-----\   |  \   /`|      |   |\    \
       /    .;   |    |   |   \ /  |      |   | \    )
      |    / |   \    /   |\..' \   \     |   \  \..'
   jgs \../  \.../    \.../ \.../---'     \.../


          READ ME FOR SOME IMPORTANT INFORMATION!
          =======================================

If Puppet did not blow up (you do not see a sea of red
above), then your VM was generated successfully!

* A unique private key was generated for you! It is located
  at "puphpet/files/dot/ssh/id_rsa". If you are on Windows,
  a PuTTY-friendly key was also generated at same location
  with a ".ppk" extension.

* If you want to use your own private key for future
  provisions, overwrite the generated key above with your
  own. Make sure to follow the naming pattern, and include a
  ".pub" public key.

* If you wish to add packages, modules, Apache/Nginx vhosts,
  or anything else, open up "puphpet/config.yaml" and make
  changes within! Some things will have random strings like
  "DIdXRs2OI2LJ" - you must create a random string as well!
  To do so, please apply face to keyboard and roll.

* If you change "puphpet/config.yaml", simply run
  "$ vagrant provision" and your VM will be updated with the
  changes you requested!

Did something go wrong? Don't worry! I can (maybe) help!
Please go to our Github issues page at:

https://github.com/puphpet/puphpet/issues

and search for your problem. If you do not find your problem
answered, open a new ticket!

PLEASE REMEMBER TO INCLUDE THE CONTENTS OF YOUR
"puphpet/config.yaml" FILE.

Make sure to xxx out any potential API keys or passwords
that you do not want others to see!

Happy programming!
                                             - Juan Treminio

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|  ____                _      _    _                    _  |
| |  _ \ ___  __ _  __| |    / \  | |__   _____   _____| | |
| | |_) / _ \/ _` |/ _` |   / _ \ | '_ \ / _ \ \ / / _ \ | |
| |  _ <  __/ (_| | (_| |  / ___ \| |_) | (_) \ V /  __/_| |
| |_| \_\___|\__,_|\__,_| /_/   \_\_.__/ \___/ \_/ \___(_) |
|                                                          |
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 ____        ____  _   _ ____      _      generated using
|  _ \ _   _|  _ \| | | |  _ \ ___| |_   ___ ___  _ __ ___
| |_) | | | | |_) | |_| | |_) / _ \ __| / __/ _ \| '_ ` _ \
|  __/| |_| |  __/|  _  |  __/  __/ |_ | (_| (_) | | | | | |
|_|    \__,_|_|   |_| |_|_|   \___|\__(_)___\___/|_| |_| |_|
#!/bin/bash

export DEBIAN_FRONTEND=noninteractive

VAGRANT_CORE_FOLDER=$(cat '/.puphpet-stuff/vagrant-core-folder.txt')

EXEC_ONCE_DIR="$1"
EXEC_ALWAYS_DIR="$2"

echo "Running files in files/${EXEC_ONCE_DIR}"

if [ -d "/.puphpet-stuff/${EXEC_ONCE_DIR}-ran" ]; then
    rm -rf "/.puphpet-stuff/${EXEC_ONCE_DIR}-ran"
fi

if [ ! -f "/.puphpet-stuff/${EXEC_ONCE_DIR}-ran" ]; then
   touch "/.puphpet-stuff/${EXEC_ONCE_DIR}-ran"
   echo "Created file /.puphpet-stuff/${EXEC_ONCE_DIR}-ran"
fi

find "${VAGRANT_CORE_FOLDER}/files/${EXEC_ONCE_DIR}" -maxdepth 1 -type f -name '*.sh' | sort | while read FILENAME; do
    SHA1=$(sha1sum "${FILENAME}")

    if ! grep -x -q "${SHA1}" "/.puphpet-stuff/${EXEC_ONCE_DIR}-ran"; then
        echo "${SHA1}" >> "/.puphpet-stuff/${EXEC_ONCE_DIR}-ran"

        chmod +x "${FILENAME}"
        /bin/bash "${FILENAME}"
    else
        echo "Skipping executing ${FILENAME} as contents have not changed"
    fi
done

echo "Finished running files in files/${EXEC_ONCE_DIR}"
echo "To run again, delete hashes you want rerun in /.puphpet-stuff/${EXEC_ONCE_DIR}-ran or the whole file to rerun all"

echo "Running files in files/${EXEC_ALWAYS_DIR}"

find "${VAGRANT_CORE_FOLDER}/files/${EXEC_ALWAYS_DIR}" -maxdepth 1 -type f -name '*.sh' | sort | while read FILENAME; do
    chmod +x "${FILENAME}"
    /bin/bash "${FILENAME}"
done

echo "Finished running files in files/${EXEC_ALWAYS_DIR}"
#!/bin/bash

VAGRANT_CORE_FOLDER=$(cat '/.puphpet-stuff/vagrant-core-folder.txt')

if [[ -f '/.puphpet-stuff/displayed-important-notices' ]]; then
    exit 0
fi

cat "${VAGRANT_CORE_FOLDER}/shell/ascii-art/important-notices.txt"

touch '/.puphpet-stuff/displayed-important-notices'
#!/bin/bash

export DEBIAN_FRONTEND=noninteractive

VAGRANT_CORE_FOLDER=$(echo "$1")

OS=$(/bin/bash "${VAGRANT_CORE_FOLDER}/shell/os-detect.sh" ID)
CODENAME=$(/bin/bash "${VAGRANT_CORE_FOLDER}/shell/os-detect.sh" CODENAME)

cat "${VAGRANT_CORE_FOLDER}/shell/ascii-art/self-promotion.txt"
printf "\n"
echo ""

if [[ ! -d '/.puphpet-stuff' ]]; then
    mkdir '/.puphpet-stuff'
    echo 'Created directory /.puphpet-stuff'
fi

touch '/.puphpet-stuff/vagrant-core-folder.txt'
echo "${VAGRANT_CORE_FOLDER}" > '/.puphpet-stuff/vagrant-core-folder.txt'

# Adding this here with a datestamped filename for future issues like #1189
# apt repos become stale, Ubuntu/Debian move stuff around and break existing
# boxes that no longer require apt-get update. Force it one more time. Update
# datestamp as required for future breaks.
if [[ ! -f '/.puphpet-stuff/initial-setup-repo-update-11052014' ]]; then
    if [ "${OS}" == 'debian' ] || [ "${OS}" == 'ubuntu' ]; then
        echo 'Running datestamped initial-setup apt-get update'
        apt-get update >/dev/null
        touch '/.puphpet-stuff/initial-setup-repo-update-11052014'
        echo 'Finished running datestamped initial-setup apt-get update'
    fi
fi

if [[ -f '/.puphpet-stuff/initial-setup-base-packages' ]]; then
    exit 0
fi

if [ "${OS}" == 'debian' ] || [ "${OS}" == 'ubuntu' ]; then
    echo 'Running initial-setup apt-get update'
    apt-get update >/dev/null
    echo 'Finished running initial-setup apt-get update'

    echo 'Installing curl'
    apt-get -y install curl >/dev/null
    echo 'Finished installing curl'

    echo 'Installing git'
    apt-get -y install git-core >/dev/null
    echo 'Finished installing git'

    if [[ "${CODENAME}" == 'lucid' || "${CODENAME}" == 'precise' ]]; then
        echo 'Installing basic curl packages'
        apt-get -y install libcurl3 libcurl4-gnutls-dev curl >/dev/null
        echo 'Finished installing basic curl packages'
    fi

    echo 'Installing build-essential packages'
    apt-get -y install build-essential >/dev/null
    echo 'Finished installing build-essential packages'
elif [[ "${OS}" == 'centos' ]]; then
    echo 'Adding repos: elrepo, epel, scl'
    perl -p -i -e 's@enabled=1@enabled=0@gi' /etc/yum/pluginconf.d/fastestmirror.conf
    perl -p -i -e 's@#baseurl=http://mirror.centos.org/centos/\$releasever/os/\$basearch/@baseurl=http://mirror.rackspace.com/CentOS//\$releasever/os/\$basearch/\nenabled=1@gi' /etc/yum.repos.d/CentOS-Base.repo
    perl -p -i -e 's@#baseurl=http://mirror.centos.org/centos/\$releasever/updates/\$basearch/@baseurl=http://mirror.rackspace.com/CentOS//\$releasever/updates/\$basearch/\nenabled=1@gi' /etc/yum.repos.d/CentOS-Base.repo
    perl -p -i -e 's@#baseurl=http://mirror.centos.org/centos/\$releasever/extras/\$basearch/@baseurl=http://mirror.rackspace.com/CentOS//\$releasever/extras/\$basearch/\nenabled=1@gi' /etc/yum.repos.d/CentOS-Base.repo

    yum -y --nogpgcheck install 'http://www.elrepo.org/elrepo-release-6-6.el6.elrepo.noarch.rpm' >/dev/null
    yum -y --nogpgcheck install 'https://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm' >/dev/null
    yum -y install centos-release-SCL >/dev/null
    yum clean all >/dev/null
    yum -y check-update >/dev/null
    echo 'Finished adding repos: elrep, epel, scl'

    echo 'Installing curl'
    yum -y install curl >/dev/null
    echo 'Finished installing curl'

    echo 'Installing git'
    yum -y install git >/dev/null
    echo 'Finished installing git'

    echo 'Installing Development Tools'
    yum -y groupinstall 'Development Tools' >/dev/null
    echo 'Finished installing Development Tools'
fi

touch '/.puphpet-stuff/initial-setup-base-packages'
#!/bin/bash

export DEBIAN_FRONTEND=noninteractive

VAGRANT_CORE_FOLDER=$(cat '/.puphpet-stuff/vagrant-core-folder.txt')

OS=$(/bin/bash "${VAGRANT_CORE_FOLDER}/shell/os-detect.sh" ID)
RELEASE=$(/bin/bash "${VAGRANT_CORE_FOLDER}/shell/os-detect.sh" RELEASE)
CODENAME=$(/bin/bash "${VAGRANT_CORE_FOLDER}/shell/os-detect.sh" CODENAME)

if [ "${OS}" == 'debian' ] || [ "${OS}" == 'ubuntu' ]; then
    RVM_RUBIES='gems'
elif [[ "${OS}" == 'centos' ]]; then
    RVM_RUBIES='rubies'
fi

function check_puppet_symlink() {
    if [[ -f "/usr/local/rvm/${RVM_RUBIES}/ruby-1.9.3-p547/bin/puppet" ]]; then
        rm -f '/usr/bin/puppet'
        ln -s "/usr/local/rvm/${RVM_RUBIES}/ruby-1.9.3-p547/bin/puppet" '/usr/bin/puppet'
        return 0;
    elif [[ -f "/usr/local/rvm/${RVM_RUBIES}/ruby-1.9.3-p551/bin/puppet" ]]; then
        rm -f '/usr/bin/puppet'
        ln -s "/usr/local/rvm/${RVM_RUBIES}/ruby-1.9.3-p551/bin/puppet" '/usr/bin/puppet'
        return 0;
    fi

    # Puppet not installed
    if [ ! -L '/usr/bin/puppet' ]; then
        rm -f '/.puphpet-stuff/install-puppet'

        return 0;
    fi

    PUPPET_SYMLINK=$(ls -l /usr/bin/puppet);

    # If puppet symlink is old-style pointing to /usr/local/rvm/wrappers/default/ruby
    if [ "grep '/usr/local/rvm/wrappers/default' ${PUPPET_SYMLINK}" ]; then
        rm -f '/usr/bin/puppet'

        if [[ -f "/usr/local/rvm/${RVM_RUBIES}/ruby-1.9.3-p547/bin/puppet" ]]; then
            ln -s "/usr/local/rvm/${RVM_RUBIES}/ruby-1.9.3-p547/bin/puppet" '/usr/bin/puppet'
        elif [[ -f "/usr/local/rvm/${RVM_RUBIES}/ruby-1.9.3-p551/bin/puppet" ]]; then
            ln -s "/usr/local/rvm/${RVM_RUBIES}/ruby-1.9.3-p551/bin/puppet" '/usr/bin/puppet'
        else
            rm -f '/.puphpet-stuff/install-puppet'
        fi
    fi
}

check_puppet_symlink

if [[ -f '/.puphpet-stuff/install-puppet' ]]; then
    exit 0
fi

if [ "${OS}" == 'debian' ] || [ "${OS}" == 'ubuntu' ]; then
    apt-get -y install augeas-tools libaugeas-dev
elif [[ "${OS}" == 'centos' ]]; then
    yum -y install augeas-devel
fi

echo 'Installing Puppet requirements'
/usr/bin/gem install haml hiera facter json ruby-augeas --no-document
echo 'Finished installing Puppet requirements'

echo 'Installing Puppet 3.4.3'
/usr/bin/gem install puppet --version 3.4.3 --no-document

if [[ -f '/usr/bin/puppet' ]]; then
    mv /usr/bin/puppet /usr/bin/puppet-old
fi

ln -s "/usr/local/rvm/${RVM_RUBIES}/ruby-1.9.3-p*/bin/puppet" /usr/bin/puppet
echo 'Finished installing Puppet 3.4.3'

touch '/.puphpet-stuff/install-puppet'
#!/bin/bash

export DEBIAN_FRONTEND=noninteractive

VAGRANT_CORE_FOLDER=$(cat '/.puphpet-stuff/vagrant-core-folder.txt')

OS=$(/bin/bash "${VAGRANT_CORE_FOLDER}/shell/os-detect.sh" ID)
RELEASE=$(/bin/bash "${VAGRANT_CORE_FOLDER}/shell/os-detect.sh" RELEASE)
CODENAME=$(/bin/bash "${VAGRANT_CORE_FOLDER}/shell/os-detect.sh" CODENAME)

function check_ruby_symlinks() {
    # Ruby or Gem not symlinked
    if [ ! -L '/usr/bin/ruby' ] || [ ! -L '/usr/bin/gem' ]; then
        rm -f '/.puphpet-stuff/install-ruby'

        return 0;
    fi

    RUBY_SYMLINK=$(ls -l /usr/bin/ruby);
    GEM_SYMLINK=$(ls -l /usr/bin/gem);

    # If ruby symlink is old-style pointing to /usr/local/rvm/wrappers/default/ruby
    if [ "grep '/usr/local/rvm/wrappers/default' ${RUBY_SYMLINK}" ]; then
        rm -f '/usr/bin/ruby'

        if [[ -f '/usr/local/rvm/rubies/ruby-1.9.3-p547/bin/ruby' ]]; then
            ln -s '/usr/local/rvm/rubies/ruby-1.9.3-p547/bin/ruby' '/usr/bin/ruby'
        elif [[ -f '/usr/local/rvm/rubies/ruby-1.9.3-p551/bin/ruby' ]]; then
            ln -s '/usr/local/rvm/rubies/ruby-1.9.3-p551/bin/ruby' '/usr/bin/ruby'
        else
            rm -f '/.puphpet-stuff/install-ruby'
        fi
    fi

    # If gem symlink is old-style pointing to /usr/local/rvm/wrappers/default/gem
    if [ "grep '/usr/local/rvm/wrappers/default' ${GEM_SYMLINK}" ]; then
        rm -f '/usr/bin/gem'

        if [[ -f '/usr/local/rvm/rubies/ruby-1.9.3-p547/bin/gem' ]]; then
            ln -s '/usr/local/rvm/rubies/ruby-1.9.3-p547/bin/gem' '/usr/bin/gem'
        elif [[ -f '/usr/local/rvm/rubies/ruby-1.9.3-p551/bin/gem' ]]; then
            ln -s '/usr/local/rvm/rubies/ruby-1.9.3-p551/bin/gem' '/usr/bin/gem'
        else
            rm -f '/.puphpet-stuff/install-ruby'
        fi
    fi
}

check_ruby_symlinks

if [[ -f '/.puphpet-stuff/install-ruby' ]]; then
    exit 0
fi

echo 'Installing Ruby 1.9.3 using RVM'

rm -rf /usr/local/rvm/rubies/ruby-1.9.3-p*

if [ "${OS}" == 'debian' ] || [ "${OS}" == 'ubuntu' ]; then
    gpg --keyserver hkp://keys.gnupg.net --recv-keys D39DC0E3
elif [[ "${OS}" == 'centos' ]]; then
    gpg2 --keyserver hkp://keys.gnupg.net --recv-keys D39DC0E3
fi

curl -sSL https://get.rvm.io | bash -s stable --quiet-curl --ruby=1.9.3
source /usr/local/rvm/scripts/rvm

if [[ -f '/usr/bin/ruby' ]]; then
    mv /usr/bin/ruby /usr/bin/ruby-old
fi

if [[ -f '/usr/bin/gem' ]]; then
    mv /usr/bin/gem /usr/bin/gem-old
fi

rm -rf /usr/bin/ruby
rm -rf /usr/bin/gem

ln -s /usr/local/rvm/rubies/ruby-1.9.3-p*/bin/ruby /usr/bin/ruby
ln -s /usr/local/rvm/rubies/ruby-1.9.3-p*/bin/gem /usr/bin/gem

/usr/local/rvm/bin/rvm cleanup all

/usr/bin/gem update --system >/dev/null

touch '/.puphpet-stuff/install-ruby'

echo 'Finished install Ruby 1.9.3 using RVM'
#!/bin/bash

TYPE=$(echo "$1" | tr '[A-Z]' '[a-z]')
OS=$(uname)
ID='unknown'
CODENAME='unknown'
RELEASE='unknown'
ARCH='unknown'

# detect centos
grep 'centos' /etc/issue -i -q
if [ $? = '0' ]; then
    ID='centos'
    RELEASE=$(cat /etc/redhat-release | grep -o 'release [0-9]' | cut -d " " -f2)
elif [ -f '/etc/redhat-release' ]; then
    ID='centos'
    RELEASE=$(cat /etc/redhat-release | grep -o 'release [0-9]' | cut -d " " -f2)
# could be debian or ubuntu
elif [ $(which lsb_release) ]; then
    ID=$(lsb_release -i | cut -f2)
    CODENAME=$(lsb_release -c | cut -f2)
    RELEASE=$(lsb_release -r | cut -f2)
elif [ -f '/etc/lsb-release' ]; then
    ID=$(cat /etc/lsb-release | grep DISTRIB_ID | cut -d "=" -f2)
    CODENAME=$(cat /etc/lsb-release | grep DISTRIB_CODENAME | cut -d "=" -f2)
    RELEASE=$(cat /etc/lsb-release | grep DISTRIB_RELEASE | cut -d "=" -f2)
elif [ -f '/etc/issue' ]; then
    ID=$(head -1 /etc/issue | cut -d " " -f1)
    if [ -f '/etc/debian_version' ]; then
      RELEASE=$(</etc/debian_version)
    else
      RELEASE=$(head -1 /etc/issue | cut -d " " -f2)
    fi
fi

declare -A info

info[id]=$(echo "${ID}" | tr '[A-Z]' '[a-z]')
info[codename]=$(echo "${CODENAME}" | tr '[A-Z]' '[a-z]')
info[release]=$(echo "${RELEASE}" | tr '[A-Z]' '[a-z]')
info[arch]=$(uname -m)

if [ "${TYPE}" ] ; then
    echo "${info[${TYPE}]}"

    exit 0
fi

echo -e "ID\t\t${info[id]}"
echo -e "CODENAME\t${info[codename]}"
echo -e "RELEASE\t\t${info[release]}"
echo -e "ARCH\t\t${info[arch]}"
#!/bin/bash

VAGRANT_CORE_FOLDER=$(cat '/.puphpet-stuff/vagrant-core-folder.txt')

OS=$(/bin/bash "${VAGRANT_CORE_FOLDER}/shell/os-detect.sh" ID)
VAGRANT_SSH_USERNAME=$(echo "$1")

function create_key()
{
    BASE_KEY_NAME=$(echo "$1")

    if [[ ! -f "${VAGRANT_CORE_FOLDER}/files/dot/ssh/${BASE_KEY_NAME}" ]]; then
        ssh-keygen -f "${VAGRANT_CORE_FOLDER}/files/dot/ssh/${BASE_KEY_NAME}" -P ""

        if [[ ! -f "${VAGRANT_CORE_FOLDER}/files/dot/ssh/${BASE_KEY_NAME}.ppk" ]]; then
            if [ "${OS}" == 'debian' ] || [ "${OS}" == 'ubuntu' ]; then
                apt-get install -y putty-tools >/dev/null
            elif [ "${OS}" == 'centos' ]; then
                yum -y install putty >/dev/null
            fi

            puttygen "${VAGRANT_CORE_FOLDER}/files/dot/ssh/${BASE_KEY_NAME}" -O private -o "${VAGRANT_CORE_FOLDER}/files/dot/ssh/${BASE_KEY_NAME}.ppk"
        fi

        echo "Your private key for SSH-based authentication has been saved to 'puphpet/files/dot/ssh/${BASE_KEY_NAME}'!"
    else
        echo "Pre-existing private key found at 'puphpet/files/dot/ssh/${BASE_KEY_NAME}'"
    fi
}

create_key 'root_id_rsa'
create_key 'id_rsa'

PUBLIC_SSH_KEY=$(cat "${VAGRANT_CORE_FOLDER}/files/dot/ssh/id_rsa.pub")

echo 'Adding generated key to /root/.ssh/id_rsa'
echo 'Adding generated key to /root/.ssh/id_rsa.pub'
echo 'Adding generated key to /root/.ssh/authorized_keys'

mkdir -p /root/.ssh

cp "${VAGRANT_CORE_FOLDER}/files/dot/ssh/id_rsa" '/root/.ssh/'
cp "${VAGRANT_CORE_FOLDER}/files/dot/ssh/id_rsa.pub" '/root/.ssh/'

if [[ ! -f '/root/.ssh/authorized_keys' ]] || ! grep -q "${PUBLIC_SSH_KEY}" '/root/.ssh/authorized_keys'; then
    cat "${VAGRANT_CORE_FOLDER}/files/dot/ssh/id_rsa.pub" >> '/root/.ssh/authorized_keys'
fi

chown -R root '/root/.ssh'
chgrp -R root '/root/.ssh'
chmod 700 '/root/.ssh'
chmod 644 '/root/.ssh/id_rsa.pub'
chmod 600 '/root/.ssh/id_rsa'
chmod 600 '/root/.ssh/authorized_keys'

if [ "${VAGRANT_SSH_USERNAME}" != 'root' ]; then
    VAGRANT_SSH_FOLDER="/home/${VAGRANT_SSH_USERNAME}/.ssh";

    mkdir -p "${VAGRANT_SSH_FOLDER}"

    echo "Adding generated key to ${VAGRANT_SSH_FOLDER}/id_rsa"
    echo "Adding generated key to ${VAGRANT_SSH_FOLDER}/id_rsa.pub"
    echo "Adding generated key to ${VAGRANT_SSH_FOLDER}/authorized_keys"

    cp "${VAGRANT_CORE_FOLDER}/files/dot/ssh/id_rsa" "${VAGRANT_SSH_FOLDER}/id_rsa"
    cp "${VAGRANT_CORE_FOLDER}/files/dot/ssh/id_rsa.pub" "${VAGRANT_SSH_FOLDER}/id_rsa.pub"

    if [[ ! -f "${VAGRANT_SSH_FOLDER}/authorized_keys" ]] || ! grep -q "${PUBLIC_SSH_KEY}" "${VAGRANT_SSH_FOLDER}/authorized_keys"; then
        cat "${VAGRANT_CORE_FOLDER}/files/dot/ssh/id_rsa.pub" >> "${VAGRANT_SSH_FOLDER}/authorized_keys"
    fi

    chown -R "${VAGRANT_SSH_USERNAME}" "${VAGRANT_SSH_FOLDER}"
    chgrp -R "${VAGRANT_SSH_USERNAME}" "${VAGRANT_SSH_FOLDER}"
    chmod 700 "${VAGRANT_SSH_FOLDER}"
    chmod 644 "${VAGRANT_SSH_FOLDER}/id_rsa.pub"
    chmod 600 "${VAGRANT_SSH_FOLDER}/id_rsa"
    chmod 600 "${VAGRANT_SSH_FOLDER}/authorized_keys"

    passwd -d "${VAGRANT_SSH_USERNAME}" >/dev/null
fi

Fixed code:
# -*- mode: ruby -*-
# vi: set ft=ruby :

ENV['VAGRANT_DEFAULT_PROVIDER'] = 'virtualbox'
Vagrant.configure("2") do |config|
  ##### VM definition #####
  config.vm.define "phpservermon-dev" do |config|
  config.vm.hostname = "phpservermon-dev"
  config.vm.box = "bento/ubuntu-20.04"
  config.vm.box_check_update = false
  config.vm.network "private_network", ip: "192.168.50.100"
  config.vm.provision :ansible do |ansible|
    ansible.limit = "all"
    ansible.playbook = "provision.yaml"
  end
  config.vm.provider "virtualbox" do |vb|
  vb.memory = "2048"
  vb.cpus = "2"
end
<?php
define('PSM_DB_PREFIX', 'monitor_');
define('PSM_DB_USER', 'psm');
define('PSM_DB_PASS', 'psm-dev-password');
define('PSM_DB_NAME', 'psm');
define('PSM_DB_HOST', 'localhost');
define('PSM_DB_PORT', '3306'); //3306 is the default port for MySQL. If no specfic port is used, leave it empty.
define('PSM_BASE_URL', '');
define('PSM_WEBCRON_KEY', '');
define('PSM_PUBLIC', false);

upstream php-fpm {
    server unix:/var/run/php/php7.4-fpm.sock;
}

server {
    listen 80;
    server_name 192.168.50.100;

    root /vagrant;
    index index.php;
    charset UTF-8;

    gzip on;
    gzip_http_version 1.1;
    gzip_vary on;
    gzip_comp_level 6;
    gzip_proxied any;
    gzip_types text/plain text/xml text/css application/x-javascript;

    access_log /var/log/nginx/psm.access.log;
    error_log /var/log/nginx/psm.com.error.log;

    location = /favicon.ico {
        log_not_found off;
        access_log off;
    }

    location = /robots.txt {
        deny all;
        log_not_found off;
        access_log off;
    }

    location ~ /\.svn/* {
        deny all;
    }

    location ~ /\.git/* {
        deny all;
    }

    location /nginx_status {
        stub_status on;
        access_log off;
    }

    location / {
        try_files $uri $uri/ /index.php?q=$uri&$args;
    }

    location ~ \.php$ {

        set $nocache "";
        if ($http_cookie ~ (comment_author_.*|wordpress_logged_in.*|wp-postpass_.*)) {
           set $nocache "Y";
        }

        fastcgi_pass  php-fpm;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME /vagrant$fastcgi_script_name;
        fastcgi_intercept_errors on;
        include fastcgi_params;

        fastcgi_cache_use_stale error timeout invalid_header http_500;
        fastcgi_cache_key $host$request_uri;
        fastcgi_cache off;
        fastcgi_cache_valid 200 1m;
        fastcgi_cache_bypass $nocache;
        fastcgi_no_cache $nocache;
    }

    location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
        expires max;
        log_not_found off;
    }

    location ~ ^/(status|ping)$ {
        include /etc/nginx/fastcgi_params;
        fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $fastcgi_script_name;
        allow 127.0.0.1;
        deny all;
    }
}


To ease development, a Vagrantfile has been included along with a full provisioning profile generated using ansible.
The Vagrantfile is configured to set up a Ubuntu 20.04 box with PHP 7.4 (FPM) and MySQL installed, with a dedicated private IP for accessing the dev environment(http://192.168.50.100).
To set up the development environment, make sure you have Vagrant, Ansible and VirtualBox (https://www.virtualbox.org/) installed, then run::
After that, you can access your development environment by navigating to http://192.168.50.100/.
---
- hosts: all
  become: yes
  become_method: sudo
  tasks:
  - name: Update OS
    package:
     name: '*'
     state: latest
  - name: wget percona release installation file
    shell: cd /root/ && wget https://repo.percona.com/apt/percona-release_latest.$(lsb_release -sc)_all.deb; dpkg -i /root/percona-release_latest.$(lsb_release -sc)_all.deb

  - name: setup percona repositories to percona server 5.7
    shell: percona-release setup ps57

  - name: Update repositories cache
    apt:
      update_cache: yes

  - name: ensure nginx is at the latest version
    apt: name=nginx state=latest
  - name: start nginx
    service:
        name: nginx
        state: started

  - name: Add nginx stable repository from PPA and install its signing key on Ubuntu target
    ansible.builtin.apt_repository:
      repo: ppa:ondrej/php

  - name: ensure php7.4-fpm is at the latest version
    apt: name=php7.4-fpm state=latest

  - name: install php7.4-curl
    apt: name=php7.4-curl state=latest

  - name: install php7.4-xml
    apt: name=php7.4-xml state=latest

  - name: install php7.4-pdo
    apt: name=php7.4-pdo state=latest

  - name: install php7.4-mysql
    apt: name=php7.4-mysql state=latest

  - name: ensure gpupg2 is at the latest version
    apt: name=gnupg2 state=latest

  - name: ensure percona-server-57 is installed
    apt: name=percona-server-server-5.7 state=latest

    #  - name: Create a new database with name 'psm'
    #    shell: mysql -e "CREATE DATABASE psm;"
  - name: setup mysql
    shell: /vagrant/setup-mysql.sh

  - name: copy psm nginx vhost
    shell: /bin/cp -far /vagrant/dev/phpservermon-default /etc/nginx/sites-available/default

  - name: setup php dependencies
    shell: /vagrant/setup-php.sh

  - name: copy psm config file
    shell: /bin/cp -far /vagrant/dev/config.php /vagrant/config.php

  - name: apply nginx modifications
    service:
        name: nginx
        state: restarted

#!/usr/bin/env bash
# Create database
mysql -e "CREATE DATABASE psm;"
# Create user
mysql -e "CREATE USER 'psm'@'localhost' IDENTIFIED BY 'psm-dev-password';"
mysql -e "GRANT ALL PRIVILEGES ON psm.* TO 'psm'@'localhost';"
mysql -e "FLUSH PRIVILEGES;"

#!/usr/bin/env bash
# check if vendor dir is existing
DIR="/vagrant/vendor/"
if [ -d "$DIR" ]; then
  # Take action if $DIR exists. #
  echo "vendor dir found, nothing to do..."
else
  echo "vendor dir not found, installing dependencies..."
  cd /vagrant/ && php composer.phar install
fi