PageRenderTime 911ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/veewee/provider/parallels/box/export.rb

https://github.com/halvards/veewee
Ruby | 184 lines | 135 code | 33 blank | 16 comment | 11 complexity | 1887f14ef5803e8e973e185a2bf8733f MD5 | raw file
  1. require 'pathname'
  2. require 'erb'
  3. module Veewee
  4. module Provider
  5. module Parallels
  6. module BoxCommand
  7. class ErbBinding < OpenStruct
  8. def get_binding
  9. return binding()
  10. end
  11. end
  12. def export_vagrant(options)
  13. # For now, we just assume prlctl is in the path. If not...it'll fail.
  14. @prlcmd = "prlctl"
  15. @prldisktool = "prl_disk_tool"
  16. # Check if box already exists
  17. unless self.exists?
  18. ui.info "#{name} is not found, maybe you need to build it first?"
  19. exit
  20. end
  21. if File.exists?("#{name}.box")
  22. if options["force"]
  23. env.logger.debug("#{name}.box exists, but --force was provided")
  24. env.logger.debug("removing #{name}.box first")
  25. FileUtils.rm("#{name}.box")
  26. env.logger.debug("#{name}.box removed")
  27. else
  28. raise Veewee::Error, "export file #{name}.box already exists. Use --force option to overwrite."
  29. end
  30. end
  31. # We need to shutdown first
  32. if self.running?
  33. ui.info "Vagrant requires the box to be shutdown, before it can export"
  34. ui.info "Sudo also needs to work for user #{definition.ssh_user}"
  35. ui.info "Performing a clean shutdown now."
  36. self.halt
  37. #Wait for state poweroff
  38. while (self.running?) do
  39. ui.info ".",{:new_line => false}
  40. sleep 1
  41. end
  42. ui.info ""
  43. ui.info "Machine #{name} is powered off cleanly"
  44. end
  45. #Vagrant requires a relative path for output of boxes
  46. #4.0.x. not using boxes as a subdir
  47. boxdir=Pathname.new(Dir.pwd)
  48. full_path=File.join(boxdir,name+".box")
  49. path1=Pathname.new(full_path)
  50. path2=Pathname.new(Dir.pwd)
  51. box_path=File.expand_path(path1.relative_path_from(path2).to_s)
  52. if File.exists?("#{box_path}")
  53. raise Veewee::Error, "box #{name}.box already exists"
  54. end
  55. # VMWare Fusion does this to the real machine, so we will too.
  56. optimize_disk
  57. # Create temp directory
  58. current_dir = FileUtils.pwd
  59. ui.info "Creating a temporary directory for export"
  60. tmp_dir = Dir.mktmpdir
  61. env.logger.debug("Create temporary directory for export #{tmp_dir}")
  62. begin
  63. ui.info "Adding additional files"
  64. # Handling the Vagrantfile
  65. if options["vagrantfile"].to_s == ""
  66. # Fetching mac address
  67. data = {
  68. :macaddress => get_mac_address
  69. }
  70. # Prepare the vagrant erb
  71. vars = ErbBinding.new(data)
  72. template_path = File.join(File.dirname(__FILE__),'..','..','..','templates',"Vagrantfile.erb")
  73. template = File.open(template_path).readlines.join
  74. erb = ERB.new(template)
  75. vars_binding = vars.send(:get_binding)
  76. result = erb.result(vars_binding)
  77. ui.info("Creating Vagrantfile")
  78. vagrant_path = File.join(tmp_dir,'Vagrantfile')
  79. env.logger.debug("Path: #{vagrant_path}")
  80. env.logger.debug(result)
  81. File.open(vagrant_path,'w') {|f| f.write(result) }
  82. else
  83. f = options["vagrantfile"]
  84. env.logger.debug("Including vagrantfile: #{f}")
  85. FileUtils.cp(f,File.join(tmp_dir,"Vagrantfile"))
  86. end
  87. #Inject a metadata.json file
  88. ui.info("Adding metadata.json file for Parallels Desktop provider")
  89. File.open(File.join(tmp_dir, 'metadata.json'), 'w') {|f| f.write(template_metadatafile()) }
  90. ui.info "Exporting the box"
  91. tmp_dest = File.join(tmp_dir, "box.pvm")
  92. clone_command = "#{@prlcmd} clone #{name} --name #{name}-veewee --template --location #{tmp_dir}"
  93. shell_exec clone_command
  94. env.logger.debug("Clone #{name} to #{name}-veewee, location #{tmp_dir}")
  95. # Previous command causes the VM to get registered, so unregister it to keep user's VM list clean
  96. unregister_command = "#{@prlcmd} unregister #{name}-veewee"
  97. shell_exec unregister_command
  98. env.logger.debug "Unregister #{name}-veewee after clone"
  99. FileUtils.move File.join(tmp_dir, "#{name}-veewee.pvm"), tmp_dest
  100. env.logger.debug("Rename Parallels Desktop-created file to what we expect")
  101. ui.info "Packaging the box"
  102. FileUtils.cd(tmp_dir)
  103. command_box_path = box_path
  104. # Gzip, for extra smallness
  105. command = "tar -cvzf '#{command_box_path}' ."
  106. env.logger.debug(command)
  107. shell_exec (command)
  108. rescue Errno::ENOENT => ex
  109. raise Veewee::Error, "#{ex}"
  110. rescue Error => ex
  111. raise Veewee::Error, "Packaging of the box failed:\n+#{ex}"
  112. ensure
  113. # Remove temporary directory
  114. ui.info "Cleaning up temporary directory"
  115. env.logger.debug("Removing temporary dir #{tmp_dir}")
  116. FileUtils.rm_rf(tmp_dir)
  117. FileUtils.cd(current_dir)
  118. end
  119. ui.info ""
  120. ui.info "To import it into vagrant type:"
  121. ui.info "vagrant box add '#{name}' '#{box_path}'"
  122. ui.info ""
  123. ui.info "To use it:"
  124. ui.info "vagrant init '#{name}'"
  125. ui.info "vagrant up --provider=parallels"
  126. ui.info "vagrant ssh"
  127. end
  128. # Inspired by vagrant-parallels
  129. def read_settings
  130. command = "#{@prlcmd} list --info --json \"#{self.name}\""
  131. r = shell_exec(command).stdout
  132. JSON.parse (r.gsub("/\s+/", "").gsub(/^(INFO)?\[/, '').gsub(/\]$/, ''))
  133. end
  134. def get_mac_address
  135. mac = read_settings.fetch("Hardware").fetch("net0").fetch("mac")
  136. env.logger.debug("mac address: #{mac}")
  137. return mac
  138. end
  139. def template_metadatafile
  140. %Q({"provider": "parallels"}\n)
  141. end
  142. def optimize_disk
  143. env.ui.info "Optimizing Disk"
  144. path_to_hdd = File.join read_settings.fetch("Home"), "harddisk.hdd"
  145. optimize_command = "#{@prldisktool} compact --hdd #{path_to_hdd}"
  146. shell_exec optimize_command
  147. end
  148. end #Module
  149. end #Module
  150. end #Module
  151. end #Module