Skip to content

Commit 5cc12dd

Browse files
Jenkinsopenstack-gerrit
authored andcommitted
Merge "os_transport_url parser function"
2 parents afd0186 + 7ef2f7b commit 5cc12dd

File tree

3 files changed

+362
-0
lines changed

3 files changed

+362
-0
lines changed
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
require 'puppet/parser/functions'
2+
3+
Puppet::Parser::Functions.newfunction(:os_transport_url,
4+
:type => :rvalue,
5+
:arity => 1,
6+
:doc => <<-EOS
7+
This function builds a os_transport_url string from a hash of parameters.
8+
9+
Valid hash parameteres:
10+
* transport - (string) type of transport, 'rabbit' or 'amqp'
11+
* host - (string) single host
12+
* hosts - (array) array of hosts to use
13+
* port - (string) port to connect to
14+
* username - (string) connection username
15+
* password - (string) connection password
16+
* virtual_host - (string) virtual host to connect to
17+
* ssl - (string) is the connection ssl or not ('1' or '0'). overrides the ssl
18+
key in the query parameter
19+
* query - (hash) hash of key,value pairs used to create a query string for
20+
the transport_url.
21+
22+
Only 'transport' and either 'host' or 'hosts' are required keys for the
23+
parameters hash.
24+
25+
The url format that will be generated:
26+
transport://user:pass@host:port[,userN:passN@hostN:portN]/virtual_host?query
27+
28+
NOTE: ipv6 addresses will automatically be bracketed for the URI using the
29+
normalize_ip_for_uri function.
30+
31+
Single Host Example:
32+
os_transport_url({
33+
'transport' => 'rabbit',
34+
'host' => '1.1.1.1',
35+
'port' => '5672',
36+
'username' => 'username',
37+
'password' => 'password',
38+
'virtual_host' => 'virtual_host',
39+
'ssl' => '1',
40+
'query' => { 'key' => 'value' },
41+
})
42+
Generates:
43+
rabbit://username:password@1.1.1.1:5672/virtual_host?key=value&ssl=1
44+
45+
Multiple Hosts Example:
46+
os_transport_url({
47+
'transport' => 'rabbit',
48+
'hosts' => [ '1.1.1.1', '2.2.2.2' ],
49+
'port' => '5672',
50+
'username' => 'username',
51+
'password' => 'password',
52+
'virtual_host' => 'virtual_host',
53+
'query' => { 'key' => 'value' },
54+
})
55+
Generates:
56+
rabbit://username:password@1.1.1.1:5672,username:password@2.2.2.2:5672/virtual_host?key=value
57+
EOS
58+
) do |arguments|
59+
60+
require 'uri'
61+
62+
v = arguments[0]
63+
klass = v.class
64+
65+
unless klass == Hash
66+
raise(Puppet::ParseError, "os_transport_url(): Requires an hash, got #{klass}")
67+
end
68+
69+
# type checking for the parameter hash
70+
v.keys.each do |key|
71+
klass = (key == 'hosts') ? Array : String
72+
klass = (key == 'query') ? Hash : klass
73+
unless (v[key].class == klass) or (v[key] == :undef)
74+
raise(Puppet::ParseError, "os_transport_url(): #{key} should be a #{klass}")
75+
end
76+
end
77+
78+
# defaults
79+
parts = {
80+
:transport => 'rabbit',
81+
:hostinfo => 'localhost',
82+
:path => '/',
83+
}
84+
85+
unless v.include?('transport')
86+
raise(Puppet::ParseError, 'os_transport_url(): transport is required')
87+
end
88+
89+
unless v.include?('host') or v.include?('hosts')
90+
raise(Puppet::ParseError, 'os_transport_url(): host or hosts is required')
91+
end
92+
93+
if v.include?('host') and v.include?('hosts')
94+
raise(Puppet::ParseError, 'os_transport_url(): cannot use both host and hosts.')
95+
end
96+
97+
if v.include?('username') and (v['username'] != :undef) and (v['username'].to_s != '')
98+
parts[:userinfo] = URI.escape(v['username'])
99+
if v.include?('password') and (v['password'] != :undef) and (v['password'].to_s != '')
100+
parts[:userinfo] += ":#{URI.escape(v['password'])}"
101+
end
102+
end
103+
104+
if v.include?('host')
105+
host = function_normalize_ip_for_uri([v['host']])
106+
host += ":#{v['port']}" if v.include?('port')
107+
if parts.include?(:userinfo)
108+
parts[:hostinfo] = "#{parts[:userinfo]}@#{host}"
109+
else
110+
parts[:hostinfo] = "#{host}"
111+
end
112+
end
113+
114+
if v.include?('hosts')
115+
hosts = function_normalize_ip_for_uri([v['hosts']])
116+
hosts = hosts.map{ |h| "#{h}:#{v['port']}" } if v.include?('port')
117+
if parts.include?(:userinfo)
118+
parts[:hostinfo] = hosts.map { |h| "#{parts[:userinfo]}@#{h}" }.join(',')
119+
else
120+
parts[:hostinfo] = hosts.join(',')
121+
end
122+
end
123+
124+
parts[:path] = "/#{v['virtual_host']}" if v.include?('virtual_host')
125+
126+
# support previous ssl option on the function. Setting ssl will
127+
# override ssl if passed in via the query parameters
128+
if v.include?('ssl')
129+
if v.include?('query')
130+
v['query'].merge!({ 'ssl' => v['ssl'] })
131+
else
132+
v['query'] = { 'ssl' => v['ssl'] }
133+
end
134+
end
135+
136+
parts[:query] = v['query'].map{ |k,val| "#{k}=#{val}" }.join('&') if v.include?('query')
137+
138+
139+
url_parts = []
140+
url_parts << parts[:transport]
141+
url_parts << '://'
142+
url_parts << parts[:hostinfo]
143+
url_parts << parts[:path]
144+
url_parts << '?' << parts[:query] if parts.include?(:query)
145+
url_parts.join()
146+
end
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
features:
3+
- os_transport_url puppet parser function can be used to generate valid
4+
transport_url URIs from a hash of connection parameters.
Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
require 'spec_helper'
2+
3+
describe 'os_transport_url' do
4+
5+
it 'refuses String' do
6+
is_expected.to run.with_params('foo').\
7+
and_raise_error(Puppet::ParseError, /Requires an hash/)
8+
end
9+
10+
it 'refuses Array' do
11+
is_expected.to run.with_params(['foo']).\
12+
and_raise_error(Puppet::ParseError, /Requires an hash/)
13+
end
14+
15+
it 'refuses without at least one argument' do
16+
is_expected.to run.with_params().\
17+
and_raise_error(ArgumentError, /Wrong number of arguments/)
18+
end
19+
20+
it 'refuses too many arguments' do
21+
is_expected.to run.with_params('foo', 'bar').\
22+
and_raise_error(ArgumentError, /Wrong number of arguments/)
23+
end
24+
25+
it 'refuses hosts params passed as String' do
26+
is_expected.to run.with_params({
27+
'transport'=> 'rabbit',
28+
'hosts' => '127.0.0.1',
29+
}).and_raise_error(Puppet::ParseError, /hosts should be a Array/)
30+
end
31+
32+
it 'fails if missing host' do
33+
is_expected.to run.with_params({
34+
'transport'=> 'rabbit',
35+
}).and_raise_error(Puppet::ParseError, /host or hosts is required/)
36+
end
37+
38+
context 'creates the correct transport URI' do
39+
40+
it 'with all params for a single host' do
41+
is_expected.to run.with_params({
42+
'transport' => 'rabbit',
43+
'host' => '127.0.0.1',
44+
'port' => '5672',
45+
'username' => 'guest',
46+
'password' => 's3cr3t',
47+
'virtual_host' => 'virt',
48+
'ssl' => '1',
49+
'query' => { 'read_timeout' => '60' },
50+
}).and_return('rabbit://guest:s3cr3t@127.0.0.1:5672/virt?read_timeout=60&ssl=1')
51+
end
52+
53+
it 'with only required params for a single host' do
54+
is_expected.to run.with_params({
55+
'transport' => 'rabbit',
56+
'host' => '127.0.0.1',
57+
}).and_return('rabbit://127.0.0.1/')
58+
end
59+
60+
it 'with a single ipv6 address' do
61+
is_expected.to run.with_params({
62+
'transport' => 'rabbit',
63+
'host' => 'fe80::ca5b:76ff:fe4b:be3b',
64+
'port' => '5672'
65+
}).and_return('rabbit://[fe80::ca5b:76ff:fe4b:be3b]:5672/')
66+
end
67+
68+
it 'with all params with multiple hosts' do
69+
is_expected.to run.with_params({
70+
'transport' => 'rabbit',
71+
'hosts' => ['1.1.1.1', '2.2.2.2'],
72+
'port' => '5672',
73+
'username' => 'guest',
74+
'password' => 's3cr3t',
75+
'virtual_host' => 'virt',
76+
'query' => { 'read_timeout' => '60' },
77+
}).and_return('rabbit://guest:s3cr3t@1.1.1.1:5672,guest:s3cr3t@2.2.2.2:5672/virt?read_timeout=60')
78+
end
79+
80+
it 'with only required params for multiple hosts' do
81+
is_expected.to run.with_params({
82+
'transport' => 'rabbit',
83+
'hosts' => [ '1.1.1.1', '2.2.2.2' ],
84+
'port' => '5672',
85+
'username' => 'guest',
86+
'password' => 's3cr3t',
87+
}).and_return('rabbit://guest:s3cr3t@1.1.1.1:5672,guest:s3cr3t@2.2.2.2:5672/')
88+
end
89+
90+
it 'with multiple ipv6 hosts' do
91+
is_expected.to run.with_params({
92+
'transport' => 'rabbit',
93+
'hosts' => [ 'fe80::ca5b:76ff:fe4b:be3b', 'fe80::ca5b:76ff:fe4b:be3c' ],
94+
'port' => '5672',
95+
'username' => 'guest',
96+
'password' => 's3cr3t',
97+
}).and_return('rabbit://guest:s3cr3t@[fe80::ca5b:76ff:fe4b:be3b]:5672,guest:s3cr3t@[fe80::ca5b:76ff:fe4b:be3c]:5672/')
98+
end
99+
100+
it 'with a mix of ipv4 and ipv6 hosts' do
101+
is_expected.to run.with_params({
102+
'transport' => 'rabbit',
103+
'hosts' => [ 'fe80::ca5b:76ff:fe4b:be3b', '1.1.1.1' ],
104+
'port' => '5672',
105+
'username' => 'guest',
106+
'password' => 's3cr3t',
107+
}).and_return('rabbit://guest:s3cr3t@[fe80::ca5b:76ff:fe4b:be3b]:5672,guest:s3cr3t@1.1.1.1:5672/')
108+
end
109+
110+
it 'without port' do
111+
is_expected.to run.with_params({
112+
'transport' => 'rabbit',
113+
'host' => '127.0.0.1',
114+
'username' => 'guest',
115+
'password' => 's3cr3t',
116+
'virtual_host' => 'virt',
117+
'query' => { 'read_timeout' => '60' },
118+
}).and_return('rabbit://guest:s3cr3t@127.0.0.1/virt?read_timeout=60')
119+
end
120+
121+
it 'without port and query' do
122+
is_expected.to run.with_params({
123+
'transport' => 'rabbit',
124+
'host' => '127.0.0.1',
125+
'username' => 'guest',
126+
'password' => 's3cr3t',
127+
'virtual_host' => 'virt',
128+
}).and_return('rabbit://guest:s3cr3t@127.0.0.1/virt')
129+
end
130+
131+
it 'without username and password' do
132+
is_expected.to run.with_params({
133+
'transport' => 'rabbit',
134+
'host' => '127.0.0.1',
135+
'port' => '5672',
136+
'virtual_host' => 'virt',
137+
'query' => { 'read_timeout' => '60' },
138+
}).and_return('rabbit://127.0.0.1:5672/virt?read_timeout=60')
139+
end
140+
141+
it 'with username set to undef' do
142+
is_expected.to run.with_params({
143+
'transport' => 'rabbit',
144+
'host' => '127.0.0.1',
145+
'port' => '5672',
146+
'username' => :undef,
147+
'virtual_host' => 'virt',
148+
'query' => { 'read_timeout' => '60' },
149+
}).and_return('rabbit://127.0.0.1:5672/virt?read_timeout=60')
150+
end
151+
152+
it 'with username set to an empty string' do
153+
is_expected.to run.with_params({
154+
'transport' => 'rabbit',
155+
'host' => '127.0.0.1',
156+
'port' => '5672',
157+
'username' => '',
158+
'virtual_host' => 'virt',
159+
'query' => { 'read_timeout' => '60' },
160+
}).and_return('rabbit://127.0.0.1:5672/virt?read_timeout=60')
161+
end
162+
163+
it 'without password' do
164+
is_expected.to run.with_params({
165+
'transport' => 'rabbit',
166+
'host' => '127.0.0.1',
167+
'port' => '5672',
168+
'username' => 'guest',
169+
'virtual_host' => 'virt',
170+
'query' => { 'read_timeout' => '60' },
171+
}).and_return('rabbit://guest@127.0.0.1:5672/virt?read_timeout=60')
172+
end
173+
174+
it 'with password set to undef' do
175+
is_expected.to run.with_params({
176+
'transport' => 'rabbit',
177+
'host' => '127.0.0.1',
178+
'port' => '5672',
179+
'username' => 'guest',
180+
'password' => :undef,
181+
'virtual_host' => 'virt',
182+
'query' => { 'read_timeout' => '60' },
183+
}).and_return('rabbit://guest@127.0.0.1:5672/virt?read_timeout=60')
184+
end
185+
186+
it 'with password set to an empty string' do
187+
is_expected.to run.with_params({
188+
'transport' => 'rabbit',
189+
'host' => '127.0.0.1',
190+
'port' => '5672',
191+
'username' => 'guest',
192+
'password' => '',
193+
'virtual_host' => 'virt',
194+
'query' => { 'read_timeout' => '60' },
195+
}).and_return('rabbit://guest@127.0.0.1:5672/virt?read_timeout=60')
196+
end
197+
198+
it 'with ssl overrides ssl in querty hash' do
199+
is_expected.to run.with_params({
200+
'transport' => 'rabbit',
201+
'host' => '127.0.0.1',
202+
'port' => '5672',
203+
'username' => 'guest',
204+
'password' => '',
205+
'virtual_host' => 'virt',
206+
'ssl' => '1',
207+
'query' => { 'read_timeout' => '60' , 'ssl' => '0'},
208+
}).and_return('rabbit://guest@127.0.0.1:5672/virt?read_timeout=60&ssl=1')
209+
end
210+
211+
end
212+
end

0 commit comments

Comments
 (0)