Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create a "old vs new" API comparision #228

Open
DavidS opened this issue Sep 24, 2019 · 0 comments
Open

Create a "old vs new" API comparision #228

DavidS opened this issue Sep 24, 2019 · 0 comments

Comments

@DavidS
Copy link
Contributor

DavidS commented Sep 24, 2019

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

  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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant