1 # Since there's only one glance type for now,
2 # this probably could have all gone in the provider file.
3 # But maybe this is good long-term.
4 require 'puppet/util/inifile'
5 class Puppet::Provider::Glance < Puppet::Provider
7 def self.glance_credentials
8 @glance_credentials ||= get_glance_credentials
11 def self.get_glance_credentials
12 if glance_file and glance_file['keystone_authtoken'] and
13 glance_file['keystone_authtoken']['auth_host'] and
14 glance_file['keystone_authtoken']['auth_port'] and
15 glance_file['keystone_authtoken']['auth_protocol'] and
16 glance_file['keystone_authtoken']['admin_tenant_name'] and
17 glance_file['keystone_authtoken']['admin_user'] and
18 glance_file['keystone_authtoken']['admin_password'] and
19 glance_file['DEFAULT']['os_region_name']
22 g['auth_host'] = glance_file['keystone_authtoken']['auth_host'].strip
23 g['auth_port'] = glance_file['keystone_authtoken']['auth_port'].strip
24 g['auth_protocol'] = glance_file['keystone_authtoken']['auth_protocol'].strip
25 g['admin_tenant_name'] = glance_file['keystone_authtoken']['admin_tenant_name'].strip
26 g['admin_user'] = glance_file['keystone_authtoken']['admin_user'].strip
27 g['admin_password'] = glance_file['keystone_authtoken']['admin_password'].strip
28 g['os_region_name'] = glance_file['DEFAULT']['os_region_name'].strip
30 # auth_admin_prefix not required to be set.
31 g['auth_admin_prefix'] = (glance_file['keystone_authtoken']['auth_admin_prefix'] || '').strip
35 raise(Puppet::Error, 'File: /etc/glance/glance-api.conf does not contain all required sections.')
39 def glance_credentials
40 self.class.glance_credentials
43 def self.auth_endpoint
44 @auth_endpoint ||= get_auth_endpoint
47 def self.get_auth_endpoint
48 g = glance_credentials
49 "#{g['auth_protocol']}://#{g['auth_host']}:#{g['auth_port']}#{g['auth_admin_prefix']}/v2.0/"
53 return @glance_file if @glance_file
54 @glance_file = Puppet::Util::IniConfig::File.new
55 @glance_file.read('/etc/glance/glance-api.conf')
60 @glance_hash ||= build_glance_hash
66 @glance_credentials = nil
71 self.class.glance_hash
74 def self.auth_glance(*args)
76 g = glance_credentials
77 remove_warnings(glance('--os-tenant-name', g['admin_tenant_name'], '--os-username', g['admin_user'], '--os-password', g['admin_password'], '--os-region-name', g['os_region_name'], '--os-auth-url', auth_endpoint, args))
79 if (e.message =~ /\[Errno 111\] Connection refused/) or (e.message =~ /\(HTTP 400\)/) or (e.message =~ /HTTP Unable to establish connection/)
81 remove_warnings(glance('--os-tenant-name', g['admin_tenant_name'], '--os-username', g['admin_user'], '--os-password', g['admin_password'], '--os-region-name', g['os_region_name'], '--os-auth-url', auth_endpoint, args))
88 def auth_glance(*args)
89 self.class.auth_glance(args)
92 def self.auth_glance_stdin(*args)
94 g = glance_credentials
95 command = "glance --os-tenant-name #{g['admin_tenant_name']} --os-username #{g['admin_user']} --os-password #{g['admin_password']} --os-region-name #{g['os_region_name']} --os-auth-url #{auth_endpoint} #{args.join(' ')}"
97 # This is a horrible, horrible hack
98 # Redirect stderr to stdout in order to report errors
100 err = `#{command} 3>&1 1>/dev/null 2>&3`
102 raise(Puppet::Error, err)
107 def auth_glance_stdin(*args)
108 self.class.auth_glance_stdin(args)
112 def self.list_glance_images
114 (auth_glance('image-list').split("\n")[3..-2] || []).collect do |line|
115 ids << line.split('|')[1].strip()
120 def self.get_glance_image_attr(id, attr)
121 (auth_glance('image-show', id).split("\n") || []).collect do |line|
122 if line =~ /^#{attr}:/
123 return line.split(': ')[1..-1]
128 def self.get_glance_image_attrs(id)
130 (auth_glance('image-show', id).split("\n")[3..-2] || []).collect do |line|
131 attrs[line.split('|')[1].strip()] = line.split('|')[2].strip()
136 def parse_table(table)
137 # parse the table into an array of maps with a simplistic state machine
139 parsed_header = false
142 table.split("\n").collect do |line|
143 # look for the header
145 if line =~ /^\+[-|+]+\+$/
149 # look for the key names in the table header
150 elsif not parsed_header
151 if line =~ /^(\|\s*[:alpha:]\s*)|$/
152 keys = line.split('|').map(&:strip)
155 # parse the values in the rest of the table
156 elsif line =~ /^|.*|$/
157 values = line.split('|').map(&:strip)
158 result = Hash[keys.zip values]
165 # Remove warning from the output. This is a temporary hack until
166 # things will be refactored to use the REST API
167 def self.remove_warnings(results)
170 results.split("\n").collect do |line|
172 if line =~ /^\+[-\+]+\+$/ # Matches upper and lower box borders
176 elsif line =~ /^WARNING/ or line =~ /UserWarning/ or in_warning
177 # warnings can be multi line, we have to skip all of them
186 end.compact.join("\n")