nova.rb 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. # Run test ie with: rspec spec/unit/provider/nova_spec.rb
  2. # Add openstacklib code to $LOAD_PATH so that we can load this during
  3. # standalone compiles without error.
  4. File.expand_path('../../../../openstacklib/lib', File.dirname(__FILE__)).tap { |dir| $LOAD_PATH.unshift(dir) unless $LOAD_PATH.include?(dir) }
  5. require 'puppet/util/inifile'
  6. require 'puppet/provider/openstack'
  7. require 'puppet/provider/openstack/auth'
  8. require 'puppet/provider/openstack/credentials'
  9. class Puppet::Provider::Nova < Puppet::Provider::Openstack
  10. extend Puppet::Provider::Openstack::Auth
  11. def self.request(service, action, properties=nil)
  12. begin
  13. super
  14. rescue Puppet::Error::OpenstackAuthInputError => error
  15. nova_request(service, action, error, properties)
  16. end
  17. end
  18. def self.nova_request(service, action, error, properties=nil)
  19. properties ||= []
  20. @credentials.username = nova_credentials['username']
  21. @credentials.password = nova_credentials['password']
  22. @credentials.project_name = nova_credentials['project_name']
  23. @credentials.auth_url = auth_endpoint
  24. if @credentials.version == '3'
  25. @credentials.user_domain_name = nova_credentials['user_domain_name']
  26. @credentials.project_domain_name = nova_credentials['project_domain_name']
  27. end
  28. if nova_credentials['region_name']
  29. @credentials.region_name = nova_credentials['region_name']
  30. end
  31. raise error unless @credentials.set?
  32. Puppet::Provider::Openstack.request(service, action, properties, @credentials)
  33. end
  34. def self.conf_filename
  35. '/etc/nova/nova.conf'
  36. end
  37. # deprecated: method for old nova cli auth
  38. def self.withenv(hash, &block)
  39. saved = ENV.to_hash
  40. hash.each do |name, val|
  41. ENV[name.to_s] = val
  42. end
  43. yield
  44. ensure
  45. ENV.clear
  46. saved.each do |name, val|
  47. ENV[name] = val
  48. end
  49. end
  50. def self.nova_conf
  51. return @nova_conf if @nova_conf
  52. @nova_conf = Puppet::Util::IniConfig::File.new
  53. @nova_conf.read(conf_filename)
  54. @nova_conf
  55. end
  56. def self.nova_credentials
  57. @nova_credentials ||= get_nova_credentials
  58. end
  59. def nova_credentials
  60. self.class.nova_credentials
  61. end
  62. def self.get_nova_credentials
  63. #needed keys for authentication
  64. auth_keys = ['auth_uri', 'project_name', 'username', 'password']
  65. conf = nova_conf
  66. if conf and conf['keystone_authtoken'] and
  67. auth_keys.all?{|k| !conf['keystone_authtoken'][k].nil?}
  68. creds = Hash[ auth_keys.map \
  69. { |k| [k, conf['keystone_authtoken'][k].strip] } ]
  70. if conf['neutron'] and conf['neutron']['region_name']
  71. creds['region_name'] = conf['neutron']['region_name'].strip
  72. end
  73. if !conf['keystone_authtoken']['project_domain_name'].nil?
  74. creds['project_domain_name'] = conf['keystone_authtoken']['project_domain_name'].strip
  75. else
  76. creds['project_domain_name'] = 'Default'
  77. end
  78. if !conf['keystone_authtoken']['user_domain_name'].nil?
  79. creds['user_domain_name'] = conf['keystone_authtoken']['user_domain_name'].strip
  80. else
  81. creds['user_domain_name'] = 'Default'
  82. end
  83. return creds
  84. else
  85. raise(Puppet::Error, "File: #{conf_filename} does not contain all " +
  86. "required sections. Nova types will not work if nova is not " +
  87. "correctly configured.")
  88. end
  89. end
  90. def self.get_auth_endpoint
  91. q = nova_credentials
  92. "#{q['auth_uri']}"
  93. end
  94. def self.auth_endpoint
  95. @auth_endpoint ||= get_auth_endpoint
  96. end
  97. # deprecated: method for old nova cli auth
  98. def self.auth_nova(*args)
  99. q = nova_credentials
  100. authenv = {
  101. :OS_AUTH_URL => self.auth_endpoint,
  102. :OS_USERNAME => q['username'],
  103. :OS_PROJECT_NAME => q['project_name'],
  104. :OS_PASSWORD => q['password']
  105. }
  106. if q.key?('region_name')
  107. authenv[:OS_REGION_NAME] = q['region_name']
  108. end
  109. begin
  110. withenv authenv do
  111. nova(args)
  112. end
  113. rescue Exception => e
  114. if (e.message =~ /\[Errno 111\] Connection refused/) or
  115. (e.message =~ /\(HTTP 400\)/)
  116. sleep 10
  117. withenv authenv do
  118. nova(args)
  119. end
  120. else
  121. raise(e)
  122. end
  123. end
  124. end
  125. # deprecated: method for old nova cli auth
  126. def auth_nova(*args)
  127. self.class.auth_nova(args)
  128. end
  129. def self.reset
  130. @nova_conf = nil
  131. @nova_credentials = nil
  132. end
  133. def self.str2hash(s)
  134. #parse string
  135. if s.include? "="
  136. k, v = s.split("=", 2)
  137. return {k.gsub(/'/, "") => v.gsub(/'/, "")}
  138. else
  139. return s.gsub(/'/, "")
  140. end
  141. end
  142. # deprecated: string to list for nova cli
  143. def self.str2list(s)
  144. #parse string
  145. if s.include? ","
  146. if s.include? "="
  147. new = {}
  148. else
  149. new = []
  150. end
  151. if s =~ /^'.+'$/
  152. s.split("', '").each do |el|
  153. ret = str2hash(el.strip())
  154. if s.include? "="
  155. new.update(ret)
  156. else
  157. new.push(ret)
  158. end
  159. end
  160. else
  161. s.split(",").each do |el|
  162. ret = str2hash(el.strip())
  163. if s.include? "="
  164. new.update(ret)
  165. else
  166. new.push(ret)
  167. end
  168. end
  169. end
  170. return new
  171. else
  172. return str2hash(s.strip())
  173. end
  174. end
  175. # deprecated: nova cli to list
  176. def self.cliout2list(output)
  177. #don't proceed with empty output
  178. if output.empty?
  179. return []
  180. end
  181. lines = []
  182. output.each_line do |line|
  183. #ignore lines starting with '+'
  184. if not line.match("^\\+")
  185. #split line at '|' and remove useless information
  186. line = line.gsub(/^\| /, "").gsub(/ \|$/, "").gsub(/[\n]+/, "")
  187. line = line.split("|").map do |el|
  188. el.strip().gsub(/^-$/, "")
  189. end
  190. #check every element for list
  191. line = line.map do |el|
  192. el = str2list(el)
  193. end
  194. lines.push(line)
  195. end
  196. end
  197. #create a list of hashes and return the list
  198. hash_list = []
  199. header = lines[0]
  200. lines[1..-1].each do |line|
  201. hash_list.push(Hash[header.zip(line)])
  202. end
  203. return hash_list
  204. end
  205. end