From 269aa0e4ab1d106f521995e9e4beb8335acdbed6 Mon Sep 17 00:00:00 2001 From: Martin Zobel-Helas Date: Sun, 21 Jun 2015 18:57:24 +0000 Subject: [PATCH] add nanliu/staging to 3rdparty --- 3rdparty/Puppetfile | 1 + 3rdparty/modules/staging/Gemfile | 7 + 3rdparty/modules/staging/LICENSE | 11 ++ 3rdparty/modules/staging/README.md | 70 +++++++ 3rdparty/modules/staging/Rakefile | 1 + 3rdparty/modules/staging/Vagrantfile | 29 +++ 3rdparty/modules/staging/checksums.json | 37 ++++ 3rdparty/modules/staging/docs/deploy.html | 113 +++++++++++ 3rdparty/modules/staging/docs/extract.html | 176 +++++++++++++++++ 3rdparty/modules/staging/docs/file.html | 178 ++++++++++++++++++ 3rdparty/modules/staging/docs/init.html | 87 +++++++++ 3rdparty/modules/staging/files/sample | 1 + 3rdparty/modules/staging/files/sample.tar.bz2 | Bin 0 -> 27984 bytes 3rdparty/modules/staging/files/sample.tar.gz | Bin 0 -> 33352 bytes .../staging/lib/facter/staging_http_get.rb | 29 +++ .../staging/lib/facter/staging_windir.rb | 11 ++ .../puppet/parser/functions/scope_defaults.rb | 17 ++ .../puppet/parser/functions/staging_parse.rb | 36 ++++ 3rdparty/modules/staging/manifests/deploy.pp | 42 +++++ 3rdparty/modules/staging/manifests/extract.pp | 109 +++++++++++ 3rdparty/modules/staging/manifests/file.pp | 125 ++++++++++++ 3rdparty/modules/staging/manifests/init.pp | 31 +++ 3rdparty/modules/staging/manifests/params.pp | 33 ++++ 3rdparty/modules/staging/metadata.json | 106 +++++++++++ .../spec/defines/staging_deploy_spec.rb | 27 +++ .../spec/defines/staging_extract_spec.rb | 104 ++++++++++ .../staging/spec/defines/staging_file_spec.rb | 163 ++++++++++++++++ 3rdparty/modules/staging/spec/spec_helper.rb | 29 +++ .../parser/functions/scope_defaults_spec.rb | 45 +++++ .../parser/functions/staging_parse_spec.rb | 51 +++++ 3rdparty/modules/staging/tests/deploy.pp | 4 + 3rdparty/modules/staging/tests/extract.pp | 25 +++ 3rdparty/modules/staging/tests/file.pp | 17 ++ 3rdparty/modules/staging/tests/init.pp | 1 + .../modules/staging/tests/scope_defaults.pp | 7 + .../modules/staging/tests/staging_parse.pp | 12 ++ 36 files changed, 1735 insertions(+) create mode 100644 3rdparty/modules/staging/Gemfile create mode 100644 3rdparty/modules/staging/LICENSE create mode 100644 3rdparty/modules/staging/README.md create mode 100644 3rdparty/modules/staging/Rakefile create mode 100644 3rdparty/modules/staging/Vagrantfile create mode 100644 3rdparty/modules/staging/checksums.json create mode 100644 3rdparty/modules/staging/docs/deploy.html create mode 100644 3rdparty/modules/staging/docs/extract.html create mode 100644 3rdparty/modules/staging/docs/file.html create mode 100644 3rdparty/modules/staging/docs/init.html create mode 100644 3rdparty/modules/staging/files/sample create mode 100644 3rdparty/modules/staging/files/sample.tar.bz2 create mode 100644 3rdparty/modules/staging/files/sample.tar.gz create mode 100644 3rdparty/modules/staging/lib/facter/staging_http_get.rb create mode 100644 3rdparty/modules/staging/lib/facter/staging_windir.rb create mode 100644 3rdparty/modules/staging/lib/puppet/parser/functions/scope_defaults.rb create mode 100644 3rdparty/modules/staging/lib/puppet/parser/functions/staging_parse.rb create mode 100644 3rdparty/modules/staging/manifests/deploy.pp create mode 100644 3rdparty/modules/staging/manifests/extract.pp create mode 100644 3rdparty/modules/staging/manifests/file.pp create mode 100644 3rdparty/modules/staging/manifests/init.pp create mode 100644 3rdparty/modules/staging/manifests/params.pp create mode 100644 3rdparty/modules/staging/metadata.json create mode 100644 3rdparty/modules/staging/spec/defines/staging_deploy_spec.rb create mode 100644 3rdparty/modules/staging/spec/defines/staging_extract_spec.rb create mode 100644 3rdparty/modules/staging/spec/defines/staging_file_spec.rb create mode 100644 3rdparty/modules/staging/spec/spec_helper.rb create mode 100644 3rdparty/modules/staging/spec/unit/puppet/parser/functions/scope_defaults_spec.rb create mode 100644 3rdparty/modules/staging/spec/unit/puppet/parser/functions/staging_parse_spec.rb create mode 100644 3rdparty/modules/staging/tests/deploy.pp create mode 100644 3rdparty/modules/staging/tests/extract.pp create mode 100644 3rdparty/modules/staging/tests/file.pp create mode 100644 3rdparty/modules/staging/tests/init.pp create mode 100644 3rdparty/modules/staging/tests/scope_defaults.pp create mode 100644 3rdparty/modules/staging/tests/staging_parse.pp diff --git a/3rdparty/Puppetfile b/3rdparty/Puppetfile index 8357f92d..86237bb9 100644 --- a/3rdparty/Puppetfile +++ b/3rdparty/Puppetfile @@ -7,3 +7,4 @@ mod 'puppetlabs/stdlib', '4.6.0' mod 'puppetlabs/concat', '1.2.2' mod 'puppetlabs/rabbitmq', '5.2.1' mod 'elasticsearch/elasticsearch', '0.9.5' +mod 'nanliu/staging', '1.0.3' diff --git a/3rdparty/modules/staging/Gemfile b/3rdparty/modules/staging/Gemfile new file mode 100644 index 00000000..7bfafd71 --- /dev/null +++ b/3rdparty/modules/staging/Gemfile @@ -0,0 +1,7 @@ +source "https://rubygems.org" + +group :development, :test do + gem 'bodeco_module_helper', :git => 'https://github.com/bodeco/bodeco_module_helper.git' + gem 'rspec', "~> 2.11.0", :require => false + gem 'mocha', "~> 0.10.5", :require => false +end diff --git a/3rdparty/modules/staging/LICENSE b/3rdparty/modules/staging/LICENSE new file mode 100644 index 00000000..51fca54c --- /dev/null +++ b/3rdparty/modules/staging/LICENSE @@ -0,0 +1,11 @@ +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. diff --git a/3rdparty/modules/staging/README.md b/3rdparty/modules/staging/README.md new file mode 100644 index 00000000..ebb5b02c --- /dev/null +++ b/3rdparty/modules/staging/README.md @@ -0,0 +1,70 @@ +# 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. + +NOTE: Version 1.0.0 will be the last feature release. New functionality such as checksum will be implemented in a type/provider module [puppet-archive](https://www.github.com/nanliu/puppet-archive). + +## Usage + +Specify a different default staging path (must be declared before using resource): +```puppet +class { 'staging': + path => '/var/staging', + owner => 'puppet', + group => 'puppet', +} +``` + +Staging files from various sources: +```puppet +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: +```puppet +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'], +} +``` + +Deploying a file (combining staging and extract): +```puppet +staging::deploy { 'sample.tar.gz': + source => 'puppet:///modules/staging/sample.tar.gz', + target => '/usr/local', +} +``` + +Staging files currently support the following source: + +* http(s):// +* puppet:// +* ftp:// +* s3:// (requires aws cli to be installed and configured.) +* local (though this doesn't serve any real purpose.) + +## Contributor + +* Adrien Thebo +* gizero +* Harald Skoglund +* Hunter Haugen +* Justin Clayton +* Owen Jacobson +* Reid Vandewiele diff --git a/3rdparty/modules/staging/Rakefile b/3rdparty/modules/staging/Rakefile new file mode 100644 index 00000000..7cae9728 --- /dev/null +++ b/3rdparty/modules/staging/Rakefile @@ -0,0 +1 @@ +require 'bodeco_module_helper/rake_tasks' diff --git a/3rdparty/modules/staging/Vagrantfile b/3rdparty/modules/staging/Vagrantfile new file mode 100644 index 00000000..9f9ac91e --- /dev/null +++ b/3rdparty/modules/staging/Vagrantfile @@ -0,0 +1,29 @@ +# -*- 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 diff --git a/3rdparty/modules/staging/checksums.json b/3rdparty/modules/staging/checksums.json new file mode 100644 index 00000000..05b08e5c --- /dev/null +++ b/3rdparty/modules/staging/checksums.json @@ -0,0 +1,37 @@ +{ + "Gemfile": "270871f3fe4a93fd7c2df1666717cabb", + "LICENSE": "cdbf8d74b765504fbdf8e154bb4458a1", + "README.md": "af449710d996f056cf718289ff800af7", + "Rakefile": "a56b311c2311136cccbc2fdc3490dc77", + "Vagrantfile": "eef71b5e6febf751053145cc86752758", + "docs/deploy.html": "d9342a62d811e8d331c83a9521d7cb60", + "docs/extract.html": "ddfc7718ed639b24861b5a1d68cf0b0c", + "docs/file.html": "879efe671f96a8eaeb5fb023ced5b7ab", + "docs/init.html": "c16ebedfb85ab41558ad2fdea679177d", + "files/sample": "c668e2074cc870f9ef59b6b33ffda097", + "files/sample.tar.bz2": "d063a08e52797236df1b769dbdbd2c69", + "files/sample.tar.gz": "eba24f899d8b439f5c461f728563ece6", + "lib/facter/staging_http_get.rb": "1f89d73e82135c4c9533119e2a95690d", + "lib/facter/staging_windir.rb": "6897a62c26ff15041cae6b62bf9b7a35", + "lib/puppet/parser/functions/scope_defaults.rb": "da916d46f3ff3be8359f75c93c2b5532", + "lib/puppet/parser/functions/staging_parse.rb": "cf6a6648b567b6efd3d0741e5f690ca8", + "manifests/deploy.pp": "f2a3e783e69ab878ac2e115fdf897e52", + "manifests/extract.pp": "b4ac5a23a1e307c46764bca61c28e21c", + "manifests/file.pp": "9488fefca4c3aca6d293ae0d76db84aa", + "manifests/init.pp": "8363cfb8b0ec3c378a9b58e4749c57ee", + "manifests/params.pp": "229aaeafe695fa94e8c5b5602f4a9f77", + "metadata.json": "85161c511984d3151e884c448e7aaae8", + "spec/defines/staging_deploy_spec.rb": "d4310153779c65fb168ab275c81c7f36", + "spec/defines/staging_extract_spec.rb": "1aa0aa8419fcf98f374e3a62e2d01958", + "spec/defines/staging_file_spec.rb": "a11f653feeb70cd8631de5f69aaa4dcb", + "spec/fixtures/hiera.yaml": "324e9873e29c1970850f01b0f64c0269", + "spec/spec_helper.rb": "050ea9cc153b1c6da1db53cf6cf214a8", + "spec/unit/puppet/parser/functions/scope_defaults_spec.rb": "16a2af56511497feb7417e226161221f", + "spec/unit/puppet/parser/functions/staging_parse_spec.rb": "1a811cf7ca52b4b6fe3fe59ae0ebd38b", + "tests/deploy.pp": "27e2deca3fd5353dc8aa37c9162b2368", + "tests/extract.pp": "8076b72133e9240500b8e04eea023918", + "tests/file.pp": "8588e9c8b5e2ca430271ba2045dfb286", + "tests/init.pp": "d889d06d4cb307c38cba9267aaac978f", + "tests/scope_defaults.pp": "b620b367fc13aad2ff6f09f0c18463ba", + "tests/staging_parse.pp": "bec31082b383ef5bf6f81e4e82ec3b94" +} \ No newline at end of file diff --git a/3rdparty/modules/staging/docs/deploy.html b/3rdparty/modules/staging/docs/deploy.html new file mode 100644 index 00000000..fdcdc34e --- /dev/null +++ b/3rdparty/modules/staging/docs/deploy.html @@ -0,0 +1,113 @@ + + + + + deploy.pp + + + +
+
+
+ Jump To … + +
+ + + + + + + + + + + + +

deploy.pp

+
+ +
+

Define: staging::deploy

+ +

The define resource extracts compressed file to a staging location.

+ +

Parameters:

+ +
    +
  • [source]: the source file location, supports local files, puppet://, http://, https://, ftp:// (default: )
  • +
  • [target]: the target extraction directory (default: )
  • +
  • [staging_path]: the staging location for compressed file. defaults to ${staging::path}/${caller_module_name} (default: undef)
  • +
  • [username]: https or ftp username (default: undef)
  • +
  • [certificate]: https certifcate file (default: undef)
  • +
  • [password]: https or ftp user password or https certificate password (default: undef)
  • +
  • [environment]: environment variable for settings such as http_proxy (default: undef)
  • +
  • [timeout]: the time to wait for the file transfer to complete (default: undef)
  • +
  • [user]: extract file as this user (default: undef)
  • +
  • [group]: extract group as this group (default: undef)
  • +
  • [creates]: the file/folder created after extraction. if unspecified defaults to ${target}/${name} (default: undef)
  • +
  • [unless]: alternative way to conditionally extract file (default: undef)
  • +
  • [onlyif]: alternative way to conditionally extract file (default: undef)
  • +
+ + +

Usage:

+ +
staging::deploy { 'sample.tar.gz':
+  source => 'puppet:///modules/staging/sample.tar.gz',
+  target => '/usr/local',
+}
+
+ +
+
define staging::deploy (
+  $source,               
+  $target,               
+  $staging_path = undef, 
+  $username     = undef, 
+  $certificate  = undef, 
+  $password     = undef, 
+  $environment  = undef, 
+  $timeout      = undef, 
+  $user         = undef, 
+  $group        = undef, 
+  $creates      = undef, 
+  $unless       = undef, 
+  $onlyif       = undef  
+) {
+
+  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],
+  }
+
+}
+
+
+ diff --git a/3rdparty/modules/staging/docs/extract.html b/3rdparty/modules/staging/docs/extract.html new file mode 100644 index 00000000..0f46958a --- /dev/null +++ b/3rdparty/modules/staging/docs/extract.html @@ -0,0 +1,176 @@ + + + + + extract.pp + + + +
+
+
+ Jump To … + +
+ + + + + + + + + + + + + + + + +

extract.pp

+
+ +
+

Define: staging::extract

+ +

Define resource to extract files from staging directories to target directories.

+ +

Parameters:

+ +
    +
  • [target]: the target extraction directory (default: )
  • +
  • [source]: the source compression file, supports tar, tar.gz, zip, war (default: undef)
  • +
  • [creates]: the file created after extraction. if unspecified defaults ${staging::path}/${caller_module_name}/${name} ${target}/${name} (default: undef)
  • +
  • [unless]: alternative way to conditionally check whether to extract file. (default: undef)
  • +
  • [onlyif]: alternative way to conditionally check whether to extract file. (default: undef)
  • +
  • [user]: extract file as this user. (default: undef)
  • +
  • [group]: extract file as this group. (default: undef)
  • +
  • [environment]: environment variables. (default: undef)
  • +
  • [subdir]: subdir per module in staging directory. (default: $caller_module_name)
  • +
+ + +

Usage:

+ +
$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'],
+}
+
+
+
define staging::extract (
+  $target,              
+  $source      = undef, 
+  $creates     = undef, 
+  $unless      = undef, 
+  $onlyif      = undef, 
+  $user        = undef, 
+  $group       = undef, 
+  $environment = undef, 
+  $subdir      = $caller_module_name 
+) {
+
+  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')
+      $creates_path = "${target}/${folder}"
+    } 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}"
+      }
+    }
+
+    /.zip$/: {
+      $command = "unzip ${source_path}"
+    }
+
+    /.war$/: {
+      $command = "jar xf ${source_path}"
+    }
+
+    default: {
+      fail("staging::extract: unsupported file format ${name}.")
+    }
+  }
+
+  exec { "extract ${name}":
+    command => $command,
+  }
+}
+
+
+ diff --git a/3rdparty/modules/staging/docs/file.html b/3rdparty/modules/staging/docs/file.html new file mode 100644 index 00000000..38aa0da5 --- /dev/null +++ b/3rdparty/modules/staging/docs/file.html @@ -0,0 +1,178 @@ + + + + + file.pp + + + +
+
+
+ Jump To … + +
+ + + + + + + + + + + + +

file.pp

+
+ +
+

Define: staging::file

+ +

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.

+ +

Parameters:

+ +
    +
  • [source]: the source file location, supports local files, puppet://, http://, https://, ftp:// (default: )
  • +
  • [target]: the target staging directory, if unspecified ${staging::path}/${caller_module_name} (default: undef)
  • +
  • [username]: https or ftp username (default: undef)
  • +
  • [certificate]: https certificate file (default: undef)
  • +
  • [password]: https or ftp user password or https certificate password (default: undef)
  • +
  • [environment]: environment variable for settings such as http_proxy, https_proxy, of ftp_proxy (default: undef)
  • +
  • [timeout]: the the time to wait for the file transfer to complete (default: undef)
  • +
  • [subdir]: (default: $caller_module_name)
  • +
+ + +

Usage:

+ +
$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',
+}
+
+ +
+
define staging::file (
+  $source,              
+  $target      = undef, 
+  $username    = undef, 
+  $certificate = undef, 
+  $password    = undef, 
+  $environment = undef, 
+  $timeout     = undef, 
+  $subdir      = $caller_module_name
+) {
+
+  include staging
+
+  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        => '/usr/local/bin:/usr/bin:/bin',
+    environment => $environment,
+    cwd         => $staging_dir,
+    creates     => $target_file,
+    timeout     => $timeout,
+    logoutput   => on_failure,
+  }
+
+  case $source {
+    /^\//: {
+      file { $target_file:
+        source  => $source,
+        replace => false,
+      }
+    }
+
+    /^puppet:\/\//: {
+      file { $target_file:
+        source  => $source,
+        replace => false,
+      }
+    }
+
+    /^http:\/\//: {
+      exec { $target_file:
+        command     => "curl -L -o ${name} ${source}",
+      }
+    }
+
+    /^https:\/\//: {
+      if $username {
+        $command = "curl -L -o ${name} -u ${username}:${password} ${source}"
+      } elsif $certificate {
+        $command = "curl -L -o ${name} -E ${certificate}:${password} ${source}"
+      } else {
+        $command = "curl -L -o ${name} ${source}"
+      }
+
+      exec { $target_file:
+        command     => $command,
+      }
+    }
+
+    /^ftp:\/\//: {
+      if $username {
+        $command = "curl -o ${name} -u ${username}:${password} ${source}"
+      } else {
+        $command = "curl -o ${name} ${source}"
+      }
+
+      exec { $target_file:
+        command     => $command,
+      }
+    }
+
+    default: {
+      fail("stage::file: do not recognize source ${source}.")
+    }
+  }
+
+}
+
+
+ diff --git a/3rdparty/modules/staging/docs/init.html b/3rdparty/modules/staging/docs/init.html new file mode 100644 index 00000000..da5b2be9 --- /dev/null +++ b/3rdparty/modules/staging/docs/init.html @@ -0,0 +1,87 @@ + + + + + init.pp + + + +
+
+
+ Jump To … + +
+ + + + + + + + + + + + +

init.pp

+
+ +
+

Class: staging

+ +

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
+
+ +

Parameters:

+ +
    +
  • [path]: staging directory filepath (default: ‘/opt/staging’)
  • +
  • [owner]: staging directory owner (default: ‘0’)
  • +
  • [group]: staging directory group (default: ‘0’)
  • +
  • [mode]: staging directory permission (default: ‘0755’)
  • +
+ + +

Usage:

+ +
include staging
+
+ +
+
class staging (
+  $path  = '/opt/staging', 
+  $owner = '0',            
+  $group = '0',            
+  $mode  = '0755'          
+) {
+
+  file { $path:
+    ensure => directory,
+    owner  => $owner,
+    group  => $group,
+    mode   => $mode,
+  }
+
+}
+
+
+ diff --git a/3rdparty/modules/staging/files/sample b/3rdparty/modules/staging/files/sample new file mode 100644 index 00000000..01e34c31 --- /dev/null +++ b/3rdparty/modules/staging/files/sample @@ -0,0 +1 @@ +sample file to test module. diff --git a/3rdparty/modules/staging/files/sample.tar.bz2 b/3rdparty/modules/staging/files/sample.tar.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..f7fbcf229f0fc0c218a89c7de41d9b62ef6406b7 GIT binary patch literal 27984 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∓o7P|O5c_WNWX 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 :windows + setcode do + program_data = `echo %SYSTEMDRIVE%\\ProgramData`.chomp + if File.directory? program_data + "#{program_data}\\staging" + else + "C:\\staging" + end + end +end diff --git a/3rdparty/modules/staging/lib/puppet/parser/functions/scope_defaults.rb b/3rdparty/modules/staging/lib/puppet/parser/functions/scope_defaults.rb new file mode 100644 index 00000000..6c814849 --- /dev/null +++ b/3rdparty/modules/staging/lib/puppet/parser/functions/scope_defaults.rb @@ -0,0 +1,17 @@ +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 diff --git a/3rdparty/modules/staging/lib/puppet/parser/functions/staging_parse.rb b/3rdparty/modules/staging/lib/puppet/parser/functions/staging_parse.rb new file mode 100644 index 00000000..2c775592 --- /dev/null +++ b/3rdparty/modules/staging/lib/puppet/parser/functions/staging_parse.rb @@ -0,0 +1,36 @@ +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.gsub('\\', '/')).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 diff --git a/3rdparty/modules/staging/manifests/deploy.pp b/3rdparty/modules/staging/manifests/deploy.pp new file mode 100644 index 00000000..56503870 --- /dev/null +++ b/3rdparty/modules/staging/manifests/deploy.pp @@ -0,0 +1,42 @@ +# 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], + } + +} diff --git a/3rdparty/modules/staging/manifests/extract.pp b/3rdparty/modules/staging/manifests/extract.pp new file mode 100644 index 00000000..a48abba7 --- /dev/null +++ b/3rdparty/modules/staging/manifests/extract.pp @@ -0,0 +1,109 @@ +# 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. + $strip = undef, #: extract file with the --strip=X option. Only works with GNU tar. + $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}" + } else { + $creates_path = undef + } + + 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, + } + } + + if $strip { + if $::osfamily == 'Solaris' or $name !~ /(.tar|.tgz|.tar.gz|.tar.bz2)$/ { + warning('strip is only supported with GNU tar, ignoring the parameter') + $strip_opt = '' + } else { + $strip_opt = " --strip=${strip}" + } + } else { + $strip_opt = '' + } + + case $name { + /.tar$/: { + $command = "tar xf ${source_path}${strip_opt}" + } + + /(.tgz|.tar.gz)$/: { + if $::osfamily == 'Solaris' { + $command = "gunzip -dc < ${source_path} | tar xf - " + } else { + $command = "tar xzf ${source_path}${strip_opt}" + } + } + + /.tar.bz2$/: { + $command = "tar xjf ${source_path}${strip_opt}" + } + + /.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, + } +} diff --git a/3rdparty/modules/staging/manifests/file.pp b/3rdparty/modules/staging/manifests/file.pp new file mode 100644 index 00000000..7d07a98c --- /dev/null +++ b/3rdparty/modules/staging/manifests/file.pp @@ -0,0 +1,125 @@ +# #### 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://, s3:// + $target = undef, #: the target file location, if unspecified ${staging::path}/${subdir}/${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 + $tries = undef, #: amount of retries for the file transfer when non transient connection errors exist + $try_sleep = undef, #: time to wait between retries for the file transfer + $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, + try_sleep => $try_sleep, + tries => $tries, + logoutput => on_failure, + } + + case $::staging_http_get { + 'curl', default: { + $http_get = "curl ${curl_option} -f -L -o ${target_file} ${quoted_source}" + $http_get_passwd = "curl ${curl_option} -f -L -o ${target_file} -u ${username}:${password} ${quoted_source}" + $http_get_cert = "curl ${curl_option} -f -L -o ${target_file} -E ${certificate}:${password} ${quoted_source}" + $ftp_get = "curl ${curl_option} -o ${target_file} ${quoted_source}" + $ftp_get_passwd = "curl ${curl_option} -o ${target_file} -u ${username}:${password} ${quoted_source}" + } + 'wget': { + $http_get = "wget ${wget_option} -O ${target_file} ${quoted_source}" + $http_get_passwd = "wget ${wget_option} -O ${target_file} --user=${username} --password=${password} ${quoted_source}" + $http_get_cert = "wget ${wget_option} -O ${target_file} --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, + } + } + /^s3:\/\//: { + $command = "aws s3 cp ${source} ${target_file}" + exec { $target_file: + command => $command, + } + } + default: { + fail("staging::file: do not recognize source ${source}.") + } + } + +} diff --git a/3rdparty/modules/staging/manifests/init.pp b/3rdparty/modules/staging/manifests/init.pp new file mode 100644 index 00000000..227e1ea3 --- /dev/null +++ b/3rdparty/modules/staging/manifests/init.pp @@ -0,0 +1,31 @@ +# 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 { + + # Resolve conflict with pe_staging + if !defined(File[$path]) { + file { $path: + ensure => directory, + owner => $owner, + group => $group, + mode => $mode, + } + } + +} diff --git a/3rdparty/modules/staging/manifests/params.pp b/3rdparty/modules/staging/manifests/params.pp new file mode 100644 index 00000000..0d2fba36 --- /dev/null +++ b/3rdparty/modules/staging/manifests/params.pp @@ -0,0 +1,33 @@ +# 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 = 'S-1-5-32-544' # Adminstrators + $group = 'S-1-5-18' # SYSTEM + $mode = '0660' + $exec_path = $::path + } + 'FreeBSD': { + $path = '/var/tmp/staging' + $owner = '0' + $group = '0' + $mode = '0755' + $exec_path = '/usr/local/bin:/usr/bin:/bin' + } + } +} diff --git a/3rdparty/modules/staging/metadata.json b/3rdparty/modules/staging/metadata.json new file mode 100644 index 00000000..ea521206 --- /dev/null +++ b/3rdparty/modules/staging/metadata.json @@ -0,0 +1,106 @@ +{ + "name": "nanliu-staging", + "version": "1.0.3", + "author": "Nan Liu", + "summary": "Compressed file staging and deployment", + "license": "Apache-2.0", + "source": "git://github.com/nanliu/puppet-staging", + "project_page": "https://github.com/nanliu/puppet-staging", + "issues_url": "https://github.com/nanliu/puppet-staging/issues", + "operatingsystem_support": [ + { + "operatingsystem": "RedHat", + "operatingsystemrelease": [ + "4", + "5", + "6" + ] + }, + { + "operatingsystem": "CentOS", + "operatingsystemrelease": [ + "4", + "5", + "6" + ] + }, + { + "operatingsystem": "OracleLinux", + "operatingsystemrelease": [ + "4", + "5", + "6" + ] + }, + { + "operatingsystem": "Scientific", + "operatingsystemrelease": [ + "4", + "5", + "6" + ] + }, + { + "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" + ] + } + ], + "requirements": [ + { + "name": "pe", + "version_requirement": "3.x" + }, + { + "name": "puppet", + "version_requirement": ">=2.7.0 <4.0.0" + } + ], + "description": "Manages compressed file staging and deployment.", + "dependencies": [ + + ] +} diff --git a/3rdparty/modules/staging/spec/defines/staging_deploy_spec.rb b/3rdparty/modules/staging/spec/defines/staging_deploy_spec.rb new file mode 100644 index 00000000..2cfd3302 --- /dev/null +++ b/3rdparty/modules/staging/spec/defines/staging_deploy_spec.rb @@ -0,0 +1,27 @@ +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', + :staging_http_get => 'curl', + :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 diff --git a/3rdparty/modules/staging/spec/defines/staging_extract_spec.rb b/3rdparty/modules/staging/spec/defines/staging_extract_spec.rb new file mode 100644 index 00000000..84186b99 --- /dev/null +++ b/3rdparty/modules/staging/spec/defines/staging_extract_spec.rb @@ -0,0 +1,104 @@ +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 tar.gz with strip' do + let(:title) { 'sample.tar.gz' } + let(:params) { { :target => '/opt', + :strip => 1, } } + + it { + should contain_file('/opt/staging') + should contain_exec('extract sample.tar.gz').with({ + :command => 'tar xzf /opt/staging/spec/sample.tar.gz --strip=1', + :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 zip with strip (noop)' do + let(:title) { 'sample.zip' } + let(:params) { { :target => '/opt', + :strip => 1, } } + + 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 war with strip (noop)' do + let(:title) { 'sample.war' } + let(:params) { { :target => '/opt', + :strip => 1, } } + + 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 diff --git a/3rdparty/modules/staging/spec/defines/staging_file_spec.rb b/3rdparty/modules/staging/spec/defines/staging_file_spec.rb new file mode 100644 index 00000000..0a0b07f0 --- /dev/null +++ b/3rdparty/modules/staging/spec/defines/staging_file_spec.rb @@ -0,0 +1,163 @@ +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', + :osfamily => 'RedHat', + :staging_http_get => 'curl' } } + + 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 /opt/staging/spec/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 /opt/staging/spec/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', + :tries => '10', + :try_sleep => '6', + } } + + it { should contain_file('/opt/staging') + should contain_exec('/usr/local/sample.tar.gz').with( { + :command => 'curl -f -L -o /usr/local/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', + :tries => '10', + :try_sleep => '6', + }) + } + 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 /opt/staging/spec/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 /opt/staging/spec/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 /opt/staging/spec/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 /opt/staging/spec/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 diff --git a/3rdparty/modules/staging/spec/spec_helper.rb b/3rdparty/modules/staging/spec/spec_helper.rb new file mode 100644 index 00000000..ba15afe2 --- /dev/null +++ b/3rdparty/modules/staging/spec/spec_helper.rb @@ -0,0 +1,29 @@ +require 'rubygems' +require 'puppetlabs_spec_helper/module_spec_helper' + +RSpec.configure do |c| + 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]} + + if Gem::Version.new(`puppet --version`) >= Gem::Version.new('3.5') + Puppet.settings[:strict_variables]=true + end + if ENV['PARSER'] + Puppet.settings[:parser]=ENV['PARSER'] + end + end + + c.after :each do + PuppetlabsSpec::Files.cleanup + end +end diff --git a/3rdparty/modules/staging/spec/unit/puppet/parser/functions/scope_defaults_spec.rb b/3rdparty/modules/staging/spec/unit/puppet/parser/functions/scope_defaults_spec.rb new file mode 100644 index 00000000..50c460de --- /dev/null +++ b/3rdparty/modules/staging/spec/unit/puppet/parser/functions/scope_defaults_spec.rb @@ -0,0 +1,45 @@ +#!/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 diff --git a/3rdparty/modules/staging/spec/unit/puppet/parser/functions/staging_parse_spec.rb b/3rdparty/modules/staging/spec/unit/puppet/parser/functions/staging_parse_spec.rb new file mode 100644 index 00000000..c7c9c69f --- /dev/null +++ b/3rdparty/modules/staging/spec/unit/puppet/parser/functions/staging_parse_spec.rb @@ -0,0 +1,51 @@ +#!/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 diff --git a/3rdparty/modules/staging/tests/deploy.pp b/3rdparty/modules/staging/tests/deploy.pp new file mode 100644 index 00000000..cf9ac58d --- /dev/null +++ b/3rdparty/modules/staging/tests/deploy.pp @@ -0,0 +1,4 @@ +staging::deploy { 'sample.tar.gz': + source => 'puppet:///modules/staging/sample.tar.gz', + target => '/usr/local', +} diff --git a/3rdparty/modules/staging/tests/extract.pp b/3rdparty/modules/staging/tests/extract.pp new file mode 100644 index 00000000..257f478c --- /dev/null +++ b/3rdparty/modules/staging/tests/extract.pp @@ -0,0 +1,25 @@ +$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'], +} diff --git a/3rdparty/modules/staging/tests/file.pp b/3rdparty/modules/staging/tests/file.pp new file mode 100644 index 00000000..475cf562 --- /dev/null +++ b/3rdparty/modules/staging/tests/file.pp @@ -0,0 +1,17 @@ +$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', +} diff --git a/3rdparty/modules/staging/tests/init.pp b/3rdparty/modules/staging/tests/init.pp new file mode 100644 index 00000000..3015c10f --- /dev/null +++ b/3rdparty/modules/staging/tests/init.pp @@ -0,0 +1 @@ +include staging diff --git a/3rdparty/modules/staging/tests/scope_defaults.pp b/3rdparty/modules/staging/tests/scope_defaults.pp new file mode 100644 index 00000000..3073ff4a --- /dev/null +++ b/3rdparty/modules/staging/tests/scope_defaults.pp @@ -0,0 +1,7 @@ +Exec { + path => '/bin', +} + +if scope_defaults('Exec', 'path') { + notice('good') +} diff --git a/3rdparty/modules/staging/tests/staging_parse.pp b/3rdparty/modules/staging/tests/staging_parse.pp new file mode 100644 index 00000000..117ad166 --- /dev/null +++ b/3rdparty/modules/staging/tests/staging_parse.pp @@ -0,0 +1,12 @@ +$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) -- 2.39.2