You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
For example: validate, insync, munge, Boolean properties, array matching, for a start - document how they underlying need is (better) served by Resource API
A more detailed starting point from an internal document:
Intro
The type defines how puppet sees a resource and which attributes accept which values.
The provider implements the interaction between puppet and the actual resources.
Due to historical reasons, puppet types are defined using a ruby DSL, expose puppet's inner workings as API, were never adapted to allow use of modern puppet features, and have bits of code sprinkled throughout which are only supposed to run on the agent.
The API between the type definition and its providers has never been formalised, and is up to each individual type to figure out. Accordingly, coding for each type needs to understand its particular quirks. Especially vexing is the general pattern of passing the desired state to the provider in a different call than enforcing that state, which makes reasoning about the behavior.
The provider is sprinkled across many little blocks, making tracing what happens hard.
The Resource API, on the other hand, has a pure-data schema definition, and a straightforward get/set or get/create/update/delete API.
Type Definition
Legacy
Resource API
Interface Definition
code ("DSL")
data
Input validation
code-only
puppet 4 data types; code possible
Boolean attributes
see The Boolean Slide below
type: 'Boolean'
Array attributes
"By default, if a property is assigned multiple values in an array, it is considered in sync if any of those values matches the current value." [docs]
type: 'Array[String]'
Array attributes, really
"[...] should only be in sync if all values match the current value [use] :array_matching => :all." [ibid.] (but passes through single-element arrays as just that element)
type: 'Array[String]'
Optional Attributes
don't use isrequired
type: 'Optional[...]'
List acceptable values
use newvalue or newvalues, with slightly different capabilities
type: 'Variant[Boolean, Enum[present, absent]]'
keep value from being logged
good luck
type: 'Sensitive[...]'
environment isolation today
run puppet generate types
run puppet generate types
environment isolation tomorrow
run puppet generate types
Load data directly into environment
read-only attributes
PUP-5624: Properties (in resource types) should allow a read-only designation
behaviour: :read_only
init only attributes
lol wat?
behaviour: :init_only
designate namevar
use isnamevar
behaviour: :namevar
distinguish parameters and properties
use newparam vs newproperty
behaviour: :parameter (defaults to property)
title_patterns
a 5-deep nested data structure with a lambda in it
a list of descriptive hashes
credentials for remote access
URL
define a schema for arbitrary credentials, using the same structure as type attributes
Implementation
Legacy
Resource API
API
types can implement all functionality without a provider. provider api can either use @property_hash, mkresourcemethods, CRUD pattern, or custom coded interaction
return list of resources as data, receive desired state as data
Memory usage
one Type and one Provider instance per resource; one Parameter instance per attribute per resource; additional memory for @property_hash
Two Hashes per resource
List existing resources
Implement the instances and prefetch methods
return the list of resources as a Hash from get
Batch processing
"What is wrong with taking two hours for a 5 minute operation?"
built-in (but not used by puppet because "it's hard to implement, and we gave up six years ago trying")
Setting values on a specific resource
Create a new type instance, set values, flush
create an instance of the provider, call set with desired state
Logging
Use the Puppet::Util::Logging module, which is included in a variety of places hogging your namespace. e.g. Puppet.info() or just info() in a provider, but not three levels down in your type definition
call the logging methods on context
implement simple CRUD
Implement create, flush, destroy methods, data gets injected through @property_hash, which you may or may not have to implement yourself. Just read one of the books.
Inherit from SimpleProvider, implement create, update, delete according to the example. Get the existing and desired state passed in as argument.
Debugging
Good luck finding where data gets passed in or stored. Depends on per-type type/provider API choices.
Each method on the provider gets data passed in or is expected to return data. Each readily available for inspection. If any data is stored, the developer has put it there themselves, and is accessible through standard debugging techniques
transform user input
use the munge function in the type definition; attribute specific; needs to be jruby 1.7 compatible because it's parsed (but not executed) on the server; only works on individual array elements
Implement canonicalize, transform the complete resource
API evolution
Still supporting puppet 2.7 semantics, because any change breaks something somewhere
each type can specify feature flags to unlock optional parts of the API, or opt-out of legacy behaviour.
unit testing
There is no way to properly separate a "unit". Testing requires a full puppet and a VM. Individual tests can take minutes.
100% test coverage without touching the system. All tests run in seconds.
remote access
use the global Device instance setup by the framework
use the Transport instance passed through to your provider
The Boolean Slide
… or how to define a Boolean attribute in core puppet
Set :boolean => true in the parameter definition
or, set :parent => Puppet::Parameter::Boolean in the parameter definition
or, use the voxpupuli/puppet-boolean module
Remember to use :true and :false (strings), instead of true and false (bools)
Depending on implementation also allows yes/no, 0/1, and/or t/f
PUP-8462: Including :boolean => true in a type parameter definition should automatically populate the values a user is allowed to specify for that parameter
PUP-8442: type parameters do not honor when default is set to false
PUP-2368: using booleans result in unmanaged property
#17519: Puppet type and provider handling of boolean values
#17206: parameter defaults of false and {} does not work
The text was updated successfully, but these errors were encountered:
Describe the Change You Would Like
For example: validate, insync, munge, Boolean properties, array matching, for a start - document how they underlying need is (better) served by Resource API
Originally raised in https://twitter.com/leothrix/status/920940960435011589
A more detailed starting point from an internal document:
Intro
The type defines how puppet sees a resource and which attributes accept which values.
The provider implements the interaction between puppet and the actual resources.
Due to historical reasons, puppet types are defined using a ruby DSL, expose puppet's inner workings as API, were never adapted to allow use of modern puppet features, and have bits of code sprinkled throughout which are only supposed to run on the agent.
The API between the type definition and its providers has never been formalised, and is up to each individual type to figure out. Accordingly, coding for each type needs to understand its particular quirks. Especially vexing is the general pattern of passing the desired state to the provider in a different call than enforcing that state, which makes reasoning about the behavior.
The provider is sprinkled across many little blocks, making tracing what happens hard.
The Resource API, on the other hand, has a pure-data schema definition, and a straightforward get/set or get/create/update/delete API.
Type Definition
type: 'Boolean'
type: 'Array[String]'
type: 'Array[String]'
isrequired
type: 'Optional[...]'
newvalue
ornewvalues
, with slightly different capabilitiestype: 'Variant[Boolean, Enum[present, absent]]'
type: 'Sensitive[...]'
puppet generate types
puppet generate types
puppet generate types
behaviour: :read_only
behaviour: :init_only
isnamevar
behaviour: :namevar
newparam
vsnewproperty
behaviour: :parameter
(defaults to property)Implementation
@property_hash
,mkresourcemethods
, CRUD pattern, or custom coded interactionType
and oneProvider
instance per resource; oneParameter
instance per attribute per resource; additional memory for@property_hash
instances
andprefetch
methodsHash
fromget
set
with desired statePuppet::Util::Logging
module, which is included in a variety of places hogging your namespace. e.g.Puppet.info()
or justinfo()
in a provider, but not three levels down in your type definitioncontext
create
,flush
,destroy
methods, data gets injected through@property_hash
, which you may or may not have to implement yourself. Just read one of the books.SimpleProvider
, implementcreate
,update
,delete
according to the example. Get the existing and desired state passed in as argument.munge
function in the type definition; attribute specific; needs to be jruby 1.7 compatible because it's parsed (but not executed) on the server; only works on individual array elementscanonicalize
, transform the complete resourceDevice
instance setup by the frameworkTransport
instance passed through to your providerThe Boolean Slide
… or how to define a Boolean attribute in core puppet
Set
:boolean => true
in the parameter definitionor, set
:parent => Puppet::Parameter::Boolean
in the parameter definitionor, use the
voxpupuli/puppet-boolean
moduleRemember to use
:true
and:false
(strings), instead oftrue
andfalse
(bools)Depending on implementation also allows
yes
/no
,0
/1
, and/ort
/f
PUP-8462: Including
:boolean => true
in a type parameter definition should automatically populate the values a user is allowed to specify for that parameterPUP-8442: type parameters do not honor when default is set to
false
PUP-2368: using booleans result in unmanaged property
#17519: Puppet type and provider handling of boolean values
#17206: parameter defaults of
false
and{}
does not workThe text was updated successfully, but these errors were encountered: