PageRenderTime 54ms CodeModel.GetById 26ms RepoModel.GetById 1ms app.codeStats 0ms

/core/model/xenserver.rb

https://github.com/drasamsetti/Hanlon
Ruby | 318 lines | 296 code | 8 blank | 14 comment | 6 complexity | 871c65e855ba4eb4ff5d50f32f27122d MD5 | raw file
Possible License(s): Apache-2.0
  1. require "erb"
  2. # Root ProjectHanlon namespace
  3. module ProjectHanlon
  4. module ModelTemplate
  5. # Root Model object
  6. # @abstract
  7. class XenServer < ProjectHanlon::ModelTemplate::Base
  8. include(ProjectHanlon::Logging)
  9. # Assigned image
  10. attr_accessor :image_uuid
  11. # Metadata
  12. attr_accessor :hostname
  13. # Compatible Image Prefix
  14. attr_accessor :image_prefix
  15. def initialize(hash)
  16. super(hash)
  17. # Static config
  18. @hidden = true
  19. @template = :xenserver_hypervisor
  20. @name = "xenserver_generic"
  21. @description = "xenserver generic"
  22. # Metadata vars
  23. @hostname_prefix = nil
  24. @gateway = nil
  25. @nameserver = nil
  26. # State / must have a starting state
  27. @current_state = :init
  28. # Image UUID
  29. @image_uuid = true
  30. # Image prefix we can attach
  31. @image_prefix = "xenserver"
  32. # Enable agent brokers for this model
  33. @broker_plugin = :proxy
  34. @final_state = :os_complete
  35. # Metadata vars
  36. @ip_range_network = nil
  37. @ip_range_start = nil
  38. @ip_range_end = nil
  39. @gateway = nil
  40. @hostname_prefix = nil
  41. @nameserver = nil
  42. @ntpserver = nil
  43. # Metadata
  44. @req_metadata_hash = {
  45. "@root_password" => { :default => "test1234",
  46. :example => "P@ssword!",
  47. :validation => '^[\S]{8,}',
  48. :required => true,
  49. :description => "root password (> 8 characters)" },
  50. "@ip_range_network" => { :default => "",
  51. :example => "192.168.10",
  52. :validation => '^\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b$',
  53. :required => true,
  54. :description => "IP Network for hosts" },
  55. "@ip_range_subnet" => { :default => "255.255.255.0",
  56. :example => "255.255.255.0",
  57. :validation => '^\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b$',
  58. :required => true,
  59. :description => "IP Subnet" },
  60. "@ip_range_start" => { :default => "",
  61. :example => "1",
  62. :validation => '^\b(25[0-4]|2[0-4][0-9]|[01]?[0-9][0-9]?)$',
  63. :required => true,
  64. :description => "Starting IP address (1-254)" },
  65. "@ip_range_end" => { :default => "",
  66. :example => "50",
  67. :validation => '^\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$',
  68. :required => true,
  69. :description => "Ending IP address (2-255)" },
  70. "@gateway" => { :default => "",
  71. :example => "192.168.1.1",
  72. :validation => '^\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b$',
  73. :required => true,
  74. :description => "Gateway for node" },
  75. "@hostname_prefix" => { :default => "",
  76. :example => "xs-node",
  77. :validation => '^[A-Za-z\d-]{3,}$',
  78. :required => true,
  79. :description => "Prefix for naming node" },
  80. "@nameserver" => { :default => "",
  81. :example => "192.168.10.10",
  82. :validation => '^\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b$',
  83. :required => true,
  84. :description => "Nameserver for node" },
  85. "@ntpserver" => { :default => "",
  86. :example => "ntp.hanlon.example.local",
  87. :validation => '^[\w.]{3,}$',
  88. :required => true,
  89. :description => "NTP server for node" }
  90. }
  91. end
  92. def node_ip_address
  93. "#{@ip_range_network}.#{(@ip_range_start..@ip_range_end).to_a[@counter - 1]}"
  94. end
  95. def hostname
  96. "#{@hostname_prefix}#{@counter.to_s}"
  97. end
  98. def broker_agent_handoff
  99. logger.debug "Broker agent called for: #{@broker.name}"
  100. if @node_ip
  101. options = {
  102. :username => "root",
  103. :password => @root_password,
  104. :metadata => node_metadata,
  105. :uuid => @node.uuid,
  106. :ipaddress => @node_ip_address,
  107. }
  108. @current_state = @broker.agent_hand_off(options)
  109. else
  110. logger.error "Node IP address isn't known"
  111. @current_state = :broker_fail
  112. end
  113. broker_fsm_log
  114. end
  115. def callback
  116. {
  117. "broker" => :broker_agent_handoff,
  118. "isolinux_cfg" => :isolinux_cfg_call,
  119. "xenserverinstall_xml" => :xenserverinstall_xml_call,
  120. "postinstall" => :postinstall,
  121. }
  122. end
  123. def fsm_tree
  124. {
  125. :init => { :mk_call => :init,
  126. :boot_call => :init,
  127. :xenserverinstall_xml_start => :preinstall,
  128. :xenserverinstall_xml_file => :init,
  129. :xenserverinstall_xml_end => :postinstall,
  130. :timeout => :timeout_error,
  131. :error => :error_catch,
  132. :else => :init },
  133. :preinstall => { :mk_call => :preinstall,
  134. :boot_call => :preinstall,
  135. :xenserverinstall_xml_start => :preinstall,
  136. :xenserverinstall_xml_file => :init,
  137. :xenserverinstall_xml_end => :postinstall,
  138. :xenserverinstall_xml_timeout => :timeout_error,
  139. :error => :error_catch,
  140. :else => :preinstall },
  141. :postinstall => { :mk_call => :postinstall,
  142. :boot_call => :postinstall,
  143. :postinstall_end => :os_complete,
  144. :xenserverinstall_xml_file => :postinstall,
  145. :xenserverinstall_xml_end => :postinstall,
  146. :postinstallscript_inject => :postinstall,
  147. :postinstall_inject => :postinstall,
  148. :xenserverinstall_xml_timeout => :postinstall,
  149. :error => :error_catch,
  150. :else => :preinstall },
  151. :os_complete => { :mk_call => :os_complete,
  152. :boot_call => :os_complete,
  153. :else => :os_complete,
  154. :reset => :init },
  155. :timeout_error => { :mk_call => :timeout_error,
  156. :boot_call => :timeout_error,
  157. :else => :timeout_error,
  158. :reset => :init },
  159. :error_catch => { :mk_call => :error_catch,
  160. :boot_call => :error_catch,
  161. :else => :error_catch,
  162. :reset => :init },
  163. }
  164. end
  165. def xenserverinstall_xml_call
  166. @arg = @args_array.shift
  167. case @arg
  168. when "start"
  169. @result = "Acknowledged xenserverinstall_xml read"
  170. fsm_action(:xenserverinstall_xml_start, :xenserverinstall_xml)
  171. return "ok"
  172. when "end"
  173. @result = "Acknowledged xenserverinstall_xml end"
  174. fsm_action(:xenserverinstall_xml_end, :xenserverinstall_xml)
  175. return "ok"
  176. when "file"
  177. @result = "Replied with xenserverinstall_xml file"
  178. fsm_action(:xenserverinstall_xml_file, :xenserverinstall_xml)
  179. return generate_xenserverinstall_xml(@policy_uuid)
  180. else
  181. return "error"
  182. end
  183. end
  184. def isolinux_cfg_call
  185. generate_isolinux_cfg(@policy_uuid)
  186. end
  187. def mk_call(node, policy_uuid)
  188. super(node, policy_uuid)
  189. case @current_state
  190. # We need to reboot
  191. when :init, :preinstall, :postinstall, :os_complete
  192. ret = [:reboot, { }]
  193. when :timeout_error, :error_catch
  194. ret = [:acknowledge, { }]
  195. else
  196. ret = [:acknowledge, { }]
  197. end
  198. fsm_action(:mk_call, :mk_call)
  199. ret
  200. end
  201. def boot_call(node, policy_uuid)
  202. super(node, policy_uuid)
  203. case @current_state
  204. when :init, :preinstall
  205. ret = start_install(node, policy_uuid)
  206. when :postinstall, :os_complete, :broker_check, :broker_fail, :broker_success, :complete_no_broker
  207. ret = local_boot(node)
  208. when :timeout_error, :error_catch
  209. engine = ProjectHanlon::Engine.instance
  210. ret = engine.default_mk_boot(node.uuid)
  211. else
  212. engine = ProjectHanlon::Engine.instance
  213. ret = engine.default_mk_boot(node.uuid)
  214. end
  215. fsm_action(:boot_call, :boot_call)
  216. ret
  217. end
  218. def start_install(node, policy_uuid)
  219. filepath = template_filepath('boot_install')
  220. ERB.new(File.read(filepath)).result(binding)
  221. end
  222. def local_boot(node)
  223. filepath = template_filepath('boot_local')
  224. ERB.new(File.read(filepath)).result(binding)
  225. end
  226. def postinstall
  227. @arg = @args_array.shift
  228. case @arg
  229. when "download"
  230. fsm_action(:postinstallscript_inject, :postinstall)
  231. return postinstall_script(@policy_uuid)
  232. when "inject"
  233. fsm_action(:postinstall_inject, :postinstall)
  234. return os_boot_script(@policy_uuid)
  235. when "end"
  236. fsm_action(:postinstall_end, :postinstall)
  237. return "ok"
  238. when "debug"
  239. ret = "V"
  240. return ret
  241. else
  242. return "error"
  243. end
  244. end
  245. def os_boot_script(policy_uuid)
  246. @result = "Replied with os boot script"
  247. filepath = template_filepath('os_boot')
  248. ERB.new(File.read(filepath)).result(binding)
  249. end
  250. def postinstall_script(policy_uuid)
  251. @result = "Replied with postinstall script"
  252. filepath = template_filepath('postinstall')
  253. ERB.new(File.read(filepath)).result(binding)
  254. end
  255. def pxelinuxbin
  256. "pxelinux.0"
  257. end
  258. def pxelinux_path
  259. "boot/pxelinux/pxelinux.0"
  260. end
  261. def pxelinuxconfigfile_path
  262. "#{api_svc_uri}/policy/callback/#{@policy_uuid}/isolinux_cfg"
  263. end
  264. def generate_xenserverinstall_xml(policy_uuid)
  265. # TODO: Review hostname
  266. hostname = "#{@hostname_prefix}#{@counter.to_s}"
  267. filepath = template_filepath('xenserverinstall_xml')
  268. ERB.new(File.read(filepath)).result(binding)
  269. end
  270. def generate_isolinux_cfg(policy_uuid)
  271. # TODO: Review hostname
  272. hostname = "#{@hostname_prefix}#{@counter.to_s}"
  273. filepath = template_filepath('isolinux_cfg')
  274. ERB.new(File.read(filepath)).result(binding)
  275. end
  276. def image_svc_uri
  277. "http://#{config.hanlon_server}:#{config.api_port}#{config.websvc_root}/image/xenserver"
  278. end
  279. def api_svc_uri
  280. "http://#{config.hanlon_server}:#{config.api_port}#{config.websvc_root}"
  281. end
  282. # ERB.result(binding) is failing in Ruby 1.9.2 and 1.9.3 so template is processed in the def block.
  283. def template_filepath(filename)
  284. raise ProjectHanlon::Error::Slice::InternalError, "must provide xenserver version." unless @osversion
  285. filepath = File.join(File.dirname(__FILE__), "xenserver/#{@osversion}/#{filename}.erb")
  286. end
  287. end
  288. end
  289. end