try again, with puppetforge modules, correctly included now
[mirror/dsa-puppet.git] / 3rdparty / modules / nova / lib / puppet / provider / nova.rb
1 # Run test ie with: rspec spec/unit/provider/nova_spec.rb
2
3 require 'puppet/util/inifile'
4
5 class Puppet::Provider::Nova < Puppet::Provider
6
7   def self.conf_filename
8     '/etc/nova/nova.conf'
9   end
10
11   def self.withenv(hash, &block)
12     saved = ENV.to_hash
13     hash.each do |name, val|
14       ENV[name.to_s] = val
15     end
16
17     yield
18   ensure
19     ENV.clear
20     saved.each do |name, val|
21       ENV[name] = val
22     end
23   end
24
25   def self.nova_conf
26     return @nova_conf if @nova_conf
27     @nova_conf = Puppet::Util::IniConfig::File.new
28     @nova_conf.read(conf_filename)
29     @nova_conf
30   end
31
32   def self.nova_credentials
33     @nova_credentials ||= get_nova_credentials
34   end
35
36   def nova_credentials
37     self.class.nova_credentials
38   end
39
40   def self.get_nova_credentials
41     #needed keys for authentication
42     auth_keys = ['auth_host', 'auth_port', 'auth_protocol',
43                  'admin_tenant_name', 'admin_user', 'admin_password']
44     conf = nova_conf
45     if conf and conf['keystone_authtoken'] and
46         auth_keys.all?{|k| !conf['keystone_authtoken'][k].nil?}
47       return Hash[ auth_keys.map \
48                    { |k| [k, conf['keystone_authtoken'][k].strip] } ]
49     else
50       raise(Puppet::Error, "File: #{conf_filename} does not contain all " +
51             "required sections.  Nova types will not work if nova is not " +
52             "correctly configured.")
53     end
54   end
55
56   def self.get_auth_endpoint
57     q = nova_credentials
58     "#{q['auth_protocol']}://#{q['auth_host']}:#{q['auth_port']}/v2.0/"
59   end
60
61   def self.auth_endpoint
62     @auth_endpoint ||= get_auth_endpoint
63   end
64
65   def self.auth_nova(*args)
66     q = nova_credentials
67     authenv = {
68       :OS_AUTH_URL    => self.auth_endpoint,
69       :OS_USERNAME    => q['admin_user'],
70       :OS_TENANT_NAME => q['admin_tenant_name'],
71       :OS_PASSWORD    => q['admin_password']
72     }
73     begin
74       withenv authenv do
75         nova(args)
76       end
77     rescue Exception => e
78       if (e.message =~ /\[Errno 111\] Connection refused/) or
79           (e.message =~ /\(HTTP 400\)/)
80         sleep 10
81         withenv authenv do
82           nova(args)
83         end
84       else
85        raise(e)
86       end
87     end
88   end
89
90   def auth_nova(*args)
91     self.class.auth_nova(args)
92   end
93
94   def self.reset
95     @nova_conf = nil
96     @nova_credentials = nil
97   end
98
99   def self.str2hash(s)
100     #parse string
101     if s.include? "="
102       k, v = s.split("=", 2)
103       return {k.gsub(/'/, "") => v.gsub(/'/, "")}
104     else
105       return s.gsub(/'/, "")
106     end
107   end
108
109   def self.str2list(s)
110     #parse string
111     if s.include? ","
112       if s.include? "="
113         new = {}
114       else
115         new = []
116       end
117       s.split(",").each do |el|
118         ret = str2hash(el.strip())
119         if s.include? "="
120           new.update(ret)
121         else
122           new.push(ret)
123         end
124       end
125       return new
126     else
127       return str2hash(s.strip())
128     end
129   end
130
131   def self.cliout2list(output)
132     #don't proceed with empty output
133     if output.empty?
134       return []
135     end
136     lines = []
137     output.each_line do |line|
138       #ignore lines starting with '+'
139       if not line.match("^\\+")
140         #split line at '|' and remove useless information
141         line = line.gsub(/^\| /, "").gsub(/ \|$/, "").gsub(/[\n]+/, "")
142         line = line.split("|").map do |el|
143           el.strip().gsub(/^-$/, "")
144         end
145         #check every element for list
146         line = line.map do |el|
147           el = str2list(el)
148         end
149         lines.push(line)
150       end
151     end
152     #create a list of hashes and return the list
153     hash_list = []
154     header = lines[0]
155     lines[1..-1].each do |line|
156       hash_list.push(Hash[header.zip(line)])
157     end
158     return hash_list
159   end
160
161   def self.nova_aggregate_resources_ids
162     #produce a list of hashes with Id=>Name pairs
163     lines = []
164     #run command
165     cmd_output = auth_nova("aggregate-list")
166     #parse output
167     hash_list = cliout2list(cmd_output)
168     #only interessted in Id and Name
169     hash_list.map{ |e| e.delete("Availability Zone")}
170     hash_list.map{ |e| e['Id'] = e['Id'].to_i}
171   return hash_list
172   end
173
174   def self.nova_aggregate_resources_get_name_by_id(name)
175     #find the id by the given name
176     nova_aggregate_resources_ids.each do |entry|
177       if entry["Name"] == name
178         return entry["Id"]
179       end
180     end
181     #name not found
182     return nil
183   end
184
185   def self.nova_aggregate_resources_attr(id)
186     #run command to get details for given Id
187     cmd_output = auth_nova("aggregate-details", id)
188     list = cliout2list(cmd_output)[0]
189     if ! list["Hosts"].is_a?(Array)
190       if list["Hosts"] == ""
191         list["Hosts"] = []
192       else
193         list["Hosts"] = [ list["Hosts"] ]
194       end
195     end
196     return list
197   end
198
199 end