4 class Puppet::Error::OpenstackAuthInputError < Puppet::Error
7 class Puppet::Error::OpenstackUnauthorizedError < Puppet::Error
10 class Puppet::Provider::Openstack < Puppet::Provider
12 initvars # so commands will work
13 commands :openstack => 'openstack'
15 # Returns an array of hashes, where the keys are the downcased CSV headers
16 # with underscores instead of spaces
17 def self.request(service, action, properties, credentials=nil)
18 env = credentials ? credentials.to_env : {}
19 Puppet::Util.withenv(env) do
22 end_time = Time.now.to_i + timeout
26 response = openstack(service, action, '--quiet', '--format', 'csv', properties)
27 response = parse_csv(response)
28 keys = response.delete_at(0) # ID,Name,Description,Enabled
29 rv = response.collect do |line|
31 keys.each_index do |index|
32 key = keys[index].downcase.gsub(/ /, '_').to_sym
33 hash[key] = line[index]
37 elsif(action == 'show' || action == 'create')
39 # shell output is name="value"\nid="value2"\ndescription="value3" etc.
40 openstack(service, action, '--format', 'shell', properties).split("\n").each do |line|
41 # key is everything before the first "="
42 key, val = line.split("=", 2)
43 next unless val # Ignore warnings
44 # value is everything after the first "=", with leading and trailing double quotes stripped
45 val = val.gsub(/\A"|"\Z/, '')
46 rv[key.downcase.to_sym] = val
49 rv = openstack(service, action, properties)
52 rescue Puppet::ExecutionFailure => e
53 if e.message =~ /HTTP 401/
54 raise(Puppet::Error::OpenstackUnauthorizedError, 'Could not authenticate.')
55 elsif e.message =~ /Unable to establish connection/
56 current_time = Time.now.to_i
57 if current_time > end_time
60 wait = end_time - current_time
61 Puppet::debug("Non-fatal error: \"#{e.message}\"; retrying for #{wait} more seconds.")
62 if wait > timeout - 2 # Only notice the first time
63 notice("#{service} service is unavailable. Will retry for up to #{wait} seconds.")
78 def self.parse_csv(text)
79 # Ignore warnings - assume legitimate output starts with a double quoted
80 # string. Errors will be caught and raised prior to this
81 text = text.split("\n").drop_while { |line| line !~ /^\".*\"/ }.join("\n")
82 return CSV.parse(text + "\n")