puppet-glance/lib/puppet/provider/glance.rb

187 lines
5.7 KiB
Ruby

# Since there's only one glance type for now,
# this probably could have all gone in the provider file.
# But maybe this is good long-term.
require 'puppet/util/inifile'
class Puppet::Provider::Glance < Puppet::Provider
def self.glance_credentials
@glance_credentials ||= get_glance_credentials
end
def self.get_glance_credentials
if glance_file and glance_file['keystone_authtoken'] and
glance_file['keystone_authtoken']['auth_host'] and
glance_file['keystone_authtoken']['auth_port'] and
glance_file['keystone_authtoken']['auth_protocol'] and
glance_file['keystone_authtoken']['admin_tenant_name'] and
glance_file['keystone_authtoken']['admin_user'] and
glance_file['keystone_authtoken']['admin_password']
g = {}
g['auth_host'] = glance_file['keystone_authtoken']['auth_host'].strip
g['auth_port'] = glance_file['keystone_authtoken']['auth_port'].strip
g['auth_protocol'] = glance_file['keystone_authtoken']['auth_protocol'].strip
g['admin_tenant_name'] = glance_file['keystone_authtoken']['admin_tenant_name'].strip
g['admin_user'] = glance_file['keystone_authtoken']['admin_user'].strip
g['admin_password'] = glance_file['keystone_authtoken']['admin_password'].strip
# auth_admin_prefix not required to be set.
g['auth_admin_prefix'] = (glance_file['keystone_authtoken']['auth_admin_prefix'] || '').strip
return g
else
raise(Puppet::Error, 'File: /etc/glance/glance-api.conf does not contain all required sections.')
end
end
def glance_credentials
self.class.glance_credentials
end
def self.auth_endpoint
@auth_endpoint ||= get_auth_endpoint
end
def self.get_auth_endpoint
g = glance_credentials
"#{g['auth_protocol']}://#{g['auth_host']}:#{g['auth_port']}#{g['auth_admin_prefix']}/v2.0/"
end
def self.glance_file
return @glance_file if @glance_file
@glance_file = Puppet::Util::IniConfig::File.new
@glance_file.read('/etc/glance/glance-api.conf')
@glance_file
end
def self.glance_hash
@glance_hash ||= build_glance_hash
end
def self.reset
@glance_hash = nil
@glance_file = nil
@glance_credentials = nil
@auth_endpoint = nil
end
def glance_hash
self.class.glance_hash
end
def self.auth_glance(*args)
begin
g = glance_credentials
remove_warnings(glance('-T', g['admin_tenant_name'], '-I', g['admin_user'], '-K', g['admin_password'], '-N', auth_endpoint, args))
rescue Exception => e
if (e.message =~ /\[Errno 111\] Connection refused/) or (e.message =~ /\(HTTP 400\)/) or (e.message =~ /HTTP Unable to establish connection/)
sleep 10
remove_warnings(glance('-T', g['admin_tenant_name'], '-I', g['admin_user'], '-K', g['admin_password'], '-N', auth_endpoint, args))
else
raise(e)
end
end
end
def auth_glance(*args)
self.class.auth_glance(args)
end
def self.auth_glance_stdin(*args)
begin
g = glance_credentials
command = "glance -T #{g['admin_tenant_name']} -I #{g['admin_user']} -K #{g['admin_password']} -N #{auth_endpoint} #{args.join(' ')}"
# This is a horrible, horrible hack
# Redirect stderr to stdout in order to report errors
# Ignore good output
err = `#{command} 3>&1 1>/dev/null 2>&3`
if $? != 0
raise(Puppet::Error, err)
end
end
end
def auth_glance_stdin(*args)
self.class.auth_glance_stdin(args)
end
private
def self.list_glance_images
ids = []
(auth_glance('index').split("\n")[2..-1] || []).collect do |line|
ids << line.split[0]
end
return ids
end
def self.get_glance_image_attr(id, attr)
(auth_glance('show', id).split("\n") || []).collect do |line|
if line =~ /^#{attr}:/
return line.split(': ')[1..-1]
end
end
end
def self.get_glance_image_attrs(id)
attrs = {}
(auth_glance('show', id).split("\n") || []).collect do |line|
attrs[line.split(': ').first.downcase] = line.split(': ')[1..-1].pop
end
return attrs
end
def parse_table(table)
# parse the table into an array of maps with a simplistic state machine
found_header = false
parsed_header = false
keys = nil
results = []
table.split("\n").collect do |line|
# look for the header
if not found_header
if line =~ /^\+[-|+]+\+$/
found_header = true
nil
end
# look for the key names in the table header
elsif not parsed_header
if line =~ /^(\|\s*[:alpha:]\s*)|$/
keys = line.split('|').map(&:strip)
parsed_header = true
end
# parse the values in the rest of the table
elsif line =~ /^|.*|$/
values = line.split('|').map(&:strip)
result = Hash[keys.zip values]
results << result
end
end
results
end
# Remove warning from the output. This is a temporary hack until
# things will be refactored to use the REST API
def self.remove_warnings(results)
found_header = false
in_warning = false
results.split("\n").collect do |line|
unless found_header
if line =~ /^\+[-\+]+\+$/ # Matches upper and lower box borders
in_warning = false
found_header = true
line
elsif line =~ /^WARNING/ or line =~ /UserWarning/ or in_warning
# warnings can be multi line, we have to skip all of them
in_warning = true
nil
else
line
end
else
line
end
end.compact.join("\n")
end
end