PageRenderTime 50ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/omf/utils.rb

https://bitbucket.org/romoore/gnrs
Ruby | 556 lines | 376 code | 116 blank | 64 comment | 26 complexity | 8df29476c4d6a20c480128bd1f8607d2 MD5 | raw file
  1. #!/bin/ruby
  2. #
  3. # Module containing GNRS experiment-related functionality.
  4. # See <https://bitbucket.org/romoore/gnrs/wiki/Running%20an%20Experiment%20on%20Orbit>
  5. # for more details.
  6. #
  7. # Author: Robert Moore
  8. # Last Modified: Jan 23, 2013
  9. #
  10. # Runtime configuration of propertes can be effected like this:
  11. # omf exec simple.rb -- --prop1 value1 --prop2 value2
  12. # Import the GNRSNode class
  13. require ('./gnrs_node.rb')
  14. require ('./gnrs_group.rb')
  15. require ('./gnrs_config.rb')
  16. require ('./statscollect.rb')
  17. # Resources file location can be configured with:
  18. # --resourceFile /path/to/file.rb
  19. defProperty('resourceFile', './resources.rb', 'Experiment resources configuration')
  20. # Read the resources file and execute its code
  21. eval(File.new(property.resourceFile).read)
  22. # Initial work of configuring topology, groups, and readying for node "up"
  23. def doInitSetup
  24. # Check initial parameters, make sure everything is sane.
  25. success = checkParams
  26. if success != 0
  27. error "*** One or more parameters was invalid. See messages above for more details. ***"
  28. return success
  29. end
  30. serversMap = Hash.new
  31. clientsMap = Hash.new
  32. allNodes = Topology[property.topology.to_s]
  33. # Grab the imaged topology (successful nodes) and break them into groups
  34. success = defineGroups(allNodes, serversMap, clientsMap)
  35. if success == 0
  36. else
  37. return success
  38. end
  39. return success, serversMap, clientsMap
  40. end # doInitSetup
  41. def checkParams
  42. if property.numServers.to_s.to_i < 1
  43. error "Must define at least 1 server."
  44. return -1
  45. elsif property.numClients.to_s.to_i < 1
  46. error "Must define at least 1 client."
  47. return -1
  48. end
  49. `rm -rf #{property.tmpDir}`
  50. `mkdir -p #{property.tmpDir}`
  51. unless $?.success?
  52. puts "Unable to use temporary directory #{property.tmpDir}."
  53. return -1
  54. end
  55. return 0
  56. end # checkParams
  57. def defineGroups(topology, serversMap, clientsMap)
  58. nodelist = topology.nodes
  59. totalNodes = nodelist.size
  60. sNodes = property.sNodes.to_s.to_i
  61. cNodes = property.cNodes.to_s.to_i
  62. numServers = property.numServers.to_s.to_i
  63. numClients = property.numClients.to_s.to_i
  64. serversPerNode = []
  65. clientsPerNode = []
  66. quotient, remainder = numServers.divmod(sNodes)
  67. if(quotient >= 1 || remainder > 0)
  68. for i in 1..sNodes
  69. num = quotient
  70. if(remainder > 0)
  71. num += 1
  72. remainder -= 1
  73. end
  74. serversPerNode << num
  75. end
  76. else
  77. for i in 1..sNodes
  78. serversPerNode << 1
  79. end
  80. end
  81. quotient, remainder = numClients.divmod(cNodes)
  82. if(quotient >= 1 || remainder > 0)
  83. for i in 1..cNodes
  84. num = quotient
  85. if(remainder > 0)
  86. num += 1
  87. remainder -= 1
  88. end
  89. clientsPerNode << num
  90. end
  91. else
  92. for i in 1..cNodes
  93. clientsPerNode << 1
  94. end
  95. end
  96. ###############################
  97. # Let's set the defGroup/nodes
  98. asNumber = 1
  99. ipOffset = 0
  100. asMap = Hash.new
  101. serversPerNode.each { |numServers|
  102. remainingServers = numServers
  103. hostname = nodelist.pop().to_s
  104. group = defGroup(hostname, hostname)
  105. gnrsGroup = GNRSGroup.new
  106. gnrsGroup.hostname = hostname
  107. gnrsGroup.group = group
  108. gnrsGroup.nodelist = []
  109. gnrsGroup.ipAddress = "192.168.1.#{ipOffset + 1}"
  110. serversMap[hostname] = gnrsGroup
  111. for i in 1..remainingServers
  112. node = GNRSNode.new
  113. node.asNumber = asNumber
  114. node.port = "500#{i}"
  115. node.group = gnrsGroup
  116. gnrsGroup.nodelist << node
  117. asMap[node.asNumber] = node
  118. asNumber += 1
  119. end
  120. ipOffset += 1
  121. }
  122. maxAsNumber = asNumber - 1
  123. ipOffset = 0
  124. asNumber = 0
  125. clientsPerNode.each { |numClients|
  126. remainingClients = numClients
  127. hostname = nodelist.pop().to_s
  128. group = defGroup(hostname, hostname)
  129. gnrsGroup = GNRSGroup.new
  130. gnrsGroup.hostname = hostname
  131. gnrsGroup.group = group
  132. gnrsGroup.nodelist = []
  133. gnrsGroup.ipAddress = "192.168.1.#{ipOffset + 101}"
  134. clientsMap[hostname] = gnrsGroup
  135. for i in 1..remainingClients
  136. node = GNRSNode.new
  137. node.asNumber = (asNumber % maxAsNumber) + 1;
  138. node.server = asMap[node.asNumber];
  139. node.port = "400#{i}"
  140. node.group = gnrsGroup
  141. gnrsGroup.nodelist << node
  142. asNumber += 1
  143. end
  144. ipOffset += 1
  145. }
  146. return 0
  147. end # defineGroups
  148. def prepareNodes(serversMap, clientsMap)
  149. serversMap.each_value { | group |
  150. group.group.net.e0.ip = group.ipAddress
  151. `mkdir -p #{property.tmpDir}/#{group.hostname}`
  152. }
  153. clientsMap.each_value { | group |
  154. group.group.net.e0.ip = group.ipAddress
  155. `mkdir -p #{property.tmpDir}/#{group.hostname}`
  156. }
  157. return 0
  158. end # prepareNodes
  159. def prepareDelayModule(serversMap, clientsMap, baseUrl, clickScript)
  160. info "Building delay module Click script"
  161. # Download delay module click script
  162. #cmd = "#{property.wget} #{property.scriptUrl}/#{property.clickModule}"
  163. info "Downloading topology route file"
  164. system("#{property.wget} #{property.dataUrl}/#{property.routeFile}")
  165. info "Building delay configurations"
  166. # This function will set the "delayConfig" member of each server/client
  167. makeDelayConfig(serversMap,clientsMap,property.routeFile.to_s)
  168. asCount = Hash.new(0)
  169. serversMap.each_value { |group|
  170. clickScript = makeDelayScript(group,false)
  171. `echo '#{clickScript}' | sed -e 's/\\\\\\([()]\\)/\\1/g' >#{property.tmpDir}/#{group.hostname}/#{property.clickModule}`
  172. unless $?.success?
  173. puts "Unable to generate click script for #{group.hostname}."
  174. return -1
  175. end
  176. group.nodelist.each { |node|
  177. `echo '#{node.delayConfig}' | sed -e 's/\\\\\\([()]\\)/\\1/g' >#{property.tmpDir}/#{group.hostname}/delayMod#{node.asNumber}R#{asCount[node.asNumber]}.dat`
  178. unless $?.success?
  179. puts "Unable to copy click script for server #{node.asNumber}."
  180. return -1
  181. end
  182. asCount[node.asNumber] = asCount[node.asNumber]+1
  183. }
  184. }
  185. clientsMap.each_value { |group|
  186. clickScript = makeDelayScript(group,true)
  187. `echo '#{clickScript}' | sed -e 's/\\\\\\([()]\\)/\\1/g' >#{property.tmpDir}/#{group.hostname}/#{property.clickModule}`
  188. unless $?.success?
  189. puts "Unable to generate click script for #{group.hostname}."
  190. return -1
  191. end
  192. group.nodelist.each { |node|
  193. `echo '#{node.delayConfig}' | sed -e 's/\\\\\\([()]\\)/\\1/g' >#{property.tmpDir}/#{group.hostname}/delayMod#{node.asNumber}R#{asCount[node.asNumber]}.dat`
  194. unless $?.success?
  195. puts "Unable to copy click script for client #{node.asNumber}."
  196. return -1
  197. end
  198. asCount[node.asNumber] = asCount[node.asNumber]+1
  199. }
  200. }
  201. return 0
  202. end
  203. def installDelayModule(serversMap, clientsMap, baseUrl, clickScript)
  204. info "Installing delay module click script"
  205. # Install the delay module click script
  206. serversMap.each_value { |group|
  207. cmd = "#{property.clickInstall} -u #{property.clickModule}"
  208. group.group.exec(cmd)
  209. }
  210. clientsMap.each_value { |group|
  211. cmd = "#{property.clickInstall} -u #{property.clickModule}"
  212. group.group.exec(cmd)
  213. }
  214. wait property.miniWait
  215. info "Installing the delay module configurations"
  216. asCount = Hash.new(0)
  217. serversMap.each_value { |group|
  218. group.nodelist.each { |node|
  219. cmd = "cp /delayMod#{node.asNumber}R#{asCount[node.asNumber]}.dat /click/delayMod#{node.asNumber}R#{asCount[node.asNumber]}/config"
  220. node.group.group.exec(cmd)
  221. asCount[node.asNumber] = asCount[node.asNumber]+1
  222. }
  223. }
  224. asCount = Hash.new(0)
  225. clientsMap.each_value { |group|
  226. group.nodelist.each { |node|
  227. cmd = "cp /delayMod#{node.asNumber}R#{asCount[node.asNumber]}.dat /click/delayMod#{node.asNumber}R#{asCount[node.asNumber]}/config"
  228. node.group.group.exec(cmd)
  229. asCount[node.asNumber] = asCount[node.asNumber]+1
  230. }
  231. }
  232. # wait property.miniWait
  233. # Delete any files we downloaded and no longer need
  234. # info "Deleting temporary files"
  235. # system("rm #{property.routeFile}");
  236. # serversMap.each_value { |group|
  237. # group.nodelist.each { |node|
  238. # cmd = "rm #{property.clickModule}"
  239. # node.group.group.exec(cmd)
  240. # cmd = "rm #{property.delayConfigServer}".gsub(/XxX/,node.asNumber.to_s)
  241. # node.group.group.exec(cmd)
  242. # }
  243. # }
  244. # clientsMap.each_value { |group|
  245. # group.nodelist.each { |node|
  246. # cmd = "rm #{property.clickModule}"
  247. # node.group.group.exec(cmd)
  248. # cmd = "rm #{property.delayConfigClient}".gsub(/XxX/,node.asNumber.to_s)
  249. # node.group.group.exec(cmd)
  250. # }
  251. # }
  252. return 0
  253. end # prepareDelayModule
  254. def installConfigs(serversMap, clientsMap)
  255. info "Creating required directories"
  256. asCount = Hash.new(0)
  257. serversMap.each_value { |group|
  258. group.nodelist.each { |server|
  259. `mkdir -p #{property.tmpDir}/#{group.hostname}/var/gnrs/stats#{server.asNumber}$#{asCount[server.asNumber]}`
  260. asCount[server.asNumber] = asCount[server.asNumber] + 1
  261. }
  262. `mkdir -p #{property.tmpDir}/#{group.hostname}/etc/gnrs`
  263. `mkdir -p #{property.tmpDir}/#{group.hostname}/usr/local/bin/gnrs`
  264. `mkdir -p #{property.tmpDir}/#{group.hostname}/etc/init.d`
  265. }
  266. clientsMap.each_value { |group|
  267. group.nodelist.each { |server|
  268. `mkdir -p #{property.tmpDir}/#{group.hostname}/var/gnrs/stats#{server.asNumber}$#{asCount[server.asNumber]}`
  269. asCount[server.asNumber] = asCount[server.asNumber] + 1
  270. }
  271. `mkdir -p #{property.tmpDir}/#{group.hostname}/etc/gnrs`
  272. `mkdir -p #{property.tmpDir}/#{group.hostname}/usr/local/bin/gnrs`
  273. }
  274. wait property.microWait
  275. info "Downloading server configuration files."
  276. `#{property.wget} #{property.dataUrl}/#{property.prefixIpv4}`
  277. `#{property.wget} #{property.dataUrl}/#{property.mapIpv4}`
  278. `#{property.wget} #{property.scriptUrl}/#{property.jarFile}`
  279. `#{property.wget} #{property.scriptUrl}/#{property.gnrsd}`
  280. # GGen script
  281. `#{property.wget} #{property.scriptUrl}/#{property.ggen}`
  282. # GBench script
  283. `#{property.wget} #{property.scriptUrl}/#{property.gbench}`
  284. # Build AS binding file
  285. asBinding = makeBindingFile(serversMap)
  286. info "Finished making binding file for servers"
  287. serversMap.each_value { |group|
  288. group.nodelist.each { |node|
  289. # Main server config
  290. configContents = makeServerConfig(node)
  291. `echo '#{configContents}' >#{property.tmpDir}/#{group.hostname}/etc/gnrs/server_#{node.asNumber}.xml`
  292. # Networking config
  293. configContents = makeServerNetConfig(node)
  294. `echo '#{configContents}' >#{property.tmpDir}/#{group.hostname}/etc/gnrs/net-ipv4_#{node.asNumber}.xml`
  295. bdb = makeBerkeleyDBConfig(node)
  296. `echo '#{bdb}' >#{property.tmpDir}/#{group.hostname}/etc/gnrs/berkeleydb_#{node.asNumber}.xml`
  297. initScript = makeServerInit(node)
  298. # The sed command below will replace any escaped ( or ) characters on the
  299. # node side. This is because the ResourceController (RC) in OMF will
  300. # crash if the string contains unbalanced ( or ) characters.
  301. # Big thanks to Ben Firner for the regular expression
  302. `echo '#{initScript}' | sed -e 's/\\\\\\([()]\\)/\\1/g' >#{property.tmpDir}/#{group.hostname}/etc/init.d/gnrsd_#{node.asNumber}`
  303. }
  304. # Download static files
  305. # Binding file
  306. # IPv4 Prefix File (BGP Table)
  307. `cp #{property.prefixIpv4} #{property.tmpDir}/#{group.hostname}/etc/gnrs/`
  308. # IPv4 Mapper Configuration
  309. `cp #{property.mapIpv4} #{property.tmpDir}/#{group.hostname}/etc/gnrs/`
  310. # Jar file
  311. `cp #{property.jarFile} #{property.tmpDir}/#{group.hostname}/usr/local/bin/gnrs/`
  312. # GNRSD script
  313. `cp #{property.gnrsd} #{property.tmpDir}/#{group.hostname}/usr/local/bin/gnrs/`
  314. # Binding file
  315. `echo '#{asBinding}' >#{property.tmpDir}/#{group.hostname}/etc/gnrs/topology.bind`
  316. }
  317. info "Downloading client configuration files"
  318. asCount = Hash.new(0)
  319. clientsMap.each_value { |group|
  320. group.nodelist.each { |node|
  321. # Client trace file
  322. cmd = "#{property.wget} -P #{property.tmpDir}/#{group.hostname}/etc/gnrs/ #{property.dataUrl}/#{property.clientTrace}".gsub(/XxX/,node.asNumber.to_s)
  323. `#{cmd}`
  324. # Main client config
  325. configContents = makeClientConfig(node,node.server,asCount[node.asNumber])
  326. `echo '#{configContents}' >#{property.tmpDir}/#{group.hostname}/etc/gnrs/client#{node.asNumber}R#{asCount[node.asNumber]}.xml`
  327. asCount[node.asNumber] = asCount[node.asNumber]+1
  328. }
  329. `cp #{property.jarFile} #{property.tmpDir}/#{group.hostname}/usr/local/bin/gnrs/`
  330. `cp #{property.ggen} #{property.tmpDir}/#{group.hostname}/usr/local/bin/gnrs/`
  331. `cp #{property.gbench} #{property.tmpDir}/#{group.hostname}/usr/local/bin/gnrs/`
  332. }
  333. return 0
  334. end # installConfigs
  335. def buildTarballs()
  336. currDir = `pwd`.chomp
  337. Dir.chdir("#{property.tmpDir}")
  338. Dir.glob("*/"){ |dir|
  339. dirname = dir.to_s.chomp('/')
  340. `cd #{dir} && tar -czvf ../#{dirname}.tgz .`
  341. unless $?.success?
  342. puts "Unable to build tarball #{dirname}.tgz"
  343. return -1
  344. end
  345. }
  346. Dir.chdir("#{currDir}")
  347. return 0
  348. end # buildTarballs
  349. def getHostTarballs(serversMap, clientsMap)
  350. serversMap.each_value { |group|
  351. cmd = "cd / && #{property.wget} #{property.tarUrl}/#{group.hostname}.tgz && tar -zxf #{group.hostname}.tgz"
  352. group.group.exec(cmd)
  353. }
  354. clientsMap.each_value { |group|
  355. cmd = "cd / && #{property.wget} #{property.tarUrl}/#{group.hostname}.tgz && tar -zxf #{group.hostname}.tgz"
  356. group.group.exec(cmd)
  357. }
  358. wait property.largeWait
  359. serversMap.each_value { |group|
  360. cmd = "chmod +x /usr/local/bin/gnrs/gnrsd"
  361. group.group.exec(cmd)
  362. group.nodelist.each { |node|
  363. cmd = "chmod +x /etc/init.d/gnrsd_#{node.asNumber}"
  364. group.group.exec(cmd)
  365. }
  366. }
  367. clientsMap.each_value { |group|
  368. cmd = "chmod +x /usr/local/bin/gnrs/gbench /usr/local/bin/gnrs/ggen"
  369. group.group.exec(cmd)
  370. }
  371. return 0
  372. end # getHostTarballs
  373. def installInit(servers)
  374. info "Installing server init scripts."
  375. servers.each_value { |group|
  376. group.nodelist.each { |node|
  377. # Update rc.d scripts
  378. cmd = "#{property.updateRc} gnrsd_#{node.asNumber} stop 2 0 1 2 3 4 5 6 ."
  379. node.group.group.exec(cmd)
  380. }
  381. }
  382. end
  383. def launchServers(serversMap)
  384. info "Launching server processes"
  385. serversMap.each_value { |group|
  386. info "\t#{group}"
  387. }
  388. serversMap.each_value { |group|
  389. group.nodelist.each { |node|
  390. cmd = "service gnrsd_#{node.asNumber} start"
  391. node.group.group.exec(cmd)
  392. }
  393. }
  394. return 0
  395. end #launchServers
  396. def loadGUIDs(clientsMap)
  397. info "Launching trace clients"
  398. clientsMap.each_value { |group|
  399. info "\t#{group}"
  400. }
  401. # 3 parameters to gbench: client config, trace file, inter-message send time in microseconds
  402. asCount = Hash.new(0)
  403. clientsMap.each_value { |group|
  404. group.nodelist.each { |node|
  405. cmd = "export gnrsLogfile=/var/log/gbench_#{node.asNumber}R#{asCount[node.asNumber]}.log; /usr/local/bin/gnrs/#{property.gbench} /etc/gnrs/client#{node.asNumber}R#{asCount[node.asNumber]}.xml /etc/gnrs/client_#{node.asNumber}.trace #{property.messageDelay}"
  406. node.group.group.exec(cmd)
  407. asCount[node.asNumber] = asCount[node.asNumber] + 1
  408. }
  409. }
  410. return 0
  411. end # loadGUIDs
  412. def genLookups(clientsMap)
  413. info "Launching generation clients"
  414. clientsMap.each_value { |node|
  415. baseCmd = "/usr/local/bin/gnrs/#{property.ggen} /etc/gnrs/client#{node.asNumber}.xml #{property.numLookups} #{property.messageDelay} 1"
  416. node.group.exec(baseCmd)
  417. }
  418. return 0
  419. end # genLookups
  420. def stopServers(serversMap)
  421. info "Stopping gnrs servers"
  422. serversMap.each_value { |group|
  423. group.nodelist.each { |node|
  424. cmd = "service gnrsd_#{node.asNumber} stop"
  425. node.group.group.exec(cmd)
  426. }
  427. }
  428. return 0
  429. end # stopServers
  430. def removeExperimentFiles(nodeMap)
  431. nodeMap.each_value { |group|
  432. group.group.exec("rm -rf /var/gnrs /etc/gnrs /usr/local/bin/gnrs /trace-client /var/log/gbench*.log /var/log/gnrsd*.log /#{group.hostname}.tgz /delayMod*")
  433. group.nodelist.each { |node|
  434. group.group.exec("#{property.updateRc} -f gnrsd_#{node.asNumber} remove")
  435. group.group.exec("rm /etc/init.d/gnrsd_#{node.asNumber}")
  436. group.group.exec("#{property.clickUninstall}")
  437. }
  438. }
  439. return 0
  440. end # removeExperimentFiles