Skip to content
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
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1697,6 +1697,8 @@ Loads a JSON file containing an array, string, or hash, and returns the data in

For example:

The first parameter can be an absolute file path, or a URL.

```puppet
$myhash = loadjson('/etc/puppet/data/myhash.json')
```
Expand Down
26 changes: 19 additions & 7 deletions lib/puppet/parser/functions/loadjson.rb
Original file line number Diff line number Diff line change
@@ -1,31 +1,43 @@
#
# loadjson.rb
#

module Puppet::Parser::Functions
newfunction(:loadjson, :type => :rvalue, :arity => -2, :doc => <<-'DOC') do |args|
Load a JSON file containing an array, string, or hash, and return the data
in the corresponding native data type.
The first parameter can be a file path or a URL.
The second parameter is the default value. It will be returned if the file
was not found or could not be parsed.

For example:

$myhash = loadjson('/etc/puppet/data/myhash.json')
$myhash = loadjson('https://example.local/my_hash.json')
$myhash = loadjson('no-file.json', {'default' => 'value'})
DOC

raise ArgumentError, 'Wrong number of arguments. 1 or 2 arguments should be provided.' unless args.length >= 1

if File.exists?(args[0]) # rubocop:disable Lint/DeprecatedClassMethods : Changing to .exist? breaks the code
begin
require 'open-uri'
begin
if args[0].start_with?('http://', 'https://')
begin
contents = OpenURI.open_uri(args[0])
rescue OpenURI::HTTPError => err
res = err.io
warning("Can't load '#{args[0]}' HTTP Error Code: '#{res.status[0]}'")
args[1]
end
PSON.load(contents) || args[1]
elsif File.exists?(args[0]) # rubocop:disable Lint/DeprecatedClassMethods : Changing to .exist? breaks the code
content = File.read(args[0])
PSON.load(content) || args[1]
rescue StandardError => e
raise e unless args[1]
else
warning("Can't load '#{args[0]}' File does not exist!")
args[1]
end
else
warning("Can't load '#{args[0]}' File does not exist!")
rescue StandardError => e
raise e unless args[1]
args[1]
end
end
Expand Down
25 changes: 18 additions & 7 deletions lib/puppet/parser/functions/loadyaml.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,38 @@ module Puppet::Parser::Functions
newfunction(:loadyaml, :type => :rvalue, :arity => -2, :doc => <<-'DOC') do |args|
Load a YAML file containing an array, string, or hash, and return the data
in the corresponding native data type.
The first parameter can be a file path or a URL.
The second parameter is the default value. It will be returned if the file
was not found or could not be parsed.

For example:

$myhash = loadyaml('/etc/puppet/data/myhash.yaml')
$myhash = loadyaml('https://example.local/my_hash.yaml')
$myhash = loadyaml('no-file.yaml', {'default' => 'value'})
DOC

raise ArgumentError, 'Wrong number of arguments. 1 or 2 arguments should be provided.' unless args.length >= 1
require 'yaml'

if File.exists?(args[0]) # rubocop:disable Lint/DeprecatedClassMethods : Changing to .exist? breaks the code
begin
require 'open-uri'
begin
if args[0].start_with?('http://', 'https://')
begin
contents = OpenURI.open_uri(args[0])
rescue OpenURI::HTTPError => err
res = err.io
warning("Can't load '#{args[0]}' HTTP Error Code: '#{res.status[0]}'")
args[1]
end
YAML.safe_load(contents) || args[1]
elsif File.exists?(args[0]) # rubocop:disable Lint/DeprecatedClassMethods : Changing to .exist? breaks the code
YAML.load_file(args[0]) || args[1]
rescue StandardError => e
raise e unless args[1]
else
warning("Can't load '#{args[0]}' File does not exist!")
args[1]
end
else
warning("Can't load '#{args[0]}' File does not exist!")
rescue StandardError => e
raise e unless args[1]
args[1]
end
end
Expand Down
38 changes: 38 additions & 0 deletions spec/functions/loadjson_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -65,5 +65,43 @@
end
it { is_expected.to run.with_params(filename, 'default' => 'value').and_return('default' => 'value') }
end

context 'when an existing URL is specified' do
let(:filename) do
'https://example.local/myhash.json'
end
let(:data) { { 'key' => 'value', 'ķęŷ' => 'νậŀųề', 'キー' => '値' } }
let(:json) { '{"key":"value", {"ķęŷ":"νậŀųề" }, {"キー":"値" }' }

it {
expect(OpenURI).to receive(:open_uri).with(filename).and_return(json)
expect(PSON).to receive(:load).with(json).and_return(data).once
is_expected.to run.with_params(filename).and_return(data)
}
end

context 'when the URL output could not be parsed, with default specified' do
let(:filename) do
'https://example.local/myhash.json'
end
let(:json) { ',;{"key":"value"}' }

it {
expect(OpenURI).to receive(:open_uri).with(filename).and_return(json)
expect(PSON).to receive(:load).with(json).once.and_raise StandardError, 'Something terrible have happened!'
is_expected.to run.with_params(filename, 'default' => 'value').and_return('default' => 'value')
}
end

context 'when the URL does not exist, with default specified' do
let(:filename) do
'https://example.local/myhash.json'
end

it {
expect(OpenURI).to receive(:open_uri).with(filename).and_raise OpenURI::HTTPError, '404 File not Found'
is_expected.to run.with_params(filename, 'default' => 'value').and_return('default' => 'value')
}
end
end
end
33 changes: 33 additions & 0 deletions spec/functions/loadyaml_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,37 @@
end
it { is_expected.to run.with_params(filename, 'default' => 'value').and_return('default' => 'value') }
end

context 'when an existing URL is specified' do
let(:filename) { 'https://example.local/myhash.yaml' }
let(:yaml) { 'Dummy YAML' }
let(:data) { { 'key' => 'value', 'ķęŷ' => 'νậŀųề', 'キー' => '値' } }

it {
expect(OpenURI).to receive(:open_uri).with(filename).and_return(yaml)
expect(YAML).to receive(:safe_load).with(yaml).and_return(data).once
is_expected.to run.with_params(filename).and_return(data)
}
end

context 'when an existing URL could not be parsed, with default specified' do
let(:filename) { 'https://example.local/myhash.yaml' }
let(:yaml) { 'Dummy YAML' }

it {
expect(OpenURI).to receive(:open_uri).with(filename).and_return(yaml)
expect(YAML).to receive(:safe_load).with(yaml).and_raise StandardError, 'Cannot parse data'
is_expected.to run.with_params(filename, 'default' => 'value').and_return('default' => 'value')
}
end

context 'when a URL does not exist, with default specified' do
let(:filename) { 'https://example.local/myhash.yaml' }
let(:yaml) { 'Dummy YAML' }

it {
expect(OpenURI).to receive(:open_uri).with(filename).and_raise OpenURI::HTTPError, '404 File not Found'
is_expected.to run.with_params(filename, 'default' => 'value').and_return('default' => 'value')
}
end
end