puppet 2.7.8 → 2.7.9

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of puppet might be problematic. Click here for more details.

Files changed (98) hide show
  1. data/CHANGELOG +6 -0
  2. data/README_DEVELOPER.md +63 -0
  3. data/conf/redhat/puppet.spec +4 -1
  4. data/ext/puppetstoredconfigclean.rb +39 -27
  5. data/lib/puppet.rb +1 -1
  6. data/lib/puppet/application/agent.rb +33 -25
  7. data/lib/puppet/application/apply.rb +15 -1
  8. data/lib/puppet/application/module.rb +3 -0
  9. data/lib/puppet/defaults.rb +4 -0
  10. data/lib/puppet/face/module.rb +12 -0
  11. data/lib/puppet/face/module/build.rb +31 -0
  12. data/lib/puppet/face/module/changes.rb +38 -0
  13. data/lib/puppet/face/module/clean.rb +30 -0
  14. data/lib/puppet/face/module/generate.rb +40 -0
  15. data/lib/puppet/face/module/install.rb +83 -0
  16. data/lib/puppet/face/module/search.rb +66 -0
  17. data/lib/puppet/indirector/exec.rb +1 -1
  18. data/lib/puppet/module_tool.rb +97 -0
  19. data/lib/puppet/module_tool/applications.rb +12 -0
  20. data/lib/puppet/module_tool/applications/application.rb +83 -0
  21. data/lib/puppet/module_tool/applications/builder.rb +91 -0
  22. data/lib/puppet/module_tool/applications/checksummer.rb +47 -0
  23. data/lib/puppet/module_tool/applications/cleaner.rb +16 -0
  24. data/lib/puppet/module_tool/applications/generator.rb +141 -0
  25. data/lib/puppet/module_tool/applications/installer.rb +89 -0
  26. data/lib/puppet/module_tool/applications/searcher.rb +40 -0
  27. data/lib/puppet/module_tool/applications/unpacker.rb +70 -0
  28. data/lib/puppet/module_tool/cache.rb +56 -0
  29. data/lib/puppet/module_tool/checksums.rb +52 -0
  30. data/lib/puppet/module_tool/contents_description.rb +82 -0
  31. data/lib/puppet/module_tool/dependency.rb +24 -0
  32. data/lib/puppet/module_tool/metadata.rb +141 -0
  33. data/lib/puppet/module_tool/modulefile.rb +75 -0
  34. data/lib/puppet/module_tool/repository.rb +79 -0
  35. data/lib/puppet/module_tool/skeleton.rb +34 -0
  36. data/lib/puppet/module_tool/skeleton/templates/generator/Modulefile.erb +11 -0
  37. data/lib/puppet/module_tool/skeleton/templates/generator/README.erb +16 -0
  38. data/lib/puppet/module_tool/skeleton/templates/generator/manifests/init.pp.erb +41 -0
  39. data/lib/puppet/module_tool/skeleton/templates/generator/metadata.json +12 -0
  40. data/lib/puppet/module_tool/skeleton/templates/generator/spec/spec_helper.rb +17 -0
  41. data/lib/puppet/module_tool/skeleton/templates/generator/tests/init.pp.erb +11 -0
  42. data/lib/puppet/module_tool/utils.rb +5 -0
  43. data/lib/puppet/module_tool/utils/interrogation.rb +25 -0
  44. data/lib/puppet/network/http/api/v1.rb +2 -1
  45. data/lib/puppet/parser/functions/create_resources.rb +19 -4
  46. data/lib/puppet/rails.rb +1 -1
  47. data/lib/puppet/rails/database/schema.rb +1 -1
  48. data/lib/puppet/ssl/host.rb +16 -8
  49. data/lib/puppet/transaction.rb +1 -1
  50. data/lib/puppet/type/file.rb +7 -2
  51. data/lib/puppet/type/file/ctime.rb +1 -1
  52. data/lib/puppet/type/file/mtime.rb +1 -1
  53. data/lib/puppet/type/file/type.rb +1 -1
  54. data/lib/puppet/util/queue/stomp.rb +19 -6
  55. data/lib/puppet/util/zaml.rb +39 -5
  56. data/spec/fixtures/releases/jamtur01-apache/Modulefile +2 -0
  57. data/spec/fixtures/releases/jamtur01-apache/files/httpd +24 -0
  58. data/spec/fixtures/releases/jamtur01-apache/files/test.vhost +18 -0
  59. data/spec/fixtures/releases/jamtur01-apache/lib/puppet/provider/a2mod/debian.rb +21 -0
  60. data/spec/fixtures/releases/jamtur01-apache/lib/puppet/type/a2mod.rb +12 -0
  61. data/spec/fixtures/releases/jamtur01-apache/manifests/dev.pp +5 -0
  62. data/spec/fixtures/releases/jamtur01-apache/manifests/init.pp +34 -0
  63. data/spec/fixtures/releases/jamtur01-apache/manifests/params.pp +17 -0
  64. data/spec/fixtures/releases/jamtur01-apache/manifests/php.pp +5 -0
  65. data/spec/fixtures/releases/jamtur01-apache/manifests/ssl.pp +15 -0
  66. data/spec/fixtures/releases/jamtur01-apache/manifests/vhost.pp +15 -0
  67. data/spec/fixtures/releases/jamtur01-apache/metadata.json +1 -0
  68. data/spec/fixtures/releases/jamtur01-apache/templates/vhost-default.conf.erb +20 -0
  69. data/spec/fixtures/releases/jamtur01-apache/tests/apache.pp +1 -0
  70. data/spec/fixtures/releases/jamtur01-apache/tests/dev.pp +1 -0
  71. data/spec/fixtures/releases/jamtur01-apache/tests/init.pp +1 -0
  72. data/spec/fixtures/releases/jamtur01-apache/tests/php.pp +1 -0
  73. data/spec/fixtures/releases/jamtur01-apache/tests/ssl.pp +1 -0
  74. data/spec/fixtures/releases/jamtur01-apache/tests/vhost.pp +2 -0
  75. data/spec/integration/module_tool_spec.rb +477 -0
  76. data/spec/integration/util/windows/security_spec.rb +1 -1
  77. data/spec/unit/application/agent_spec.rb +26 -0
  78. data/spec/unit/application/apply_spec.rb +12 -1
  79. data/spec/unit/face/module/build_spec.rb +30 -0
  80. data/spec/unit/face/module/changes_spec.rb +30 -0
  81. data/spec/unit/face/module/clean_spec.rb +30 -0
  82. data/spec/unit/face/module/generate_spec.rb +30 -0
  83. data/spec/unit/face/module/install_spec.rb +75 -0
  84. data/spec/unit/face/module/search_spec.rb +40 -0
  85. data/spec/unit/face/module_spec.rb +3 -0
  86. data/spec/unit/file_bucket/dipper_spec.rb +1 -1
  87. data/spec/unit/module_tool/application_spec.rb +29 -0
  88. data/spec/unit/module_tool/metadata_spec.rb +11 -0
  89. data/spec/unit/module_tool/repository_spec.rb +52 -0
  90. data/spec/unit/module_tool_spec.rb +38 -0
  91. data/spec/unit/network/http/api/v1_spec.rb +4 -0
  92. data/spec/unit/parser/functions/create_resources_spec.rb +21 -4
  93. data/spec/unit/rails_spec.rb +89 -158
  94. data/spec/unit/ssl/host_spec.rb +10 -33
  95. data/spec/unit/type/file_spec.rb +30 -0
  96. data/spec/unit/util/queue/stomp_spec.rb +9 -4
  97. data/spec/unit/util/zaml_spec.rb +37 -0
  98. metadata +77 -11
@@ -0,0 +1,47 @@
1
+ module Puppet::Module::Tool
2
+ module Applications
3
+ class Checksummer < Application
4
+
5
+ def initialize(path, options = {})
6
+ @path = Pathname.new(path)
7
+ super(options)
8
+ end
9
+
10
+ def run
11
+ changes = []
12
+ if metadata_file.exist?
13
+ sums = Checksums.new(@path)
14
+ (metadata['checksums'] || {}).each do |child_path, canonical_checksum|
15
+ path = @path + child_path
16
+ if canonical_checksum != sums.checksum(path)
17
+ changes << child_path
18
+ end
19
+ end
20
+ else
21
+ raise ArgumentError, "No metadata.json found."
22
+ end
23
+
24
+ # Return an Array of strings representing file paths of files that have
25
+ # been modified since this module was installed. All paths are relative
26
+ # to the installed module directory. This return value is used by the
27
+ # module_tool face changes action, and displayed on the console.
28
+ #
29
+ # Example return value:
30
+ #
31
+ # [ "REVISION", "metadata.json", "manifests/init.pp"]
32
+ #
33
+ changes
34
+ end
35
+
36
+ private
37
+
38
+ def metadata
39
+ PSON.parse(metadata_file.read)
40
+ end
41
+
42
+ def metadata_file
43
+ (@path + 'metadata.json')
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,16 @@
1
+ module Puppet::Module::Tool
2
+ module Applications
3
+ class Cleaner < Application
4
+ def run
5
+ Puppet::Module::Tool::Cache.clean
6
+
7
+ # Return a status Hash containing the status of the clean command
8
+ # and a status message. This return value is used by the module_tool
9
+ # face clean action, and the status message, return_value[:msg], is
10
+ # displayed on the console.
11
+ #
12
+ { :status => "success", :msg => "Cleaned module cache." }
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,141 @@
1
+ require 'pathname'
2
+ require 'fileutils'
3
+ require 'erb'
4
+
5
+ module Puppet::Module::Tool
6
+ module Applications
7
+ class Generator < Application
8
+
9
+ def initialize(full_module_name, options = {})
10
+ begin
11
+ @metadata = Metadata.new(:full_module_name => full_module_name)
12
+ rescue ArgumentError
13
+ raise "Could not generate directory #{full_module_name.inspect}, you must specify a dash-separated username and module name."
14
+ end
15
+ super(options)
16
+ end
17
+
18
+ def skeleton
19
+ @skeleton ||= Skeleton.new
20
+ end
21
+
22
+ def get_binding
23
+ binding
24
+ end
25
+
26
+ def run
27
+ if destination.directory?
28
+ raise ArgumentError, "#{destination} already exists."
29
+ end
30
+ Puppet.notice "Generating module at #{Dir.pwd}/#{@metadata.dashed_name}"
31
+ files_created = []
32
+ skeleton.path.find do |path|
33
+ if path == skeleton
34
+ destination.mkpath
35
+ else
36
+ node = Node.on(path, self)
37
+ if node
38
+ node.install!
39
+ files_created << node.target
40
+ else
41
+ Puppet.notice "Could not generate from #{path}"
42
+ end
43
+ end
44
+ end
45
+
46
+ # Return an array of Pathname objects representing file paths of files
47
+ # and directories just generated. This return value is used by the
48
+ # module_tool face generate action, and displayed on the console.
49
+ #
50
+ # Example return value:
51
+ #
52
+ # [
53
+ # #<Pathname:puppetlabs-apache>,
54
+ # #<Pathname:puppetlabs-apache/tests>,
55
+ # #<Pathname:puppetlabs-apache/tests/init.pp>,
56
+ # #<Pathname:puppetlabs-apache/spec>,
57
+ # #<Pathname:puppetlabs-apache/spec/spec_helper.rb>,
58
+ # #<Pathname:puppetlabs-apache/spec/spec.opts>,
59
+ # #<Pathname:puppetlabs-apache/README>,
60
+ # #<Pathname:puppetlabs-apache/Modulefile>,
61
+ # #<Pathname:puppetlabs-apache/metadata.json>,
62
+ # #<Pathname:puppetlabs-apache/manifests>,
63
+ # #<Pathname:puppetlabs-apache/manifests/init.pp"
64
+ # ]
65
+ #
66
+ files_created
67
+ end
68
+
69
+ def destination
70
+ @destination ||= Pathname.new(@metadata.dashed_name)
71
+ end
72
+
73
+ class Node
74
+ def self.types
75
+ @types ||= []
76
+ end
77
+ def self.inherited(klass)
78
+ types << klass
79
+ end
80
+ def self.on(path, generator)
81
+ klass = types.detect { |t| t.matches?(path) }
82
+ if klass
83
+ klass.new(path, generator)
84
+ end
85
+ end
86
+ def initialize(source, generator)
87
+ @generator = generator
88
+ @source = source
89
+ end
90
+ def read
91
+ @source.read
92
+ end
93
+ def target
94
+ target = @generator.destination + @source.relative_path_from(@generator.skeleton.path)
95
+ components = target.to_s.split(File::SEPARATOR).map do |part|
96
+ part == 'NAME' ? @generator.metadata.name : part
97
+ end
98
+ Pathname.new(components.join(File::SEPARATOR))
99
+ end
100
+ def install!
101
+ raise NotImplementedError, "Abstract"
102
+ end
103
+ end
104
+
105
+ class DirectoryNode < Node
106
+ def self.matches?(path)
107
+ path.directory?
108
+ end
109
+ def install!
110
+ target.mkpath
111
+ end
112
+ end
113
+
114
+ class ParsedFileNode < Node
115
+ def self.matches?(path)
116
+ path.file? && path.extname == '.erb'
117
+ end
118
+ def target
119
+ path = super
120
+ path.parent + path.basename('.erb')
121
+ end
122
+ def contents
123
+ template = ERB.new(read)
124
+ template.result(@generator.send(:get_binding))
125
+ end
126
+ def install!
127
+ target.open('w') { |f| f.write contents }
128
+ end
129
+ end
130
+
131
+ class FileNode < Node
132
+ def self.matches?(path)
133
+ path.file?
134
+ end
135
+ def install!
136
+ FileUtils.cp(@source, target)
137
+ end
138
+ end
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,89 @@
1
+ require 'open-uri'
2
+ require 'pathname'
3
+ require 'tmpdir'
4
+
5
+ module Puppet::Module::Tool
6
+ module Applications
7
+ class Installer < Application
8
+
9
+ def initialize(name, options = {})
10
+ if File.exist?(name)
11
+ if File.directory?(name)
12
+ # TODO Unify this handling with that of Unpacker#check_clobber!
13
+ raise ArgumentError, "Module already installed: #{name}"
14
+ end
15
+ @source = :filesystem
16
+ @filename = File.expand_path(name)
17
+ parse_filename!
18
+ else
19
+ @source = :repository
20
+ begin
21
+ @username, @module_name = Puppet::Module::Tool::username_and_modname_from(name)
22
+ rescue ArgumentError
23
+ raise "Could not install module with invalid name: #{name}"
24
+ end
25
+ @version_requirement = options[:version]
26
+ end
27
+ super(options)
28
+ end
29
+
30
+ def force?
31
+ options[:force]
32
+ end
33
+
34
+ def run
35
+ case @source
36
+ when :repository
37
+ if match['file']
38
+ begin
39
+ cache_path = repository.retrieve(match['file'])
40
+ rescue OpenURI::HTTPError => e
41
+ raise RuntimeError, "Could not install module: #{e.message}"
42
+ end
43
+ module_dir = Unpacker.run(cache_path, options)
44
+ else
45
+ raise RuntimeError, "Malformed response from module repository."
46
+ end
47
+ when :filesystem
48
+ repository = Repository.new('file:///')
49
+ uri = URI.parse("file://#{URI.escape(File.expand_path(@filename))}")
50
+ cache_path = repository.retrieve(uri)
51
+ module_dir = Unpacker.run(cache_path, options)
52
+ else
53
+ raise ArgumentError, "Could not determine installation source"
54
+ end
55
+
56
+ # Return the Pathname object representing the path to the installed
57
+ # module. This return value is used by the module_tool face install
58
+ # action, and displayed to on the console.
59
+ #
60
+ # Example return value:
61
+ #
62
+ # "/etc/puppet/modules/apache"
63
+ #
64
+ module_dir
65
+ end
66
+
67
+ private
68
+
69
+ def match
70
+ return @match ||= begin
71
+ url = repository.uri + "/users/#{@username}/modules/#{@module_name}/releases/find.json"
72
+ if @version_requirement
73
+ url.query = "version=#{URI.escape(@version_requirement)}"
74
+ end
75
+ begin
76
+ raw_result = read_match(url)
77
+ rescue => e
78
+ raise ArgumentError, "Could not find a release for this module (#{e.message})"
79
+ end
80
+ @match = PSON.parse(raw_result)
81
+ end
82
+ end
83
+
84
+ def read_match(url)
85
+ return url.read
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,40 @@
1
+ module Puppet::Module::Tool
2
+ module Applications
3
+ class Searcher < Application
4
+
5
+ def initialize(term, options = {})
6
+ @term = term
7
+ super(options)
8
+ end
9
+
10
+ def run
11
+ request = Net::HTTP::Get.new("/modules.json?q=#{URI.escape(@term)}")
12
+ response = repository.make_http_request(request)
13
+ case response
14
+ when Net::HTTPOK
15
+ matches = PSON.parse(response.body)
16
+ else
17
+ raise RuntimeError, "Could not execute search (HTTP #{response.code})"
18
+ matches = []
19
+ end
20
+
21
+ # Return a list of module metadata hashes that match the search query.
22
+ # This return value is used by the module_tool face install search,
23
+ # and displayed to on the console.
24
+ #
25
+ # Example return value:
26
+ #
27
+ # [
28
+ # {
29
+ # "name" => "nginx",
30
+ # "project_url" => "http://github.com/puppetlabs/puppetlabs-nginx",
31
+ # "version" => "0.0.1",
32
+ # "full_name" => "puppetlabs/nginx" # full_name comes back from
33
+ # } # API all to the forge.
34
+ # ]
35
+ #
36
+ matches
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,70 @@
1
+ require 'pathname'
2
+ require 'tmpdir'
3
+
4
+ module Puppet::Module::Tool
5
+ module Applications
6
+ class Unpacker < Application
7
+
8
+ def initialize(filename, options = {})
9
+ @filename = Pathname.new(filename)
10
+ parse_filename!
11
+ super(options)
12
+ @module_dir = Pathname.new(options[:install_dir]) + @module_name
13
+ end
14
+
15
+ def run
16
+ extract_module_to_install_dir
17
+ tag_revision
18
+
19
+ # Return the Pathname object representing the directory where the
20
+ # module release archive was unpacked the to, and the module release
21
+ # name.
22
+ @module_dir
23
+ end
24
+
25
+ private
26
+
27
+ def tag_revision
28
+ File.open("#{@module_dir}/REVISION", 'w') do |f|
29
+ f.puts "module: #{@username}/#{@module_name}"
30
+ f.puts "version: #{@version}"
31
+ f.puts "url: file://#{@filename.expand_path}"
32
+ f.puts "installed: #{Time.now}"
33
+ end
34
+ end
35
+
36
+ def extract_module_to_install_dir
37
+ delete_existing_installation_or_abort!
38
+
39
+ build_dir = Puppet::Module::Tool::Cache.base_path + "tmp-unpacker-#{Digest::SHA1.hexdigest(@filename.basename.to_s)}"
40
+ build_dir.mkpath
41
+ begin
42
+ Puppet.notice "Installing #{@filename.basename} to #{@module_dir.expand_path}"
43
+ unless system "tar xzf #{@filename} -C #{build_dir}"
44
+ raise RuntimeError, "Could not extract contents of module archive."
45
+ end
46
+ # grab the first directory
47
+ extracted = build_dir.children.detect { |c| c.directory? }
48
+ FileUtils.mv extracted, @module_dir
49
+ ensure
50
+ build_dir.rmtree
51
+ end
52
+ end
53
+
54
+ def delete_existing_installation_or_abort!
55
+ return unless @module_dir.exist?
56
+
57
+ if !options[:force]
58
+ Puppet.warning "Existing module '#{@module_dir.expand_path}' found"
59
+ response = prompt "Overwrite module installed at #{@module_dir.expand_path}? [y/N]"
60
+ unless response =~ /y/i
61
+ raise RuntimeError, "Aborted installation."
62
+ end
63
+ end
64
+
65
+ Puppet.warning "Deleting #{@module_dir.expand_path}"
66
+ FileUtils.rm_rf @module_dir
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,56 @@
1
+ require 'uri'
2
+
3
+ module Puppet::Module::Tool
4
+
5
+ # = Cache
6
+ #
7
+ # Provides methods for reading files from local cache, filesystem or network.
8
+ class Cache
9
+
10
+ # Instantiate new cahe for the +repositry+ instance.
11
+ def initialize(repository, options = {})
12
+ @repository = repository
13
+ @options = options
14
+ end
15
+
16
+ # Return filename retrieved from +uri+ instance. Will download this file and
17
+ # cache it if needed.
18
+ #
19
+ # TODO: Add checksum support.
20
+ # TODO: Add error checking.
21
+ def retrieve(url)
22
+ (path + File.basename(url.to_s)).tap do |cached_file|
23
+ uri = url.is_a?(::URI) ? url : ::URI.parse(url)
24
+ unless cached_file.file?
25
+ if uri.scheme == 'file'
26
+ FileUtils.cp(URI.unescape(uri.path), cached_file)
27
+ else
28
+ # TODO: Handle HTTPS; probably should use repository.contact
29
+ data = read_retrieve(uri)
30
+ cached_file.open('wb') { |f| f.write data }
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+ # Return contents of file at the given URI's +uri+.
37
+ def read_retrieve(uri)
38
+ return uri.read
39
+ end
40
+
41
+ # Return Pathname for repository's cache directory, create it if needed.
42
+ def path
43
+ return @path ||= (self.class.base_path + @repository.cache_key).tap{ |o| o.mkpath }
44
+ end
45
+
46
+ # Return the base Pathname for all the caches.
47
+ def self.base_path
48
+ Pathname(Puppet.settings[:module_working_dir]) + 'cache'
49
+ end
50
+
51
+ # Clean out all the caches.
52
+ def self.clean
53
+ base_path.rmtree if base_path.exist?
54
+ end
55
+ end
56
+ end