puppet-resource_api 1.3.0 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 48ed58d882063171b3d9cd9b0711403cf6d8bc0c213aa98d0583d2b0bf8746a7
4
- data.tar.gz: c6acb1edb2ee5b1cefe1cb0449090ee3072e380632952d82948b6eb2455a49b4
3
+ metadata.gz: e87d10235bb663c8a935d0ff8e1c50dc468e953255d96dd075df6c47e169a171
4
+ data.tar.gz: 91560d8c900e70924b4f9ca4c527a8100d3ad5604a0403227440a4e82f1eb00a
5
5
  SHA512:
6
- metadata.gz: 4fc8c73ce49206569836f00aa1c52380b1571055ccc3f6842577a6c890c657b19280ad9b6c09e376db8acc3b63daa700cebe6d64c47571d464df797ba1b0e482
7
- data.tar.gz: 9e64c5cc2d4474014ed8f45d66b44ad0416874f29b6b2f6c5b0a0da01e93179525d3eee33029f3e28eaa29acb5f5ea2d537935265f608d23610e63d51e5b3ec3
6
+ metadata.gz: ef62b7f3ac5119b64136f54200818d5753bf4612636560135724e2621d200c4067e07e700507613d54461a2c5eaf13be02aa0892fc8b2ed230fa66f163566ad2
7
+ data.tar.gz: fd919bff975e27af3807cd0c1818ee50c4166e26ba55b136bb5a432b11ee4a1228478525ade80aa954579389d59ef2114eb247abdb16b062509d800e149a82b9
data/.rspec CHANGED
@@ -1,2 +1,3 @@
1
1
  --format documentation
2
2
  --color
3
+ --order rand:123
data/.rubocop.yml CHANGED
@@ -154,3 +154,7 @@ Naming/UncommunicativeMethodParamName:
154
154
  - id
155
155
  - is
156
156
  ForbiddenNames: []
157
+
158
+ # This cop breaks syntax highlighting in VSCode
159
+ Layout/ClosingHeredocIndentation:
160
+ Enabled: false
data/.travis.yml CHANGED
@@ -6,7 +6,7 @@ script:
6
6
  - cat Gemfile.lock
7
7
  - bundle list
8
8
  - echo travis_fold:end:DEBUG
9
- - COVERAGE=yes bundle exec rake $CHECK
9
+ - bundle exec rake $CHECK
10
10
  cache: bundler
11
11
  branches:
12
12
  except:
@@ -14,13 +14,14 @@ branches:
14
14
  matrix:
15
15
  include:
16
16
  - rvm: 2.4.3
17
- env: PUPPET_GEM_VERSION='~> 5' # 5.5
18
- - env: RVM="jruby-1.7.26" PUPPET_GEM_VERSION='~> 5' JRUBY_OPTS="--debug"
17
+ env: PUPPET_GEM_VERSION='~> 5' COVERAGE=yes # 5.5
18
+ - env: RVM="jruby-1.7.26" PUPPET_GEM_VERSION='~> 5' JRUBY_OPTS="--debug" COVERAGE=yes
19
19
  before_cache: pushd ~/.rvm && rm -rf archives rubies/ruby-2.2.7 rubies/ruby-2.3.4 && popd
20
20
  cache:
21
21
  bundler: true
22
22
  directories: ~/.rvm
23
23
  before_install: rvm use jruby-1.7.26 --install --binary --fuzzy
24
+ # disable coverage on jruby9k as this confuses codecov
24
25
  - env: RVM="jruby-9.1.9.0" PUPPET_GEM_VERSION='~> 5' JRUBY_OPTS="--debug"
25
26
  before_cache: pushd ~/.rvm && rm -rf archives rubies/ruby-2.2.7 rubies/ruby-2.3.4 && popd
26
27
  cache:
@@ -44,7 +45,7 @@ matrix:
44
45
  - rvm: 2.4.1
45
46
  env: PUPPET_GEM_VERSION='~> 5.0.0'
46
47
  - rvm: 2.1.9
47
- env: PUPPET_GEM_VERSION='~> 4' # 4.10
48
+ env: PUPPET_GEM_VERSION='~> 4' COVERAGE=yes # 4.10
48
49
  - rvm: 2.1.9
49
50
  env: PUPPET_GEM_VERSION='~> 4.9.0'
50
51
  - rvm: 2.1.9
data/CHANGELOG.md CHANGED
@@ -3,6 +3,33 @@
3
3
  All significant changes to this repo will be summarized in this file.
4
4
 
5
5
 
6
+ ## [v1.4.0](https://github.com/puppetlabs/puppet-resource_api/tree/v1.4.0) (2018-06-19)
7
+ [Full Changelog](https://github.com/puppetlabs/puppet-resource_api/compare/v1.3.0...v1.4.0)
8
+
9
+ **Implemented enhancements:**
10
+
11
+ - Allow `SimpleDevice` to be initialized with a config hash [\#96](https://github.com/puppetlabs/puppet-resource_api/pull/96) ([DavidS](https://github.com/DavidS))
12
+ - \(PDK-1007\) implement enough to support purge=\>true [\#95](https://github.com/puppetlabs/puppet-resource_api/pull/95) ([DavidS](https://github.com/DavidS))
13
+ - \(PDK-917\) Validates provider.get values against Type schema [\#88](https://github.com/puppetlabs/puppet-resource_api/pull/88) ([da-ar](https://github.com/da-ar))
14
+
15
+ **Fixed bugs:**
16
+
17
+ - \(PDK-1004\) log exceptions as they are processed [\#101](https://github.com/puppetlabs/puppet-resource_api/pull/101) ([DavidS](https://github.com/DavidS))
18
+ - \(PDK-1000\) do not print nil valued attributes [\#100](https://github.com/puppetlabs/puppet-resource_api/pull/100) ([DavidS](https://github.com/DavidS))
19
+ - \(PDK-1007\) Handle setting `ensure` to a Symbol through code [\#94](https://github.com/puppetlabs/puppet-resource_api/pull/94) ([DavidS](https://github.com/DavidS))
20
+ - \(PDK-1007\) the namevar is a param [\#91](https://github.com/puppetlabs/puppet-resource_api/pull/91) ([DavidS](https://github.com/DavidS))
21
+ - \(PDK-996\) Provide better messaging when type cannot be resolved [\#87](https://github.com/puppetlabs/puppet-resource_api/pull/87) ([da-ar](https://github.com/da-ar))
22
+
23
+ **Merged pull requests:**
24
+
25
+ - Whitespace cleanup with new rubocop version [\#98](https://github.com/puppetlabs/puppet-resource_api/pull/98) ([DavidS](https://github.com/DavidS))
26
+ - \(PDK-1007\) add tests for `to\_resource` [\#93](https://github.com/puppetlabs/puppet-resource_api/pull/93) ([DavidS](https://github.com/DavidS))
27
+ - Enable randomised rspec testing [\#92](https://github.com/puppetlabs/puppet-resource_api/pull/92) ([da-ar](https://github.com/da-ar))
28
+ - appease rubocop 0.57.0 [\#90](https://github.com/puppetlabs/puppet-resource_api/pull/90) ([da-ar](https://github.com/da-ar))
29
+ - Improve unit tests of parameter and property results after register\_type [\#89](https://github.com/puppetlabs/puppet-resource_api/pull/89) ([DavidS](https://github.com/DavidS))
30
+ - Update release docs and announcement template [\#86](https://github.com/puppetlabs/puppet-resource_api/pull/86) ([DavidS](https://github.com/DavidS))
31
+ - Release prep for v1.3.0 [\#85](https://github.com/puppetlabs/puppet-resource_api/pull/85) ([da-ar](https://github.com/da-ar))
32
+
6
33
  ## [v1.3.0](https://github.com/puppetlabs/puppet-resource_api/tree/v1.3.0) (2018-05-24)
7
34
  [Full Changelog](https://github.com/puppetlabs/puppet-resource_api/compare/v1.2.0...v1.3.0)
8
35
 
data/CONTRIBUTING.md CHANGED
@@ -1,11 +1 @@
1
- # Contributing
2
-
3
- We welcome error reports and patches to the puppet-resource\_api repository. Post questions to [puppet-users@groups.google.com](https://groups.google.com/forum/#!forum/puppet-users). Post bug reports and pull requests on GitHub at https://github.com/puppetlabs/puppet-resource_api/issues.
4
-
5
- # Running tests
6
-
7
- puppet-resource\_api has the following testing Rake tasks.
8
-
9
- ## spec
10
-
11
- Runs unit tests.
1
+ Please see [the Contributing section in the README](https://github.com/puppetlabs/puppet-resource_api#contributing) for contributing guidelines.
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # Puppet::ResourceApi [![TravisCI Build Status](https://travis-ci.org/puppetlabs/puppet-resource_api.svg?branch=master)](https://travis-ci.org/puppetlabs/puppet-resource_api) [![Appveyor Build status](https://ci.appveyor.com/api/projects/status/8o9s1ax0hs8lm5fd/branch/master?svg=true)](https://ci.appveyor.com/project/puppetlabs/puppet-resource-api/branch/master)
2
2
  [![codecov](https://codecov.io/gh/puppetlabs/puppet-resource_api/branch/master/graph/badge.svg)](https://codecov.io/gh/puppetlabs/puppet-resource_api)
3
3
 
4
- This is an implementation of the [Resource API](https://github.com/DavidS/puppet-specifications/blob/resourceapi/language/resource-api/README.md) proposal. Find a working example of a new-style provider in the [experimental puppetlabs-apt branch](https://github.com/DavidS/puppetlabs-apt/blob/resource-api-experiments/lib/puppet/provider/apt_key2/apt_key2.rb). There is also the corresponding [type](https://github.com/DavidS/puppetlabs-apt/blob/resource-api-experiments/lib/puppet/type/apt_key2.rb), [provider](https://github.com/DavidS/puppetlabs-apt/blob/resource-api-experiments/lib/puppet/provider/apt_key2/apt_key2.rb), and [new unit tests](https://github.com/DavidS/puppetlabs-apt/blob/resource-api-experiments/spec/unit/puppet/provider/apt_key2/apt_key2_spec.rb) for 100% coverage.
4
+ This is an implementation of the [Resource API](https://github.com/puppetlabs/puppet-specifications/blob/master/language/resource-api/README.md) proposal. Find a working example of a new-style provider in the [experimental puppetlabs-apt branch](https://github.com/DavidS/puppetlabs-apt/blob/resource-api-experiments/lib/puppet/provider/apt_key2/apt_key2.rb). There is also the corresponding [type](https://github.com/DavidS/puppetlabs-apt/blob/resource-api-experiments/lib/puppet/type/apt_key2.rb), [provider](https://github.com/DavidS/puppetlabs-apt/blob/resource-api-experiments/lib/puppet/provider/apt_key2/apt_key2.rb), and [new unit tests](https://github.com/DavidS/puppetlabs-apt/blob/resource-api-experiments/spec/unit/puppet/provider/apt_key2/apt_key2_spec.rb) for 100% coverage.
5
5
 
6
6
  ## Getting started
7
7
 
@@ -176,7 +176,7 @@ After this, `puppet device` will be able to use the new provider, and supply it
176
176
 
177
177
  ### Further Reading
178
178
 
179
- The [Resource API](https://github.com/DavidS/puppet-specifications/blob/resourceapi/language/resource-api/README.md) describes details of all the capabilities of this gem.
179
+ The [Resource API](https://github.com/puppetlabs/puppet-specifications/blob/master/language/resource-api/README.md) describes details of all the capabilities of this gem.
180
180
 
181
181
  This [Introduction to Testing Puppet Modules](https://www.netways.de/index.php?id=3445#c44135) talk describes rspec usage in more detail.
182
182
 
@@ -239,9 +239,10 @@ To cut a new release, from a current `master` checkout:
239
239
  * run `rake changelog`
240
240
  * double check the PRs to make sure they're all tagged correctly (using the new CHANGELOG for cross-checking)
241
241
  * Check README and other materials for up-to-date-ness
242
- * Commit changes with title "Release prep for v<VERSION>"
242
+ * Commit changes with title "Release prep for v\<VERSION>"
243
243
  * Upload and PR the release-prep branch to the puppetlabs GitHub repo
244
244
  * Check that CI is green and merge the PR
245
245
  * Run `rake release[upstream]` to release from your checkout
246
246
  * make sure to use the name of your git remote pointing to the puppetlabs GitHub repo
247
247
  * Remove the release-prep branch
248
+ * Send the release announcements using the template in [misc/ANNOUNCEMENT_TEMPLATE.md](misc/ANNOUNCEMENT_TEMPLATE.md)
data/contrib/pre-commit CHANGED
@@ -2,15 +2,7 @@
2
2
  # Code modified from: https://gist.github.com/hanloong/9849098
3
3
  require 'English'
4
4
 
5
- ADDED = %r{A|AM}
6
-
7
- changed_files = `git status --porcelain`.split(%r{\n})
8
- changed_files = changed_files.select do |file_name_with_status|
9
- file_name_with_status =~ ADDED
10
- end
11
- changed_files = changed_files.map do |file_name_with_status|
12
- file_name_with_status.split(' ')[1]
13
- end
5
+ changed_files = `git diff --name-only --cached --diff-filter=ACM`.split(%r{\n})
14
6
  changed_files = changed_files.select { |file_name|
15
7
  File.extname(file_name) == '.rb'
16
8
  }.join(' ')
@@ -20,4 +12,5 @@ system("bundle exec rubocop -a #{changed_files}") unless changed_files.empty?
20
12
  if $CHILD_STATUS.to_s[-1].to_i.zero? && !changed_files.empty?
21
13
  system("git add #{changed_files}")
22
14
  end
15
+
23
16
  exit $CHILD_STATUS.to_s[-1].to_i
@@ -51,7 +51,7 @@ class Puppet::ResourceApi::BaseContext
51
51
  block.call
52
52
  notice("Finished in #{format_seconds(Time.now - start_time)} seconds")
53
53
  rescue StandardError => e
54
- err("Failed after #{format_seconds(Time.now - start_time)} seconds: #{e}")
54
+ log_exception(e, message: "Failed after #{format_seconds(Time.now - start_time)} seconds")
55
55
  @failed = true
56
56
  ensure
57
57
  @context = nil
@@ -67,7 +67,7 @@ class Puppet::ResourceApi::BaseContext
67
67
  yield
68
68
  warning("Finished failing in #{format_seconds(Time.now - start_time)} seconds")
69
69
  rescue StandardError => e
70
- err("Failed after #{format_seconds(Time.now - start_time)} seconds: #{e}")
70
+ log_exception(e, message: "Failed after #{format_seconds(Time.now - start_time)} seconds")
71
71
  @failed = true
72
72
  ensure
73
73
  @context = nil
@@ -83,7 +83,7 @@ class Puppet::ResourceApi::BaseContext
83
83
  yield
84
84
  notice("Finished processing #{title} in #{format_seconds(Time.now - start_time)} seconds: #{should}")
85
85
  rescue StandardError => e
86
- err("Failed processing #{title} after #{format_seconds(Time.now - start_time)} seconds: #{e}")
86
+ log_exception(e, message: "Failed processing #{title} after #{format_seconds(Time.now - start_time)} seconds")
87
87
  @failed = true
88
88
  ensure
89
89
  @context = nil
@@ -124,6 +124,15 @@ class Puppet::ResourceApi::BaseContext
124
124
  end
125
125
  end
126
126
 
127
+ def log_exception(exception, message: 'Error encountered', trace: false)
128
+ message = "#{message}: #{exception}"
129
+ if trace
130
+ message += "\n"
131
+ message += exception.backtrace.join("\n")
132
+ end
133
+ err(message)
134
+ end
135
+
127
136
  def send_log(_level, _message)
128
137
  raise 'Received send_log() on an unprepared BaseContext. Use IOContext, or PuppetContext instead.'
129
138
  end
@@ -2,29 +2,6 @@ require 'yaml'
2
2
 
3
3
  module Puppet; end # rubocop:disable Style/Documentation
4
4
  module Puppet::ResourceApi
5
- # A trivial class to provide the functionality required to push data through the existing type/provider parts of puppet
6
- class TypeShim
7
- attr_reader :values, :typename, :namevars, :attr_def
8
-
9
- def initialize(resource_hash, typename, namevars, attr_def)
10
- # internalize and protect - needs to go deeper
11
- @values = resource_hash.dup.freeze
12
-
13
- @typename = typename
14
- @namevars = namevars
15
- @attr_def = attr_def
16
- @resource = ResourceShim.new(@values, @typename, @namevars, @attr_def)
17
- end
18
-
19
- def to_resource
20
- @resource
21
- end
22
-
23
- def name
24
- @resource.title
25
- end
26
- end
27
-
28
5
  # A trivial class to provide the functionality required to push data through the existing type/provider parts of puppet
29
6
  class ResourceShim
30
7
  attr_reader :values, :typename, :namevars, :attr_def
@@ -37,7 +14,7 @@ module Puppet::ResourceApi
37
14
  end
38
15
 
39
16
  def title
40
- values[@namevars.first]
17
+ values[:title] || values[@namevars.first]
41
18
  end
42
19
 
43
20
  def prune_parameters(*_args)
@@ -49,12 +26,12 @@ module Puppet::ResourceApi
49
26
  (["#{@typename} { #{Puppet::Parameter.format_value_for_display(title)}: "] + filtered_keys.map do |k|
50
27
  cs = ' '
51
28
  ce = ''
52
- if attr_def[k][:behaviour] && attr_def[k][:behaviour] == :read_only
29
+ if attr_def[k] && attr_def[k][:behaviour] && attr_def[k][:behaviour] == :read_only
53
30
  cs = '#'
54
31
  ce = ' # Read Only'
55
32
  end
56
- "#{cs} #{k} => #{Puppet::Parameter.format_value_for_display(values[k])},#{ce}"
57
- end + ['}']).join("\n")
33
+ "#{cs} #{k} => #{Puppet::Parameter.format_value_for_display(values[k])},#{ce}" unless values[k].nil?
34
+ end + ['}']).compact.join("\n")
58
35
  end
59
36
 
60
37
  # Convert our resource to yaml for Hiera purposes.
@@ -65,7 +42,7 @@ module Puppet::ResourceApi
65
42
 
66
43
  # attribute names that are not title or namevars
67
44
  def filtered_keys
68
- values.keys.reject { |k| k == :title || attr_def[k][:behaviour] == :namevar && @namevars.size == 1 }
45
+ values.keys.reject { |k| k == :title || !attr_def[k] || (attr_def[k][:behaviour] == :namevar && @namevars.size == 1) }
69
46
  end
70
47
  end
71
48
  end
@@ -2,9 +2,24 @@ require 'puppet/resource_api/base_context'
2
2
  require 'puppet/util/logging'
3
3
 
4
4
  class Puppet::ResourceApi::PuppetContext < Puppet::ResourceApi::BaseContext
5
+ def log_exception(exception, message: 'Error encountered', trace: false)
6
+ self.class.logging_proxy.log_exception(exception, message, trace: trace)
7
+ end
8
+
5
9
  protected
6
10
 
7
11
  def send_log(level, message)
8
12
  Puppet::Util::Log.create(level: level, message: message)
9
13
  end
14
+
15
+ # Avoid including Puppet::Util::Logging into the main class to avoid the namespace clashes
16
+ class LoggingProxy
17
+ include Puppet::Util::Logging
18
+ end
19
+
20
+ class << self
21
+ def logging_proxy
22
+ @logging_proxy ||= LoggingProxy.new
23
+ end
24
+ end
10
25
  end
@@ -13,6 +13,7 @@ module Puppet::ResourceApi
13
13
  else
14
14
  change.key?(:is) ? change[:is] : (get(context) || []).find { |r| r[:name] == name }
15
15
  end
16
+ context.type.check_schema(is) unless change.key?(:is)
16
17
 
17
18
  should = change[:should]
18
19
 
@@ -7,6 +7,10 @@ class Puppet::ResourceApi::TypeDefinition
7
7
  @definition = definition
8
8
  end
9
9
 
10
+ def name
11
+ @definition[:name]
12
+ end
13
+
10
14
  def attributes
11
15
  @definition[:attributes]
12
16
  end
@@ -31,4 +35,59 @@ class Puppet::ResourceApi::TypeDefinition
31
35
  end
32
36
  supported
33
37
  end
38
+
39
+ # validates a resource hash against its type schema
40
+ def check_schema(resource)
41
+ namevars.each do |namevar|
42
+ if resource[namevar].nil?
43
+ raise Puppet::ResourceError, "`#{name}.get` did not return a value for the `#{namevar}` namevar attribute"
44
+ end
45
+ end
46
+
47
+ message = "Provider returned data that does not match the Type Schema for `#{name}[#{resource[namevars.first]}]`"
48
+
49
+ rejected_keys = check_schema_keys(resource) # removes bad keys
50
+ bad_values = check_schema_values(resource)
51
+
52
+ unless rejected_keys.empty?
53
+ message += "\n Unknown attribute:\n"
54
+ rejected_keys.each { |key, _value| message += " * #{key}\n" }
55
+ end
56
+ unless bad_values.empty?
57
+ message += "\n Value type mismatch:\n"
58
+ bad_values.each { |key, value| message += " * #{key}: #{value}\n" }
59
+ end
60
+
61
+ return if rejected_keys.empty? && bad_values.empty?
62
+
63
+ if Puppet.settings[:strict] == :off
64
+ Puppet.debug(message)
65
+ elsif Puppet.settings[:strict] == :warning
66
+ Puppet::ResourceApi.warning_count += 1
67
+ Puppet.warning(message) if Puppet::ResourceApi.warning_count <= 100 # maximum number of schema warnings to display in a run
68
+ elsif Puppet.settings[:strict] == :error
69
+ raise Puppet::DevError, message
70
+ end
71
+ end
72
+
73
+ # Returns an array of keys that where not found in the type schema
74
+ # Modifies the resource passed in, leaving only valid attributes
75
+ def check_schema_keys(resource)
76
+ rejected = []
77
+ resource.reject! { |key| rejected << key unless attributes.key? key }
78
+ rejected
79
+ end
80
+
81
+ # Returns a hash of keys and values that are not valid
82
+ # does not modify the resource passed in
83
+ def check_schema_values(resource)
84
+ bad_vals = {}
85
+ resource.each do |key, value|
86
+ next unless attributes[key]
87
+ type = Puppet::ResourceApi.parse_puppet_type(key, attributes[key][:type])
88
+ error_message = Puppet::ResourceApi.try_validate(type, value, '')
89
+ bad_vals[key] = value unless error_message.nil?
90
+ end
91
+ bad_vals
92
+ end
34
93
  end
@@ -1,5 +1,5 @@
1
1
  module Puppet
2
2
  module ResourceApi
3
- VERSION = '1.3.0'.freeze
3
+ VERSION = '1.4.0'.freeze
4
4
  end
5
5
  end
@@ -6,6 +6,12 @@ require 'puppet/resource_api/version'
6
6
  require 'puppet/type'
7
7
 
8
8
  module Puppet::ResourceApi
9
+ @warning_count = 0
10
+
11
+ class << self
12
+ attr_accessor :warning_count
13
+ end
14
+
9
15
  def register_type(definition)
10
16
  raise Puppet::DevError, 'requires a hash as definition, not `%{other_type}`' % { other_type: definition.class } unless definition.is_a? Hash
11
17
  raise Puppet::DevError, 'requires a `:name`' unless definition.key? :name
@@ -94,6 +100,20 @@ module Puppet::ResourceApi
94
100
  super(attributes)
95
101
  end
96
102
 
103
+ def name
104
+ title
105
+ end
106
+
107
+ def to_resource
108
+ to_resource_shim(super)
109
+ end
110
+
111
+ define_method(:to_resource_shim) do |resource|
112
+ resource_hash = Hash[resource.keys.map { |k| [k, resource[k]] }]
113
+ resource_hash[:title] = resource.title
114
+ ResourceShim.new(resource_hash, type_definition.name, type_definition.namevars, type_definition.attributes)
115
+ end
116
+
97
117
  validate do
98
118
  # enforce mandatory attributes
99
119
  @missing_attrs = []
@@ -103,7 +123,7 @@ module Puppet::ResourceApi
103
123
  return if @ral_find_absent
104
124
 
105
125
  definition[:attributes].each do |name, options|
106
- type = Puppet::Pops::Types::TypeParser.singleton.parse(options[:type])
126
+ type = Puppet::ResourceApi.parse_puppet_type(:name, options[:type])
107
127
 
108
128
  # skip read only vars and the namevar
109
129
  next if [:read_only, :namevar].include? options[:behaviour]
@@ -136,7 +156,7 @@ module Puppet::ResourceApi
136
156
  # TODO: using newparam everywhere would suppress change reporting
137
157
  # that would allow more fine-grained reporting through context,
138
158
  # but require more invest in hooking up the infrastructure to emulate existing data
139
- param_or_property = if [:read_only, :parameter].include? options[:behaviour]
159
+ param_or_property = if [:read_only, :parameter, :namevar].include? options[:behaviour]
140
160
  :newparam
141
161
  else
142
162
  :newproperty
@@ -170,7 +190,8 @@ module Puppet::ResourceApi
170
190
  end
171
191
  end
172
192
 
173
- type = Puppet::Pops::Types::TypeParser.singleton.parse(options[:type])
193
+ type = Puppet::ResourceApi.parse_puppet_type(name, options[:type])
194
+
174
195
  if param_or_property == :newproperty
175
196
  define_method(:should) do
176
197
  if type.is_a? Puppet::Pops::Types::PBooleanType
@@ -185,6 +206,11 @@ module Puppet::ResourceApi
185
206
 
186
207
  define_method(:should=) do |value|
187
208
  @shouldorig = value
209
+
210
+ if name == :ensure
211
+ value = value.to_s
212
+ end
213
+
188
214
  # Puppet requires the @should value to always be stored as an array. We do not use this
189
215
  # for anything else
190
216
  # @see Puppet::Property.should=(value)
@@ -260,50 +286,49 @@ module Puppet::ResourceApi
260
286
  define_singleton_method(:instances) do
261
287
  # puts 'instances'
262
288
  # force autoloading of the provider
263
- provider(name)
264
- attr_def = {}
289
+ provider(type_definition.name)
290
+
265
291
  my_provider.get(context).map do |resource_hash|
266
- resource_hash.each do |key|
267
- property = definition[:attributes][key.first]
268
- attr_def[key.first] = property
269
- end
270
- context.type.namevars.each do |namevar|
271
- if resource_hash[namevar].nil?
272
- raise Puppet::ResourceError, "`#{name}.get` did not return a value for the `#{namevar}` namevar attribute"
273
- end
274
- end
275
- Puppet::ResourceApi::TypeShim.new(resource_hash, name, context.type.namevars, attr_def)
292
+ type_definition.check_schema(resource_hash)
293
+ result = new(title: resource_hash[type_definition.namevars.first])
294
+ result.cache_current_state(resource_hash)
295
+ result
276
296
  end
277
297
  end
278
298
 
279
- define_method(:retrieve) do
280
- # puts "retrieve(#{title.inspect})"
281
- result = Puppet::Resource.new(self.class, title)
282
-
283
- current_state = if type_definition.feature?('simple_get_filter')
284
- my_provider.get(context, [title]).first
285
- else
286
- my_provider.get(context).find { |h| namevar_match?(h) }
287
- end
288
-
289
- strict_check(current_state) if current_state && type_definition.feature?('canonicalize')
299
+ define_method(:refresh_current_state) do
300
+ @rapi_current_state = if type_definition.feature?('simple_get_filter')
301
+ my_provider.get(context, [title]).first
302
+ else
303
+ my_provider.get(context).find { |h| namevar_match?(h) }
304
+ end
290
305
 
291
- if current_state
292
- current_state.each do |k, v|
293
- result[k] = v
294
- end
306
+ if @rapi_current_state
307
+ type_definition.check_schema(@rapi_current_state)
308
+ strict_check(@rapi_current_state) if type_definition.feature?('canonicalize')
295
309
  else
296
- result[:title] = title
297
- result[:ensure] = :absent if type_definition.ensurable?
310
+ @rapi_current_state = { title: title }
311
+ @rapi_current_state[:ensure] = :absent if type_definition.ensurable?
298
312
  end
313
+ end
314
+
315
+ # Use this to set the current state from the `instances` method
316
+ def cache_current_state(resource_hash)
317
+ @rapi_current_state = resource_hash
318
+ strict_check(@rapi_current_state) if type_definition.feature?('canonicalize')
319
+ end
299
320
 
321
+ define_method(:retrieve) do
322
+ refresh_current_state unless @rapi_current_state
323
+
324
+ Puppet.debug("Current State: #{@rapi_current_state.inspect}")
325
+
326
+ result = Puppet::Resource.new(self.class, title, parameters: @rapi_current_state)
300
327
  # puppet needs ensure to be a symbol
301
328
  result[:ensure] = result[:ensure].to_sym if type_definition.ensurable? && result[:ensure].is_a?(String)
302
329
 
303
330
  raise_missing_attrs
304
331
 
305
- @rapi_current_state = current_state
306
- Puppet.debug("Current State: #{@rapi_current_state.inspect}")
307
332
  result
308
333
  end
309
334
 
@@ -347,6 +372,9 @@ module Puppet::ResourceApi
347
372
  my_provider.set(context, title => { is: @rapi_current_state, should: target_state }) unless noop?
348
373
  end
349
374
  raise 'Execution encountered an error' if context.failed?
375
+
376
+ # remember that we have successfully reached our desired state
377
+ @rapi_current_state = target_state
350
378
  end
351
379
 
352
380
  define_method(:raise_missing_attrs) do
@@ -441,7 +469,7 @@ MESSAGE
441
469
  end
442
470
  end
443
471
  end
444
- module_function :register_type
472
+ module_function :register_type # rubocop:disable Style/AccessModifierDeclarations
445
473
 
446
474
  def load_provider(type_name)
447
475
  class_name = class_name_from_type_name(type_name)
@@ -453,7 +481,7 @@ MESSAGE
453
481
  rescue NameError
454
482
  raise Puppet::DevError, "class #{class_name} not found in puppet/provider/#{type_name}/#{type_name}"
455
483
  end
456
- module_function :load_provider
484
+ module_function :load_provider # rubocop:disable Style/AccessModifierDeclarations
457
485
 
458
486
  def self.class_name_from_type_name(type_name)
459
487
  type_name.to_s.split('_').map(&:capitalize).join
@@ -598,9 +626,17 @@ MESSAGE
598
626
  def self.validate_ensure(definition)
599
627
  return unless definition[:attributes].key? :ensure
600
628
  options = definition[:attributes][:ensure]
601
- type = Puppet::Pops::Types::TypeParser.singleton.parse(options[:type])
629
+ type = Puppet::ResourceApi.parse_puppet_type(:ensure, options[:type])
602
630
 
603
631
  return if type.is_a?(Puppet::Pops::Types::PEnumType) && type.values.sort == %w[absent present].sort
604
632
  raise Puppet::DevError, '`:ensure` attribute must have a type of: `Enum[present, absent]`'
605
633
  end
634
+
635
+ def self.parse_puppet_type(attr_name, type)
636
+ Puppet::Pops::Types::TypeParser.singleton.parse(type)
637
+ rescue Puppet::ParseErrorWithIssue => e
638
+ raise Puppet::DevError, "The type of the `#{attr_name}` attribute `#{type}` could not be parsed: #{e.message}"
639
+ rescue Puppet::ParseError => e
640
+ raise Puppet::DevError, "The type of the `#{attr_name}` attribute `#{type}` is not recognised: #{e.message}"
641
+ end
606
642
  end
@@ -6,9 +6,13 @@ module Puppet::Util::NetworkDevice::Simple
6
6
  # A basic device class, that reads its configuration from the provided URL.
7
7
  # The URL has to be a local file URL.
8
8
  class Device
9
- def initialize(url, _options = {})
10
- @url = URI.parse(url)
11
- raise "Unexpected url '#{url}' found. Only file:/// URLs for configuration supported at the moment." unless @url.scheme == 'file'
9
+ def initialize(url_or_config, _options = {})
10
+ if url_or_config.is_a? String
11
+ @url = URI.parse(url_or_config)
12
+ raise "Unexpected url '#{url_or_config}' found. Only file:/// URLs for configuration supported at the moment." unless @url.scheme == 'file'
13
+ else
14
+ @config = url_or_config
15
+ end
12
16
  end
13
17
 
14
18
  def facts
@@ -16,7 +20,7 @@ module Puppet::Util::NetworkDevice::Simple
16
20
  end
17
21
 
18
22
  def config
19
- raise "Trying to load config from '#{@url.path}, but file does not exist." unless File.exist? @url.path
23
+ raise "Trying to load config from '#{@url.path}, but file does not exist." if @url && !File.exist?(@url.path)
20
24
  @config ||= Hocon.load(@url.path, syntax: Hocon::ConfigSyntax::HOCON)
21
25
  end
22
26
  end
@@ -1,4 +1,4 @@
1
- Send out announcements for major new feature releases, and high-impact bugfixes to puppet-dev@googlegroups.com, puppet-users@googlegroups.com, voxpupuli@groups.io, and the puppet internal mailing lists.
1
+ Send out announcements for major new feature releases, and high-impact bugfixes to <puppet-announce@googlegroups.com>, <puppet-dev@googlegroups.com>, <puppet-users@googlegroups.com>, <voxpupuli@groups.io>, and the puppet internal mailing lists <dev@puppet.com> and <tech-discuss@puppet.com>.
2
2
 
3
3
  Before sending, do check that all links are still valid. Feel free to adjust the text to match better with the circumstances of the release, or add other news that are relevant at the time. If you make changes, consider committing them here, for the benefit of future-you.
4
4
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: puppet-resource_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Schmitt
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-05-24 00:00:00.000000000 Z
11
+ date: 2018-06-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: hocon
@@ -81,7 +81,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
81
81
  version: '0'
82
82
  requirements: []
83
83
  rubyforge_project:
84
- rubygems_version: 2.7.3
84
+ rubygems_version: 2.7.6
85
85
  signing_key:
86
86
  specification_version: 4
87
87
  summary: This library provides a simple way to write new native resources for puppet.