1# -*- mode: ruby -*- 2# vi: set ft=ruby : 3 4require 'open3' 5def get_box_type(distro, force_distro) 6 spdk_distro = 'spdk/' + distro 7 localboxes, stderr, status = Open3.capture3("vagrant box list") 8 return spdk_distro if localboxes.include?(spdk_distro) 9 10 distro_to_type = { 11 'centos7' => 'centos/7', 12 'centos8' => 'centos/8', 13 'ubuntu1604' => 'peru/ubuntu-16.04-server-amd64', 14 'ubuntu1804' => 'peru/ubuntu-18.04-server-amd64', 15 'ubuntu2004' => 'peru/ubuntu-20.04-server-amd64', 16 'ubuntu2204' => 'generic/ubuntu2204', 17 'fedora33' => 'generic/fedora33', 18 'fedora34' => 'generic/fedora34', 19 'fedora35' => 'generic/fedora35', 20 'fedora36' => 'generic/fedora36', 21 'arch' => 'generic/arch', 22 'freebsd12' => 'generic/freebsd12', 23 'freebsd13' => 'generic/freebsd13', 24 'rocky8' => 'rockylinux/8' 25 } 26 abort("Invalid argument! #{distro}") unless distro_to_type.key?(distro) || force_distro 27 28 return distro_to_type[distro] ? distro_to_type[distro] : distro 29end 30 31def setup_proxy(config,distro) 32 return unless ENV['http_proxy'] 33 34 if Vagrant.has_plugin?("vagrant-proxyconf") 35 config.proxy.http = ENV['http_proxy'] 36 config.proxy.https = ENV['https_proxy'] 37 config.proxy.no_proxy = "localhost,127.0.0.1" 38 end 39 40 # Proxyconf does not seem to support FreeBSD boxes or at least it's 41 # docs do not mention that. Set up proxy configuration manually. 42 if distro.include?("freebsd") 43 $freebsd_proxy = <<-SCRIPT 44 sudo -s 45 echo "export http_proxy=#{ENV['http_proxy']}" >> /etc/profile 46 echo "export https_proxy=#{ENV['http_proxy']}" >> /etc/profile 47 echo "pkg_env: {http_proxy: #{ENV['http_proxy']}}" > /usr/local/etc/pkg.conf 48 chown root:wheel /usr/local/etc/pkg.conf 49 chmod 644 /usr/local/etc/pkg.conf 50 SCRIPT 51 config.vm.provision "shell", inline: $freebsd_proxy 52 end 53end 54 55def copy_gitconfig(config) 56 src_path = '~/.gitconfig' 57 return unless File.file?(File.expand_path(src_path)) 58 59 config.vm.provision "file", source: src_path, destination: ".gitconfig" 60end 61 62def copy_tsocks(config) 63 tsocks_file = 'tsocks.conf' 64 tsocks_file_path = '/etc/' + tsocks_file 65 66 return unless File.file?(tsocks_file_path) 67 68 $tsocks_copy_cmd = <<-SCRIPT 69 sudo -s 70 mv -f "#{tsocks_file}" "#{tsocks_file_path}" 71 chown root "#{tsocks_file_path}" 72 chmod 644 "#{tsocks_file_path}" 73 SCRIPT 74 75 config.vm.provision "file", source: tsocks_file_path, destination: tsocks_file 76 config.vm.provision "shell", inline: $tsocks_copy_cmd 77end 78 79def copy_vagrant_tools(config,files_sync_backend) 80 src_path = '~/vagrant_tools' 81 return unless File.directory?(File.expand_path(src_path)) 82 83 config.vm.synced_folder src_path, "/home/vagrant/tools", files_sync_backend 84end 85 86def copy_spdk_dir(config, files_sync_backend) 87 return unless ENV['COPY_SPDK_DIR'] == "1" 88 return unless ENV['SPDK_DIR'] 89 90 config.vm.synced_folder ENV['SPDK_DIR'], '/home/vagrant/spdk_repo/spdk', files_sync_backend 91end 92 93def copy_spdk_artifacts(config, plugins_sync_backend) 94 return unless ENV['COPY_SPDK_ARTIFACTS'] == "1" 95 96 vagrantfile_dir=(ENV['VAGRANTFILE_DIR'] || "none") 97 config.vm.synced_folder "#{vagrantfile_dir}/output", "/home/vagrant/spdk_repo/output", plugins_sync_backend 98end 99 100def make_spdk_local_copy_of_nfs(config,distro) 101 user_group = 'vagrant:vagrant' 102 103 spdk_path = '/home/vagrant/spdk_repo/spdk' 104 spdk_tmp_path = '/tmp/spdk' 105 $spdk_repo_cmd = <<-SCRIPT 106 sudo -s 107 cp -R '#{spdk_path}' '#{spdk_tmp_path}' 108 umount '#{spdk_path}' && rm -rf '#{spdk_path}' 109 mv '#{spdk_tmp_path}' '#{spdk_path}' 110 chown -R #{user_group} '#{spdk_path}' 111 SCRIPT 112 113 config.vm.provision "shell", inline: $spdk_repo_cmd 114end 115 116def get_nvme_disk(disk, index) 117 if ENV['NVME_FILE'] 118 nvme_file = ENV['NVME_FILE'].split(',') 119 nvme_disk = nvme_file[index] 120 else 121 nvme_disk = '/var/lib/libvirt/images/nvme_disk.img' 122 end 123 124 unless nvme_disk == "none" || File.exist?(nvme_disk) 125 puts 'If run with libvirt provider please execute create_nvme_img.sh' 126 end 127 128 return nvme_disk 129end 130 131def setup_nvme_disk(libvirt, disk, index) 132 nvme_disk_id = disk + '-' + index.to_s 133 nvme_disk = get_nvme_disk(disk, index) 134 135 nvme_namespaces=(ENV['NVME_DISKS_NAMESPACES'] || "").split(',') 136 nvme_cmbs=(ENV['NVME_CMB'] || "").split(',') 137 nvme_pmrs=(ENV['NVME_PMR'] || "").split(',') 138 nvme_zns=(ENV['NVME_ZNS'] || "").split(',') 139 nvme_ms=(ENV['NVME_MS'] || "").split(',') 140 141 142 namespace_disks = [] 143 pmr_cmdline = "" 144 nvme_controller = "" 145 146 # Define controller 147 nvme_controller = "nvme,id=#{nvme_disk_id},serial=1234#{index}" 148 149 # Gather all drives - each namespace requires separate drive 150 if nvme_namespaces[index].nil? 151 namespace_disks = namespace_disks + nvme_disk.split() 152 elsif !nvme_namespaces[index].nil? && !nvme_namespaces[index].match(/^[0-9]+$/) 153 namespace_disks = namespace_disks + nvme_disk.split() + nvme_namespaces[index].split(':') 154 elsif !nvme_namespaces[index].nil? && nvme_namespaces[index].match(/^[0-9]+$/) 155 # Compatibility with spdk-5.0.0 fork 156 libvirt.qemuargs :value => "-drive" 157 libvirt.qemuargs :value => "format=raw,file=#{nvme_disk},if=none,id=#{nvme_disk_id}" 158 if nvme_namespaces[index] == "1" 159 nvme_controller <<",drive=#{nvme_disk_id}" 160 else 161 nvme_controller <<",namespaces=#{nvme_namespaces[index]},drive=#{nvme_disk_id}" 162 end 163 end 164 165 if !nvme_cmbs[index].nil? && nvme_cmbs[index] != "" 166 # Fix the size of the buffer to 128M 167 nvme_controller << ",cmb_size_mb=128" 168 end 169 170 if !nvme_pmrs[index].nil? && nvme_pmrs[index] != "" 171 pmr_path, pmr_size = nvme_pmrs[index].split(':') 172 if pmr_size.nil? 173 pmr_size = "16M" 174 end 175 nvme_controller << ",pmrdev=pmr#{index}" 176 pmr_cmdline = "memory-backend-file,id=pmr#{index},share=on,mem-path=#{pmr_path},size=#{pmr_size}" 177 end 178 179 libvirt.qemuargs :value => "-device" 180 libvirt.qemuargs :value => nvme_controller 181 182 if pmr_cmdline != "" 183 libvirt.qemuargs :value => "-object" 184 libvirt.qemuargs :value => pmr_cmdline 185 end 186 187 # Define all namespaces 188 namespace_disks.each_with_index { |disk, nsid| 189 if disk == "none" 190 next 191 end 192 zoned = nvme_zns[index].nil? ? "false" : "true" 193 ms = nvme_ms[index].nil? ? "" : ",ms=64" 194 libvirt.qemuargs :value => "-drive" 195 libvirt.qemuargs :value => "format=raw,file=#{disk},if=none,id=#{nvme_disk_id}-drive#{nsid}" 196 libvirt.qemuargs :value => "-device" 197 libvirt.qemuargs :value => "nvme-ns,drive=#{nvme_disk_id}-drive#{nsid},bus=#{nvme_disk_id},nsid=#{nsid + 1},zoned=#{zoned},logical_block_size=4096,physical_block_size=4096#{ms}" 198 } 199 200end 201 202def setup_ssh(config) 203 config.ssh.forward_agent = true 204 config.ssh.forward_x11 = true 205 if ENV['VAGRANT_PASSWORD_AUTH'] == "1" 206 config.ssh.username = "vagrant" 207 config.ssh.password = "vagrant" 208 config.ssh.private_key_path = nil 209 end 210end 211 212def deploy_test_vm(config, distro, plugins_sync_backend) 213 return unless ENV['DEPLOY_TEST_VM'] == "1" 214 return unless ENV['COPY_SPDK_DIR'] == "1" 215 return unless ENV['SPDK_DIR'] 216 217 # use http proxy if available 218 setup_proxy(config, distro) 219 220 # Copy the tsocks configuration file for use when installing some spdk test pool dependencies 221 copy_tsocks(config) 222 223 # freebsd boxes in order to have spdk sources synced from 224 # host properly will use NFS with "ro" option enabled to prevent changes 225 # on host filesystem. 226 # To make sources usable in the guest VM we need to unmount them and use 227 # local copy. 228 make_spdk_local_copy_of_nfs(config,distro) if plugins_sync_backend[:type] == :nfs 229 230 config.vm.provision "shell" do |setup| 231 setup.inline = "/home/vagrant/spdk_repo/spdk/test/common/config/vm_setup.sh" 232 setup.privileged = false 233 setup.args = ["-u", "-i"] 234 end 235end 236 237def setup_virtualbox(config, vmcpu, vmram) 238 config.vm.provider "virtualbox" do |vb| 239 vb.customize ["modifyvm", :id, "--ioapic", "on"] 240 vb.memory = vmram 241 vb.cpus = vmcpu 242 243 nvme_disk=(ENV['NVME_FILE'] || "nvme_disk.img") 244 unless File.exist? (nvme_disk) 245 vb.customize ["createhd", "--filename", nvme_disk, "--variant", "Fixed", "--size", "1024"] 246 vb.customize ["storagectl", :id, "--name", "nvme", "--add", "pcie", "--controller", "NVMe", "--portcount", "1", "--bootable", "off"] 247 vb.customize ["storageattach", :id, "--storagectl", "nvme", "--type", "hdd", "--medium", nvme_disk, "--port", "0"] 248 end 249 250 #support for the SSE4.x instruction is required in some versions of VB. 251 vb.customize ["setextradata", :id, "VBoxInternal/CPUM/SSE4.1", "1"] 252 vb.customize ["setextradata", :id, "VBoxInternal/CPUM/SSE4.2", "1"] 253 end 254end 255 256def setup_libvirt(config, vmcpu, vmram, distro) 257 emulated_nvme_types=(ENV['NVME_DISKS_TYPE'] || "nvme").split(',') 258 259 config.vm.provider "libvirt" do |libvirt, override| 260 libvirt.random_hostname = "1" 261 libvirt.driver = "kvm" 262 libvirt.graphics_type = "vnc" 263 libvirt.memory = vmram 264 libvirt.cpus = vmcpu 265 libvirt.video_type = "cirrus" 266 267 if (distro.include?("freebsd")) 268 # generic/freebsd boxes need to be explicitly run with SCSI bus, 269 # otherwise boot process fails on mounting the disk 270 libvirt.disk_bus = "scsi" 271 elsif (distro.include?("arch")) 272 # Run generic/arch boxes explicitly with IDE bus, 273 # otherwise boot process fails on mounting the disk 274 libvirt.disk_bus = "ide" 275 else 276 libvirt.disk_bus = "virtio" 277 end 278 279 if ENV['SPDK_QEMU_EMULATOR'] 280 libvirt.emulator_path = ENV['SPDK_QEMU_EMULATOR'] 281 libvirt.machine_type = "pc" 282 end 283 284 # we put nvme_disk inside default pool to eliminate libvirt/SELinux Permissions Problems 285 # and to be able to run vagrant from user $HOME directory 286 287 # Loop to create all emulated disks set 288 emulated_nvme_types.each_with_index { |disk, index| 289 setup_nvme_disk(libvirt, disk, index) 290 } 291 292 # Add network interface for openstack tests 293 if ENV['SPDK_OPENSTACK_NETWORK'] == "1" 294 libvirt.qemuargs :value => "-device" 295 libvirt.qemuargs :value => "virtio-net,netdev=openstack.0" 296 libvirt.qemuargs :value => "-netdev" 297 libvirt.qemuargs :value => "user,id=openstack.0" 298 end 299 300 if ENV['VAGRANT_HUGE_MEM'] == "1" 301 libvirt.memorybacking :hugepages 302 end 303 304 # Optional field if we want use other storage pools than default 305 # libvirt.storage_pool_name = "vm" 306 end 307end 308 309################################################################################################# 310# Pick the right distro and bootstrap, default is fedora33 311distro = (ENV['SPDK_VAGRANT_DISTRO'] || "fedora33") 312provider = (ENV['SPDK_VAGRANT_PROVIDER'] || "virtualbox") 313 314# Get all variables for creating vm 315vmcpu = (ENV['SPDK_VAGRANT_VMCPU'] || 2) 316vmram = (ENV['SPDK_VAGRANT_VMRAM'] || 4096) 317 318force_distro = ENV['FORCE_DISTRO'] == "true" ? true : false 319 320distro_to_use = get_box_type(distro, force_distro) 321if (distro_to_use.include?("generic/freebsd")) 322 files_sync_backend = {type: :nfs, nfs_udp: false, mount_options: ['ro']} 323 plugins_sync_backend = {type: :nfs, nfs_udp: false} 324else 325 # Remove --copy-links from default rsync cmdline since we do want to sync 326 # actual symlinks as well. Also, since copy is made between host and its 327 # local VM we don't need to worry about saturating the local link so skip 328 # the compression to speed up the whole transfer. 329 files_sync_backend = {type: "rsync", rsync__auto: false, rsync__args: ["--archive", "--verbose", "--delete"]} 330 plugins_sync_backend = {type: :sshfs} 331end 332 333Vagrant.configure(2) do |config| 334 config.vm.box = distro_to_use 335 config.vm.box_check_update = false 336 config.vm.synced_folder '.', '/vagrant', disabled: true 337 if ENV['VAGRANT_BOX_VERSION'] 338 config.vm.box_version = ENV['VAGRANT_BOX_VERSION'] 339 end 340 341 # Copy in the .gitconfig if it exists 342 copy_gitconfig(config) 343 344 # Copy in the user's tools if they exists 345 copy_vagrant_tools(config,files_sync_backend) 346 347 copy_spdk_dir(config, files_sync_backend) 348 349 # rsync artifacts from build 350 copy_spdk_artifacts(config, plugins_sync_backend) 351 352 # Setup SSH 353 setup_ssh(config) 354 355 # Virtualbox configuration 356 setup_virtualbox(config,vmcpu,vmram) 357 358 setup_libvirt(config,vmcpu,vmram,distro) 359 360 # provision the vm with all of the necessary spdk dependencies for running the autorun.sh tests 361 deploy_test_vm(config, distro, plugins_sync_backend) 362end 363 364if ENV['EXTRA_VAGRANTFILES'] 365 loaders = (ENV['EXTRA_VAGRANTFILES'].split(',')) 366 loaders.each { |loader| 367 load loader if File.exists?(loader) 368 } 369end 370