Skip to content

MODULES-11309 : convert a string to a resource #1233

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

Merged
merged 2 commits into from
May 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ If you are authoring a module that depends on stdlib, be sure to [specify depend

Most of stdlib's features are automatically loaded by Puppet. To use standardized run stages in Puppet, declare this class in your manifest with `include stdlib`.

When declared, stdlib declares all other classes in the module. The only other class currently included in the module is `stdlib::stages`.
When declared, stdlib declares all other classes in the module. This currently consists of `stdlib::manage` and `stdlib::stages`.

The `stdlib::stages` class declares various run stages for deploying infrastructure, language runtimes, and application layers. The high level stages are (in order):

Expand All @@ -62,6 +62,8 @@ node default {
}
```

The `stdlib::manage` class provides an interface for generating trivial resource declarations via the `create_resources` parameter.

## Reference

For information on the classes and types, see the [REFERENCE.md](https://github.com/puppetlabs/puppetlabs-stdlib/blob/main/REFERENCE.md).
Expand Down
37 changes: 37 additions & 0 deletions lib/puppet/functions/stdlib/str2resource.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# frozen_string_literal: true

# @summary
# This converts a string to a puppet resource.
#
# This attempts to convert a string like 'File[/foo]' into the
# puppet resource `File['/foo']` as detected by the catalog.
#
# Things like 'File[/foo, /bar]' are not supported as a
# title might contain things like ',' or ' '. There is
# no clear value seperator to use.
#
# This function can depend on the parse order of your
# manifests/modules as it inspects the catalog thus far.
Puppet::Functions.create_function(:'stdlib::str2resource') do
# @param res_string The string to lookup as a resource
# @example
# stdlib::str2resource('File[/foo]') => File[/foo]
# @return Puppet::Resource
dispatch :str2resource do
param 'String', :res_string
# return_type 'Puppet::Resource'
return_type 'Any'
end

def str2resource(res_string)
type_name, title = Puppet::Resource.type_and_title(res_string, nil)

resource = closure_scope.findresource(type_name, title)

if resource.nil?
raise(Puppet::ParseError, "stdlib::str2resource(): could not find #{type_name}[#{title}], this is parse order dependent and values should not be quoted")
end

resource
end
end
3 changes: 2 additions & 1 deletion manifests/init.pp
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
# declared in order to use the standardized run stages.
#
# Declares all other classes in the stdlib module. Currently, this consists
# of stdlib::stages.
# of stdlib::stages and stdlib::manage.
#
class stdlib {
include stdlib::manage
include stdlib::stages
}
77 changes: 77 additions & 0 deletions manifests/manage.pp
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# @summary A simple place to define trivial resources
#
# Sometimes your systems require a single simple resource.
# It can feel unnecessary to create a module for a single
# resource. There are a number of possible patterns to
# generate trivial resource definitions. This is an attempt
# to create a single clear method for uncomplicated resources.
# There is limited support for `before`, `require`, `notify`,
# and `subscribe`. However, the target resources must be defined
# before this module is run.
#
# @param create_resources
# A hash of resources to create
# NOTE: functions, such as `template` or `epp` are not evaluated.
#
# @example
# class { 'stdlib::manage':
# 'create_resources' => {
# 'file' => {
# '/etc/motd.d/hello' => {
# 'content' => 'I say Hi',
# 'notify' => 'Service[sshd]',
# }
# },
# 'package' => {
# 'example' => {
# 'ensure' => 'installed',
# }
# }
# }
#
# @example
# stdlib::manage::create_resources:
# file:
# '/etc/motd.d/hello':
# content: I say Hi
# notify: 'Service[sshd]'
# package:
# example:
# ensure: installed
class stdlib::manage (
Hash[String, Hash] $create_resources = {}
) {
$create_resources.each |$type, $resources| {
$resources.each |$title, $attributes| {
$filtered_attributes = $attributes.filter |$key, $value| {
$key !~ /(before|require|notify|subscribe)/
}

if $attributes['before'] {
$_before = stdlib::str2resource($attributes['before'])
} else {
$_before = undef
}

if $attributes['require'] {
$_require = stdlib::str2resource($attributes['require'])
} else {
$_require = undef
}

if $attributes['notify'] {
$_notify = stdlib::str2resource($attributes['notify'])
} else {
$_notify = undef
}

if $attributes['subscribe'] {
$_subscribe = stdlib::str2resource($attributes['subscribe'])
} else {
$_subscribe = undef
}

create_resources($type, { $title => $filtered_attributes }, { 'before' => $_before, 'require' => $_require, 'notify' => $_notify, 'subscribe' => $_subscribe })
}
}
}
43 changes: 43 additions & 0 deletions spec/classes/manage_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# frozen_string_literal: true

require 'spec_helper'

describe 'stdlib::manage' do
on_supported_os.each do |os, os_facts|
context "on #{os}" do
let(:facts) { os_facts }

it { is_expected.to compile }
end
end

describe 'with resources to create' do
let :pre_condition do
<<-PRECOND
file { '/etc/motd.d' : }
service { 'sshd' : }
PRECOND
end
let :params do
{
'create_resources' => {
'file' => {
'/etc/motd.d/hello' => {
'content' => 'I say Hi',
'notify' => 'Service[sshd]',
}
},
'package' => {
'example' => {
'ensure' => 'installed',
}
}
}
}
end

it { is_expected.to compile }
it { is_expected.to contain_file('/etc/motd.d/hello').with_content('I say Hi').with_notify('Service[sshd]') }
it { is_expected.to contain_package('example').with_ensure('installed') }
end
end
44 changes: 44 additions & 0 deletions spec/functions/str2resource_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# frozen_string_literal: true

require 'spec_helper'

describe 'stdlib::str2resource' do
context 'when default' do
it { is_expected.not_to eq(nil) }
it { is_expected.to run.with_params.and_raise_error(ArgumentError, %r{stdlib::str2resource}) }
end

context 'when testing simple resource definitions exist' do
let :pre_condition do
<<-PRECOND
file { 'foo': }
file { '/foo': }
file { 'foot': }
user { 'foo': }
PRECOND
end

file_foo = Puppet::Resource.new(:file, 'foo')
user_foo = Puppet::Resource.new(:user, 'foo')

it { is_expected.to run.with_params('File[foo]').and_return(file_foo) }
it { is_expected.not_to run.with_params('File[\'foo\']') }
it { is_expected.not_to run.with_params('File["foo"]') }

it { is_expected.to run.with_params('User[foo]').and_return(user_foo) }
end

context 'when someone tries a compound definition' do
let :pre_condition do
'user { "foo, bar": }'
end

user_foo_bar = Puppet::Resource.new(:user, 'foo, bar')

it { is_expected.to run.with_params('User[foo, bar]').and_return(user_foo_bar) }
end

context 'when testing simple resource definitions no exist' do
it { is_expected.not_to run.with_params('File[foo]') }
end
end