try again, with puppetforge modules, correctly included now
[mirror/dsa-puppet.git] / 3rdparty / modules / glance / lib / puppet / provider / glance.rb
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
6
7   def self.glance_credentials
8     @glance_credentials ||= get_glance_credentials
9   end
10
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']
20
21         g = {}
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
29
30         # auth_admin_prefix not required to be set.
31         g['auth_admin_prefix'] = (glance_file['keystone_authtoken']['auth_admin_prefix'] || '').strip
32
33         return g
34     else
35       raise(Puppet::Error, 'File: /etc/glance/glance-api.conf does not contain all required sections.')
36     end
37   end
38
39   def glance_credentials
40     self.class.glance_credentials
41   end
42
43   def self.auth_endpoint
44     @auth_endpoint ||= get_auth_endpoint
45   end
46
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/"
50   end
51
52   def self.glance_file
53     return @glance_file if @glance_file
54     @glance_file = Puppet::Util::IniConfig::File.new
55     @glance_file.read('/etc/glance/glance-api.conf')
56     @glance_file
57   end
58
59   def self.glance_hash
60     @glance_hash ||= build_glance_hash
61   end
62
63   def self.reset
64     @glance_hash        = nil
65     @glance_file        = nil
66     @glance_credentials = nil
67     @auth_endpoint      = nil
68   end
69
70   def glance_hash
71     self.class.glance_hash
72   end
73
74   def self.auth_glance(*args)
75     begin
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))
78     rescue Exception => e
79       if (e.message =~ /\[Errno 111\] Connection refused/) or (e.message =~ /\(HTTP 400\)/) or (e.message =~ /HTTP Unable to establish connection/)
80         sleep 10
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))
82       else
83         raise(e)
84       end
85     end
86   end
87
88   def auth_glance(*args)
89     self.class.auth_glance(args)
90   end
91
92   def self.auth_glance_stdin(*args)
93     begin
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(' ')}"
96
97       # This is a horrible, horrible hack
98       # Redirect stderr to stdout in order to report errors
99       # Ignore good output
100       err = `#{command} 3>&1 1>/dev/null 2>&3`
101       if $? != 0
102         raise(Puppet::Error, err)
103       end
104     end
105   end
106
107   def auth_glance_stdin(*args)
108     self.class.auth_glance_stdin(args)
109   end
110
111   private
112     def self.list_glance_images
113       ids = []
114       (auth_glance('image-list').split("\n")[3..-2] || []).collect do |line|
115         ids << line.split('|')[1].strip()
116       end
117       return ids
118     end
119
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]
124         end
125       end
126     end
127
128     def self.get_glance_image_attrs(id)
129       attrs = {}
130       (auth_glance('image-show', id).split("\n")[3..-2] || []).collect do |line|
131         attrs[line.split('|')[1].strip()] = line.split('|')[2].strip()
132       end
133       return attrs
134     end
135
136     def parse_table(table)
137       # parse the table into an array of maps with a simplistic state machine
138       found_header = false
139       parsed_header = false
140       keys = nil
141       results = []
142       table.split("\n").collect do |line|
143         # look for the header
144         if not found_header
145           if line =~ /^\+[-|+]+\+$/
146             found_header = true
147             nil
148           end
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)
153             parsed_header = true
154           end
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]
159           results << result
160         end
161       end
162       results
163     end
164
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)
168       found_header = false
169       in_warning = false
170       results.split("\n").collect do |line|
171         unless found_header
172           if line =~ /^\+[-\+]+\+$/ # Matches upper and lower box borders
173             in_warning = false
174             found_header = true
175             line
176           elsif line =~ /^WARNING/ or line =~ /UserWarning/ or in_warning
177             # warnings can be multi line, we have to skip all of them
178             in_warning = true
179             nil
180           else
181             line
182           end
183         else
184           line
185         end
186       end.compact.join("\n")
187     end
188 end