Skip to content

Commit 03c95ae

Browse files
committed
Add the ability for the loadjson() and loadyaml() functions to accept
an HTTP or HTTPS URI.
1 parent bd2d5c7 commit 03c95ae

4 files changed

Lines changed: 69 additions & 14 deletions

File tree

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1697,6 +1697,8 @@ Loads a JSON file containing an array, string, or hash, and returns the data in
16971697

16981698
For example:
16991699

1700+
The first parameter can be an absolute file path, or a URL.
1701+
17001702
```puppet
17011703
$myhash = loadjson('/etc/puppet/data/myhash.json')
17021704
```

lib/puppet/parser/functions/loadjson.rb

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,43 @@
11
#
22
# loadjson.rb
33
#
4+
45
module Puppet::Parser::Functions
56
newfunction(:loadjson, :type => :rvalue, :arity => -2, :doc => <<-'DOC') do |args|
67
Load a JSON file containing an array, string, or hash, and return the data
78
in the corresponding native data type.
9+
The first parameter can be a file path or a URL.
810
The second parameter is the default value. It will be returned if the file
911
was not found or could not be parsed.
1012
1113
For example:
1214
1315
$myhash = loadjson('/etc/puppet/data/myhash.json')
16+
$myhash = loadjson('https://example.local/my_hash.json')
1417
$myhash = loadjson('no-file.json', {'default' => 'value'})
1518
DOC
1619

1720
raise ArgumentError, 'Wrong number of arguments. 1 or 2 arguments should be provided.' unless args.length >= 1
18-
19-
if File.exists?(args[0]) # rubocop:disable Lint/DeprecatedClassMethods : Changing to .exist? breaks the code
20-
begin
21+
require 'open-uri'
22+
begin
23+
if args[0].start_with?('http://', 'https://')
24+
begin
25+
contents = open(args[0])
26+
rescue OpenURI::HTTPError => err
27+
res = err.io
28+
warning("Can't load '#{args[0]}' HTTP Error Code: '#{res.status[0]}'")
29+
args[1]
30+
end
31+
PSON.load(contents) || args[1]
32+
elsif File.exists?(args[0]) # rubocop:disable Lint/DeprecatedClassMethods : Changing to .exist? breaks the code
2133
content = File.read(args[0])
2234
PSON.load(content) || args[1]
23-
rescue StandardError => e
24-
raise e unless args[1]
35+
else
36+
warning("Can't load '#{args[0]}' File does not exist!")
2537
args[1]
2638
end
27-
else
28-
warning("Can't load '#{args[0]}' File does not exist!")
39+
rescue StandardError => e
40+
raise e unless args[1]
2941
args[1]
3042
end
3143
end

lib/puppet/parser/functions/loadyaml.rb

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,27 +5,38 @@ module Puppet::Parser::Functions
55
newfunction(:loadyaml, :type => :rvalue, :arity => -2, :doc => <<-'DOC') do |args|
66
Load a YAML file containing an array, string, or hash, and return the data
77
in the corresponding native data type.
8+
The first parameter can be a file path or a URL.
89
The second parameter is the default value. It will be returned if the file
910
was not found or could not be parsed.
1011
1112
For example:
1213
1314
$myhash = loadyaml('/etc/puppet/data/myhash.yaml')
15+
$myhash = loadyaml('https://example.local/my_hash.yaml')
1416
$myhash = loadyaml('no-file.yaml', {'default' => 'value'})
1517
DOC
1618

1719
raise ArgumentError, 'Wrong number of arguments. 1 or 2 arguments should be provided.' unless args.length >= 1
1820
require 'yaml'
19-
20-
if File.exists?(args[0]) # rubocop:disable Lint/DeprecatedClassMethods : Changing to .exist? breaks the code
21-
begin
21+
require 'open-uri'
22+
begin
23+
if args[0].start_with?('http://', 'https://')
24+
begin
25+
contents = open(args[0])
26+
rescue OpenURI::HTTPError => err
27+
res = err.io
28+
warning("Can't load '#{args[0]}' HTTP Error Code: '#{res.status[0]}'")
29+
args[1]
30+
end
31+
YAML.safe_load(contents) || args[1]
32+
elsif File.exists?(args[0]) # rubocop:disable Lint/DeprecatedClassMethods : Changing to .exist? breaks the code
2233
YAML.load_file(args[0]) || args[1]
23-
rescue StandardError => e
24-
raise e unless args[1]
34+
else
35+
warning("Can't load '#{args[0]}' File does not exist!")
2536
args[1]
2637
end
27-
else
28-
warning("Can't load '#{args[0]}' File does not exist!")
38+
rescue StandardError => e
39+
raise e unless args[1]
2940
args[1]
3041
end
3142
end

spec/functions/loadjson_spec.rb

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,5 +65,35 @@
6565
end
6666
it { is_expected.to run.with_params(filename, 'default' => 'value').and_return('default' => 'value') }
6767
end
68+
69+
context 'when an existing URL is specified' do
70+
let(:filename) do
71+
'https://example.local/myhash.json'
72+
end
73+
let(:data) { { 'key' => 'value', 'ķęŷ' => 'νậŀųề', 'キー' => '値' } }
74+
let(:json) { '{"key":"value", {"ķęŷ":"νậŀųề" }, {"キー":"値" }' }
75+
76+
before(:each) do
77+
allow(File).to receive(:exists?).with(filename).and_return(true).once
78+
allow(File).to receive(:read).with(filename).and_return(json).once
79+
allow(File).to receive(:read).with(filename).and_return(json).once
80+
allow(PSON).to receive(:load).with(json).and_return(data).once
81+
end
82+
it { is_expected.to run.with_params(filename).and_return(data) }
83+
end
84+
85+
context 'when the URL output could not be parsed' do
86+
let(:filename) do
87+
'https://example.local/myhash.json'
88+
end
89+
let(:json) { '{"key":"value"}' }
90+
91+
before(:each) do
92+
allow(File).to receive(:exists?).with(filename).and_return(true).once
93+
allow(File).to receive(:read).with(filename).and_return(json).once
94+
allow(PSON).to receive(:load).with(json).once.and_raise StandardError, 'Something terrible have happened!'
95+
end
96+
it { is_expected.to run.with_params(filename, 'default' => 'value').and_return('default' => 'value') }
97+
end
6898
end
6999
end

0 commit comments

Comments
 (0)