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