# frozen_string_literal: true

require 'log4r'
require 'fileutils'
require 'digest/md5'
require 'io/console'
require 'ruby_expect'
require 'netaddr'
require 'ipaddr'
require 'vagrant/util/numeric'
require 'pty'
require 'expect'
require 'vagrant'
require 'resolv'
require 'vagrant-zones/util/timer'
require 'vagrant-zones/util/subprocess'
require 'vagrant/util/retryable'

module VagrantPlugins
  module ProviderZone
    # This class does the heavy lifting of the zone provider
    class Driver
      include Vagrant::Util::Retryable
      attr_accessor :executor

      def initialize(machine)
        @logger = Log4r::Logger.new('vagrant_zones::driver')
        @machine = machine
        @executor = Executor::Exec.new
        @pfexec = if Process.uid.zero?
                    ''
                  elsif system('sudo -v')
                    'sudo'
                  else
                    'pfexec'
                  end
      end

      def state(machine)
        name = machine.name
        vm_state = execute(false, "#{@pfexec} zoneadm -z #{name} list -p | awk -F: '{ print $3 }'")
        case vm_state
        when 'running'
          :running
        when 'configured'
          :preparing
        when 'installed'
          :stopped
        when 'incomplete'
          :incomplete
        else
          :not_created
        end
      end

      # Execute System commands
      def execute(*cmd, **opts, &block)
        @executor.execute(*cmd, **opts, &block)
      end

      ## Begin installation for zone
      def install(uii)
        config = @machine.provider_config
        name = @machine.name
        case config.brand
        when 'lx'
          box = "#{@machine.data_dir}/#{@machine.config.vm.box}"
          results = execute(false, "#{@pfexec} zoneadm -z #{name} install -s #{box}")
          raise Errors::InvalidLXBrand if results.include? 'unknown brand'
        when 'bhyve'
          results = execute(false, "#{@pfexec} zoneadm -z #{name} install")
          raise Errors::InvalidbhyveBrand if results.include? 'unknown brand'
        when 'kvm' || 'illumos'
          raise Errors::NotYetImplemented
        end
        uii.info(I18n.t('vagrant_zones.installing_zone'))
        uii.info("  #{config.brand}")
      end

      ## Control the zone from inside the zone OS
      def control(uii, control)
        config = @machine.provider_config
        uii.info(I18n.t('vagrant_zones.control')) if config.debug
        case control
        when 'restart'
          command = 'sudo shutdown -r'
          command = config.safe_restart unless config.safe_restart.nil?
          ssh_run_command(uii, command)
        when 'shutdown'
          command = 'sudo init 0 || true'
          command = config.safe_shutdown unless config.safe_shutdown.nil?
          ssh_run_command(uii, command)
        else
          uii.info(I18n.t('vagrant_zones.control_no_cmd'))
        end
      end

      ## Run commands over SSH instead of ZLogin
      def ssh_run_command(uii, command)
        config = @machine.provider_config
        ip = get_ip_address('runsshcommmand')
        user = user(@machine)
        key = userprivatekeypath(@machine).to_s
        port = sshport(@machine).to_s
        port = 22 if sshport(@machine).to_s.nil?
        execute_return = ''
        Util::Timer.time do
          retryable(on: Errors::TimeoutError, tries: 60) do
            # If we're interrupted don't worry about waiting
            ssh_string = "#{@pfexec} ssh -o 'StrictHostKeyChecking=no' -p"
            execute_return = execute(false, %(#{ssh_string} #{port} -i #{key} #{user}@#{ip} "#{command}"))
            uii.info(I18n.t('vagrant_zones.ssh_run_command')) if config.debug
            uii.info(I18n.t('vagrant_zones.ssh_run_command') + command) if config.debug
            loop do
              break if @machine.communicate.ready?
            end
          end
        end
        execute_return
      end

      ## Function to provide console, vnc, or webvnc access
      ## Future To-Do: Should probably split this up
      def console(uii, command, ip, port, exit)
        uii.info(I18n.t('vagrant_zones.console'))
        detach = exit[:detach]
        kill = exit[:kill]
        name = @machine.name
        config = @machine.provider_config
        if port.nil?
          port = if config.consoleport.nil?
                   ''
                 else
                   config.consoleport
                 end
        end
        ipaddr = '0.0.0.0'
        ipaddr = config.consolehost if config.consolehost =~ Resolv::IPv4::Regex
        ipaddr = ip if ip =~ Resolv::IPv4::Regex
        netport = "#{ipaddr}:#{port}"
        pid = 0
        if File.exist?("#{name}.pid")
          pid = File.readlines("#{name}.pid")[0].strip
          ctype = File.readlines("#{name}.pid")[1].strip
          ts = File.readlines("#{name}.pid")[2].strip
          vmname = File.readlines("#{name}.pid")[3].strip
          nport = File.readlines("#{name}.pid")[4].strip
          uii.info("Session running with PID: #{pid} since: #{ts} as console type: #{ctype} served at: #{nport}\n") if vmname[name.to_s]
          if kill == 'yes'
            File.delete("#{name}.pid")
            Process.kill 'TERM', pid.to_i
            Process.detach pid.to_i
            uii.info('Session Terminated')
          end
        else
          case command
          when /vnc/
            run = "pfexec zadm #{command} #{netport} #{name}"
            pid = spawn(run)
            Process.wait pid if detach == 'no'
            Process.detach(pid) if detach == 'yes'
            time = Time.new.strftime('%Y-%m-%d-%H:%M:%S')
            File.write("#{name}.pid", "#{pid}\n#{command}\n#{time}\n#{name}\n#{netport}") if detach == 'yes'
            uii.info("Session running with PID: #{pid} as console type: #{command} served at: #{netport}") if detach == 'yes'
          when 'zlogin'
            run = "#{@pfexec} zadm console #{name}"
            exec(run)
          end
        end
      end

      ## Boot the Machine
      def boot(uii)
        name = @machine.name
        uii.info(I18n.t('vagrant_zones.starting_zone'))
        execute(false, "#{@pfexec} zoneadm -z #{name} boot")
      end

      # This filters the VM usage for VNIC Naming Purposes
      def vtype(uii)
        config = @machine.provider_config
        uii.info(I18n.t('vagrant_zones.vtype')) if config.debug
        case config.vm_type
        when /template/
          '1'
        when /development/
          '2'
        when /production/ || nil
          '3'
        when /firewall/
          '4'
        when /other/
          '5'
        end
      end

      # This filters the NIC Types
      def nictype(opts)
        case opts[:nictype]
        when /external/ || nil
          'e'
        when /internal/
          'i'
        when /carp/
          'c'
        when /management/
          'm'
        when /host/
          'h'
        end
      end

      # This Sanitizes the DNS Records
      def dnsservers(uii, opts)
        config = @machine.provider_config
        servers = opts['dns']
        servers = [{ 'nameserver' => '1.1.1.1' }, { 'nameserver' => '8.8.8.8' }] if opts['dns'].nil?
        uii.info(I18n.t('vagrant_zones.nsservers') + servers.to_s) if config.debug
        servers
      end

      # This Sanitizes the Mac Address
      def macaddress(uii, opts)
        config = @machine.provider_config
        regex = /^(?:[[:xdigit:]]{2}([-:]))(?:[[:xdigit:]]{2}\1){4}[[:xdigit:]]{2}$/
        mac = opts[:mac] unless opts[:mac].nil?
        mac = 'auto' unless mac.match(regex)
        uii.info(I18n.t('vagrant_zones.mac') + mac) if config.debug
        mac
      end

      # This Sanitizes the IP Address to set
      def ipaddress(uii, opts)
        config = @machine.provider_config
        ip = if opts[:ip].empty?
               nil
             else
               opts[:ip].gsub(/\t/, '')
             end
        uii.info(I18n.t('vagrant_zones.ipaddress') + ip) if config.debug
        ip
      end

      # This Sanitizes the AllowedIP Address to set for Cloudinit
      def allowedaddress(uii, opts)
        config = @machine.provider_config
        ip = ipaddress(uii, opts)
        shrtsubnet = IPAddr.new(opts[:netmask].to_s).to_i.to_s(2).count('1').to_s
        allowed_address = "#{ip}/#{shrtsubnet}"
        uii.info(I18n.t('vagrant_zones.allowedaddress') + allowed_address) if config.debug
        allowed_address
      end

      # This Sanitizes the VNIC Name
      def vname(uii, opts)
        config = @machine.provider_config
        vnic_name = "vnic#{nictype(opts)}#{vtype(uii)}_#{config.partition_id}_#{opts[:nic_number]}"
        uii.info(I18n.t('vagrant_zones.vnic_name') + vnic_name) if config.debug
        vnic_name
      end

      ## If DHCP and Zlogin, get the IP address
      def get_ip_address(_function)
        config = @machine.provider_config
        name = @machine.name
        # uii.info(I18n.t('vagrant_zones.get_ip_address')) if config.debug
        @machine.config.vm.networks.each do |_adaptertype, opts|
          responses = []
          nic_type = nictype(opts)
          if opts[:dhcp4] && opts[:managed]
            vnic_name = "vnic#{nic_type}#{vtype(uii)}_#{config.partition_id}_#{opts[:nic_number]}"
            PTY.spawn("pfexec zlogin -C #{name}") do |zlogin_read, zlogin_write, pid|
              command = "ip -4 addr show dev #{vnic_name} | head -n -1 | tail -1 | awk '{ print $2 }' | cut -f1 -d\"/\" \n"
              zlogin_read.expect(/\n/) { zlogin_write.printf(command) }
              Timeout.timeout(config.clean_shutdown_time) do
                loop do
                  zlogin_read.expect(/\r\n/) { |line| responses.push line }
                  if responses[-1].to_s.match(/(?:[0-9]{1,3}\.){3}[0-9]{1,3}/)
                    ip = responses[-1][0].rstrip.gsub(/\e\[\?2004l/, '').lstrip
                    return nil if ip.empty?
                    return ip.gsub(/\t/, '') unless ip.empty?

                    break
                  end
                  errormessage = "==> #{name} ==> Command ==> #{cmd} \nFailed with ==> #{responses[-1]}"
                  raise errormessage if responses[-1].to_s.match(/Error Code: \b(?!0\b)\d{1,4}\b/)
                end
              end
              Process.kill('HUP', pid)
            end
          elsif (opts[:dhcp4] == false || opts[:dhcp4].nil?) && opts[:managed]
            ip = opts[:ip].to_s
            return nil if ip.empty?

            return ip.gsub(/\t/, '')
          end
        end
      end

      ## Manage Network Interfaces
      def network(uii, state)
        config = @machine.provider_config
        uii.info(I18n.t('vagrant_zones.creating_networking_interfaces')) if state == 'create'
        @machine.config.vm.networks.each do |adaptertype, opts|
          case adaptertype.to_s
          when 'public_network'
            zonenicdel(uii, opts) if state == 'delete'
            zonecfgnicconfig(uii, opts) if state == 'config'
            zoneniccreate(uii, opts) if state == 'create'
            zonenicstpzloginsetup(uii, opts, config) if state == 'setup' && config.setup_method == 'zlogin'
          when 'private_network'
            zonenicdel(uii, opts) if state == 'delete'
            zonedhcpentriesrem(uii, opts) if state == 'delete'
            zonenatclean(uii, opts) if state == 'delete'
            etherstubdelhvnic(uii, opts) if state == 'delete'
            etherstubdelete(uii, opts) if state == 'delete'
            natnicconfig(uii, opts) if state == 'config'
            etherstub = etherstubcreate(uii, opts) if state == 'create'
            zonenatniccreate(uii, opts, etherstub) if state == 'create'
            etherstubcreatehvnic(uii, opts, etherstub) if state == 'create'
            zonenatforward(uii, opts) if state == 'create'
            zonenatentries(uii, opts) if state == 'create'
            zonedhcpentries(uii, opts) if state == 'create'
            zonedhcpcheckaddr(uii, opts) if state == 'setup'
            zonenicnatsetup(uii, opts) if state == 'setup'
          end
        end
      end

      ## Delete DHCP entries for Zones
      def zonedhcpentriesrem(uii, opts)
        config = @machine.provider_config

        ip = ipaddress(uii, opts)
        name = @machine.name
        defrouter = opts[:gateway].to_s
        shrtsubnet = IPAddr.new(opts[:netmask].to_s).to_i.to_s(2).count('1').to_s
        hvnic_name = "h_vnic_#{config.partition_id}_#{opts[:nic_number]}"
        mac = macaddress(uii, opts)

        ## if mac is auto, then grab NIC from VNIC
        if mac == 'auto'
          mac = ''
          cmd = "#{@pfexec} dladm show-vnic #{hvnic_name} | tail -n +2 |  awk '{ print $4 }'"
          vnicmac = execute(false, cmd.to_s)
          vnicmac.split(':').each { |x| mac += "#{format('%02x', x.to_i(16))}:" }
          mac = mac[0..-2]
        end
        uii.info(I18n.t('vagrant_zones.deconfiguring_dhcp'))
        uii.info("  #{hvnic_name}")
        broadcast = IPAddr.new(defrouter).mask(shrtsubnet).to_s
        subnet = %(subnet #{broadcast} netmask #{opts[:netmask]} { option routers #{defrouter}; })
        subnetopts = %(host #{name} { option host-name "#{name}"; hardware ethernet #{mac}; fixed-address #{ip}; })
        File.open('/etc/dhcpd.conf-temp', 'w') do |out_file|
          File.foreach('/etc/dhcpd.conf') do |entry|
            out_file.puts line unless entry == subnet || subnetopts
          end
        end
        FileUtils.mv('/etc/dhcpd.conf-temp', '/etc/dhcpd.conf')
        subawk = '{ $1=""; $2=""; sub(/^[ \\t]+/, ""); print}'
        awk = %(| awk '#{subawk}' | tr ' ' '\\n' | tr -d '"')
        cmd = 'svccfg -s dhcp:ipv4 listprop config/listen_ifnames '
        nicsused = execute(false, cmd + awk.to_s).split("\n")
        newdhcpnics = []
        nicsused.each do |nic|
          newdhcpnics << nic unless nic.to_s == hvnic_name.to_s
        end
        if newdhcpnics.empty?
          dhcpcmdnewstr = '\(\"\"\)'
        else
          dhcpcmdnewstr = '\('
          newdhcpnics.each do |nic|
            dhcpcmdnewstr += %(\\"#{nic}\\")
          end
          dhcpcmdnewstr += '\)'
        end
        execute(false, "#{@pfexec} svccfg -s dhcp:ipv4 setprop config/listen_ifnames = #{dhcpcmdnewstr}")
        execute(false, "#{@pfexec} svcadm refresh dhcp:ipv4")
        execute(false, "#{@pfexec} svcadm disable dhcp:ipv4")
        execute(false, "#{@pfexec} svcadm enable dhcp:ipv4")
      end

      def zonenatclean(uii, opts)
        vnic_name = vname(uii, opts)
        defrouter = opts[:gateway].to_s
        shrtsubnet = IPAddr.new(opts[:netmask].to_s).to_i.to_s(2).count('1').to_s
        broadcast = IPAddr.new(defrouter).mask(shrtsubnet).to_s
        uii.info(I18n.t('vagrant_zones.deconfiguring_nat'))
        uii.info("  #{vnic_name}")
        line1 = %(map #{opts[:bridge]} #{broadcast}/#{shrtsubnet} -> 0/32  portmap tcp/udp auto)
        line2 = %(map #{opts[:bridge]} #{broadcast}/#{shrtsubnet} -> 0/32)
        File.open('/etc/ipf/ipnat.conf-temp', 'w') do |out_file|
          File.foreach('/etc/ipf/ipnat.conf') do |entry|
            out_file.puts line unless entry == line1 || line2
          end
        end
        FileUtils.mv('/etc/ipf/ipnat.conf-temp', '/etc/ipf/ipnat.conf')
        execute(false, "#{@pfexec} svcadm refresh network/ipfilter")
      end

      def zonenicdel(uii, opts)
        vnic_name = vname(uii, opts)
        vnic_configured = execute(false, "#{@pfexec} dladm show-vnic | grep #{vnic_name} | awk '{ print $1 }' ")
        uii.info(I18n.t('vagrant_zones.removing_vnic')) if vnic_configured == vnic_name.to_s
        uii.info("  #{vnic_name}") if vnic_configured == vnic_name.to_s
        execute(false, "#{@pfexec} dladm delete-vnic #{vnic_name}") if vnic_configured == vnic_name.to_s
        uii.info(I18n.t('vagrant_zones.no_removing_vnic')) unless vnic_configured == vnic_name.to_s
      end

      ## Delete etherstubs vnic
      def etherstubdelhvnic(uii, opts)
        config = @machine.provider_config
        hvnic_name = "h_vnic_#{config.partition_id}_#{opts[:nic_number]}"
        vnic_configured = execute(false, "#{@pfexec} dladm show-vnic | grep #{hvnic_name} | awk '{ print $1 }' ")
        uii.info(I18n.t('vagrant_zones.removing_host_vnic')) if vnic_configured == hvnic_name.to_s
        uii.info("  #{hvnic_name}") if vnic_configured == hvnic_name.to_s
        execute(false, "#{@pfexec} ipadm delete-if #{hvnic_name}") if vnic_configured == hvnic_name.to_s
        execute(false, "#{@pfexec} dladm delete-vnic #{hvnic_name}") if vnic_configured == hvnic_name.to_s
        uii.info(I18n.t('vagrant_zones.no_removing_host_vnic')) unless vnic_configured == hvnic_name.to_s
      end

      ## Delete etherstubs
      def etherstubdelete(uii, opts)
        config = @machine.provider_config
        ether_name = "stub_#{config.partition_id}_#{opts[:nic_number]}"
        ether_configured = execute(false, "#{@pfexec} dladm show-etherstub | grep #{ether_name} | awk '{ print $1 }' ")
        uii.info(I18n.t('vagrant_zones.delete_ethervnic')) if ether_configured == ether_name
        uii.info("  #{ether_name}") if ether_configured == ether_name
        uii.info(I18n.t('vagrant_zones.no_delete_ethervnic')) unless ether_configured == ether_name
        execute(false, "#{@pfexec} dladm delete-etherstub #{ether_name}") if ether_configured == ether_name
      end

      ## Create etherstubs for Zones
      def etherstubcreate(uii, opts)
        config = @machine.provider_config
        ether_name = "stub_#{config.partition_id}_#{opts[:nic_number]}"
        ether_configured = execute(false, "#{@pfexec} dladm show-etherstub | grep #{ether_name} | awk '{ print $1 }' ")
        uii.info(I18n.t('vagrant_zones.creating_etherstub')) unless ether_configured == ether_name
        uii.info("  #{ether_name}") unless ether_configured == ether_name
        execute(false, "#{@pfexec} dladm create-etherstub #{ether_name}") unless ether_configured == ether_name
        ether_name
      end

      ## Create ethervnics for Zones
      def zonenatniccreate(uii, opts, etherstub)
        vnic_name = vname(uii, opts)
        mac = macaddress(uii, opts)
        uii.info(I18n.t('vagrant_zones.creating_ethervnic'))
        uii.info("  #{vnic_name}")
        execute(false, "#{@pfexec} dladm create-vnic -l #{etherstub} -m #{mac} #{vnic_name}")
      end

      ## Create Host VNIC on etherstubs for IP for Zones DHCP
      def etherstubcreatehvnic(uii, opts, etherstub)
        config = @machine.provider_config
        defrouter = opts[:gateway].to_s
        shrtsubnet = IPAddr.new(opts[:netmask].to_s).to_i.to_s(2).count('1').to_s
        hvnic_name = "h_vnic_#{config.partition_id}_#{opts[:nic_number]}"
        uii.info(I18n.t('vagrant_zones.creating_etherhostvnic'))
        uii.info("  #{hvnic_name}")
        execute(false, "#{@pfexec} dladm create-vnic -l #{etherstub} #{hvnic_name}")
        execute(false, "#{@pfexec} ipadm create-if #{hvnic_name}")
        execute(false, "#{@pfexec} ipadm create-addr -T static -a local=#{defrouter}/#{shrtsubnet} #{hvnic_name}/v4")
      end

      ## Setup vnics for Zones using nat/dhcp
      def zonenicnatsetup(uii, opts)
        config = @machine.provider_config
        return if config.cloud_init_enabled

        vnic_name = vname(uii, opts)
        mac = macaddress(uii, opts)
        ## if mac is auto, then grab NIC from VNIC
        if mac == 'auto'
          mac = ''
          cmd = "#{@pfexec} dladm show-vnic #{vnic_name} | tail -n +2 |  awk '{ print $4 }'"
          vnicmac = execute(false, cmd.to_s)
          vnicmac.split(':').each { |x| mac += "#{format('%02x', x.to_i(16))}:" }
          mac = mac[0..-2]
        end

        ## Code Block to Detect OS
        uii.info(I18n.t('vagrant_zones.os_detect'))
        cmd = 'uname -a'
        os_type = config.os_type
        uii.info("Zone OS configured as: #{os_type}")
        os_detected = ssh_run_command(uii, cmd.to_s)
        uii.info("Zone OS detected as: #{os_detected}")

        ## Check if Ansible is Installed to enable easier configuration
        uii.info(I18n.t('vagrant_zones.ansible_detect'))
        cmd = 'which ansible > /dev/null 2>&1 ; echo $?'
        ansible_detected = ssh_run_command(uii, cmd.to_s)
        uii.info('Ansible detected') if ansible_detected == '0'

        # Run Network Configuration
        zonenicnatsetup_netplan(uii, opts, mac) unless os_detected.to_s.match(/SunOS/)
        zonenicnatsetup_dladm(uii, opts, mac) if os_detected.to_s.match(/SunOS/)
      end

      ## Setup vnics for Zones using nat/dhcp using netplan
      def zonenicnatsetup_netplan(uii, opts, mac)
        ssh_run_command(uii, 'sudo rm -rf /etc/netplan/*.yaml')
        ip = ipaddress(uii, opts)
        defrouter = opts[:gateway].to_s
        vnic_name = vname(uii, opts)
        shrtsubnet = IPAddr.new(opts[:netmask].to_s).to_i.to_s(2).count('1').to_s
        servers = dnsservers(uii, opts)
        ## Begin of code block to move to Netplan function
        uii.info(I18n.t('vagrant_zones.configure_interface_using_vnic'))
        uii.info("  #{vnic_name}")

        netplan1 = %(network:\n  version: 2\n  ethernets:\n    #{vnic_name}:\n      match:\n        macaddress: #{mac}\n)
        netplan2 = %(      dhcp-identifier: mac\n      dhcp4: #{opts[:dhcp4]}\n      dhcp6: #{opts[:dhcp6]}\n)
        netplan3 = %(      set-name: #{vnic_name}\n      addresses: [#{ip}/#{shrtsubnet}]\n      gateway4: #{defrouter}\n)
        netplan4 = %(      nameservers:\n        addresses: [#{servers[0]['nameserver']} , #{servers[1]['nameserver']}] )
        netplan = netplan1 + netplan2 + netplan3 + netplan4
        cmd = "echo -e '#{netplan}' | sudo tee /etc/netplan/#{vnic_name}.yaml"
        infomessage = I18n.t('vagrant_zones.netplan_applied_static') + "/etc/netplan/#{vnic_name}.yaml"
        uii.info(infomessage) if ssh_run_command(uii, cmd)

        ## Apply the Configuration
        uii.info(I18n.t('vagrant_zones.netplan_applied')) if ssh_run_command(uii, 'sudo netplan apply')
        ## End of code block to move to Netplan function
      end

      ## Setup vnics for Zones using nat/dhcp over dladm
      def zonenicnatsetup_dladm(uii, opts, mac)
        ip = ipaddress(uii, opts)
        defrouter = opts[:gateway].to_s
        vnic_name = vname(uii, opts)
        shrtsubnet = IPAddr.new(opts[:netmask].to_s).to_i.to_s(2).count('1').to_s
        servers = dnsservers(uii, opts)
        uii.info(I18n.t('vagrant_zones.configure_interface_using_vnic_dladm'))
        uii.info("  #{vnic_name}")

        # loop through each phys if and run code if physif matches #{mac}
        phys_if = 'pfexec dladm show-phys -m -o LINK,ADDRESS,CLIENT | tail -n +2'
        phys_if_results = ssh_run_command(uii, phys_if).split("\n")
        device = ''
        phys_if_results.each do |entry|
          e_mac = ''
          entries = entry.strip.split
          entries[1].split(':').each { |x| e_mac += "#{format('%02x', x.to_i(16))}:" }
          e_mac = e_mac[0..-2]
          device = entries[0] if e_mac.match(/#{mac}/)
        end

        delete_if = "pfexec ipadm delete-if #{device}"
        rename_link = "pfexec dladm rename-link #{device} #{vnic_name}"
        if_create = "pfexec ipadm create-if #{vnic_name}"
        static_addr = "pfexec ipadm create-addr -T static -a #{ip}/#{shrtsubnet} #{vnic_name}/v4vagrant"
        net_cmd = "#{delete_if} && #{rename_link} && #{if_create} && #{static_addr}"
        uii.info(I18n.t('vagrant_zones.dladm_applied')) if ssh_run_command(uii, net_cmd)

        route_add = "pfexec route -p add default #{defrouter}"
        uii.info(I18n.t('vagrant_zones.dladm_route_applied')) if ssh_run_command(uii, route_add)

        ns_string = "nameserver #{servers[0]['nameserver']}\nnameserver #{servers[1]['nameserver']}"
        dns_set = "pfexec echo '#{ns_string}' | pfexec tee /etc/resolv.conf"
        uii.info(I18n.t('vagrant_zones.dladm_dns_applied')) if ssh_run_command(uii, dns_set.to_s)
      end

      ## zonecfg function for for nat Networking
      def natnicconfig(uii, opts)
        config = @machine.provider_config
        allowed_address = allowedaddress(uii, opts)
        defrouter = opts[:gateway].to_s
        vnic_name = vname(uii, opts)
        uii.info(I18n.t('vagrant_zones.nat_vnic_setup'))
        uii.info("  #{vnic_name}")
        strt = "#{@pfexec} zonecfg -z #{@machine.name} "
        cie = config.cloud_init_enabled
        case config.brand
        when 'lx'
          shrtstr1 = %(set allowed-address=#{allowed_address}; add property (name=gateway,value="#{defrouter}"); )
          shrtstr2 = %(add property (name=ips,value="#{allowed_address}"); add property (name=primary,value="true"); end;)
          execute(false, %(#{strt}set global-nic=auto; #{shrtstr1} #{shrtstr2}"))
        when 'bhyve'
          execute(false, %(#{strt}"add net; set physical=#{vnic_name}; end;")) unless cie
          execute(false, %(#{strt}"add net; set physical=#{vnic_name}; set allowed-address=#{allowed_address}; end;")) if cie
        end
      end

      ## Set NatForwarding on global interface
      def zonenatforward(uii, opts)
        config = @machine.provider_config
        hvnic_name = "h_vnic_#{config.partition_id}_#{opts[:nic_number]}"
        uii.info(I18n.t('vagrant_zones.forwarding_nat'))
        uii.info("  #{hvnic_name}")
        execute(false, "#{@pfexec} routeadm -u -e ipv4-forwarding")
        execute(false, "#{@pfexec} ipadm set-ifprop -p forwarding=on -m ipv4 #{opts[:bridge]}")
        execute(false, "#{@pfexec} ipadm set-ifprop -p forwarding=on -m ipv4 #{hvnic_name}")
      end

      ## Create nat entries for the zone
      def zonenatentries(uii, opts)
        vnic_name = vname(uii, opts)
        defrouter = opts[:gateway].to_s
        shrtsubnet = IPAddr.new(opts[:netmask].to_s).to_i.to_s(2).count('1').to_s
        uii.info(I18n.t('vagrant_zones.configuring_nat'))
        uii.info("  #{vnic_name}")
        broadcast = IPAddr.new(defrouter).mask(shrtsubnet).to_s
        ## Read NAT File, Check for these lines, if exist, warn, but continue
        natentries = execute(false, "#{@pfexec} cat /etc/ipf/ipnat.conf").split("\n")
        line1 = %(map #{opts[:bridge]} #{broadcast}/#{shrtsubnet} -> 0/32  portmap tcp/udp auto)
        line2 = %(map #{opts[:bridge]} #{broadcast}/#{shrtsubnet} -> 0/32)
        line1exists = false
        line2exists = false
        natentries.each do |entry|
          line1exists = true if entry == line1
          line2exists = true if entry == line2
        end
        execute(false, %(#{@pfexec} echo "#{line1}" | #{@pfexec} tee -a /etc/ipf/ipnat.conf)) unless line1exists
        execute(false, %(#{@pfexec} echo "#{line2}" | #{@pfexec} tee -a /etc/ipf/ipnat.conf)) unless line2exists
        execute(false, "#{@pfexec} svcadm refresh network/ipfilter")
        execute(false, "#{@pfexec} svcadm disable network/ipfilter")
        execute(false, "#{@pfexec} svcadm enable network/ipfilter")
      end

      ## Create dhcp entries for the zone
      def zonedhcpentries(uii, opts)
        config = @machine.provider_config
        ip = ipaddress(uii, opts)
        name = @machine.name
        vnic_name = vname(uii, opts)
        defrouter = opts[:gateway].to_s
        shrtsubnet = IPAddr.new(opts[:netmask].to_s).to_i.to_s(2).count('1').to_s
        hvnic_name = "h_vnic_#{config.partition_id}_#{opts[:nic_number]}"
        ## Set Mac address from VNIC
        mac = macaddress(uii, opts)
        if mac == 'auto'
          mac = ''
          cmd = "#{@pfexec} dladm show-vnic #{vnic_name} | tail -n +2 |  awk '{ print $4 }'"
          vnicmac = execute(false, cmd.to_s)
          vnicmac.split(':').each { |x| mac += "#{format('%02x', x.to_i(16))}:" }
          mac = mac[0..-2]
        end
        uii.info(I18n.t('vagrant_zones.configuring_dhcp'))
        broadcast = IPAddr.new(defrouter).mask(shrtsubnet).to_s
        dhcpentries = execute(false, "#{@pfexec} cat /etc/dhcpd.conf").split("\n")
        subnet = %(subnet #{broadcast} netmask #{opts[:netmask]} { option routers #{defrouter}; })
        subnetopts = %(host #{name} { option host-name "#{name}"; hardware ethernet #{mac}; fixed-address #{ip}; })
        subnetexists = false
        subnetoptsexists = false
        dhcpentries.each do |entry|
          subnetexists = true if entry == subnet
          subnetoptsexists = true if entry == subnetopts
        end
        execute(false, "#{@pfexec} echo '#{subnet}' | #{@pfexec} tee -a /etc/dhcpd.conf") unless subnetexists
        execute(false, "#{@pfexec} echo '#{subnetopts}' | #{@pfexec} tee -a /etc/dhcpd.conf") unless subnetoptsexists
        execute(false, "#{@pfexec} svccfg -s dhcp:ipv4 setprop config/listen_ifnames = #{hvnic_name}")
        execute(false, "#{@pfexec} svcadm refresh dhcp:ipv4")
        execute(false, "#{@pfexec} svcadm disable dhcp:ipv4")
        execute(false, "#{@pfexec} svcadm enable dhcp:ipv4")
      end

      ## Check if Address shows up in lease list /var/db/dhcpd ping address after
      def zonedhcpcheckaddr(uii, opts)
        # vnic_name = vname(uii, opts)
        # ip = ipaddress(uii, opts)
        uii.info(I18n.t('vagrant_zones.chk_dhcp_addr'))
        uii.info("  #{opts[:ip]}")
        # execute(false, "#{@pfexec} ping #{ip} ")
      end

      ## Create vnics for Zones
      def zoneniccreate(uii, opts)
        mac = macaddress(uii, opts)
        vnic_name = vname(uii, opts)
        if opts[:vlan].nil?
          uii.info(I18n.t('vagrant_zones.creating_vnic'))
          uii.info("  #{vnic_name}")
          execute(false, "#{@pfexec} dladm create-vnic -l #{opts[:bridge]} -m #{mac} #{vnic_name}")
        else
          vlan = opts[:vlan]
          uii.info(I18n.t('vagrant_zones.creating_vnic'))
          uii.info("  #{vnic_name}")
          execute(false, "#{@pfexec} dladm create-vnic -l #{opts[:bridge]} -m #{mac} -v #{vlan} #{vnic_name}")
        end
      end

      # This helps us create all the datasets for the zone
      def create_dataset(uii)
        config = @machine.provider_config
        name = @machine.name
        bootconfigs = config.boot
        datasetpath = "#{bootconfigs['array']}/#{bootconfigs['dataset']}/#{name}"
        datasetroot = "#{datasetpath}/#{bootconfigs['volume_name']}"
        sparse = '-s '
        sparse = '' unless bootconfigs['sparse']
        refres = "-o refreservation=#{bootconfigs['refreservation']}" unless bootconfigs['refreservation'].nil?
        refres = '-o refreservation=none' if bootconfigs['refreservation'] == 'none' || bootconfigs['refreservation'].nil?
        uii.info(I18n.t('vagrant_zones.begin_create_datasets'))
        ## Create Boot Volume
        case config.brand
        when 'lx'
          uii.info(I18n.t('vagrant_zones.lx_zone_dataset'))
          uii.info("  #{datasetroot}")
          execute(false, "#{@pfexec} zfs create -o zoned=on -p #{datasetroot}")
        when 'bhyve'
          ## Create root dataset
          uii.info(I18n.t('vagrant_zones.bhyve_zone_dataset_root'))
          uii.info("  #{datasetpath}")
          execute(false, "#{@pfexec} zfs create #{datasetpath}")

          # Create boot volume
          cinfo = "#{datasetroot}, #{bootconfigs['size']}"
          uii.info(I18n.t('vagrant_zones.bhyve_zone_dataset_boot'))
          uii.info("  #{cinfo}")
          execute(false, "#{@pfexec} zfs create #{sparse} #{refres} -V #{bootconfigs['size']} #{datasetroot}")

          ## Import template to boot volume
          commandtransfer = "#{@pfexec} pv -n #{@machine.box.directory.join('box.zss')} | #{@pfexec} zfs recv -u -v -F #{datasetroot}"
          uii.info(I18n.t('vagrant_zones.template_import_path'))
          uii.info("  #{@machine.box.directory.join('box.zss')}")
          Util::Subprocess.new commandtransfer do |_stdout, stderr, _thread|
            uii.rewriting do |uiprogress|
              uiprogress.clear_line
              uiprogress.info(I18n.t('vagrant_zones.importing_box_image_to_disk') + "#{datasetroot} ", new_line: false)
              uiprogress.report_progress(stderr, 100, false)
            end
          end
          uii.clear_line

          uii.info(I18n.t('vagrant_zones.template_import_path_set_size'))
          execute(false, "#{@pfexec} zfs set volsize=#{bootconfigs['size']} #{datasetroot}")

        when 'illumos' || 'kvm'
          raise Errors::NotYetImplemented
        else
          raise Errors::InvalidBrand
        end
        ## Create Additional Disks
        return if config.additional_disks.nil?

        config.additional_disks.each do |disk|
          shrtpath = "#{disk['array']}/#{disk['dataset']}/#{name}"
          dataset = "#{shrtpath}/#{disk['volume_name']}"
          sparse = '-s '
          sparse = '' unless disk['sparse']
          refres = "-o refreservation=#{bootconfigs['refreservation']}" unless bootconfigs['refreservation'].nil?
          refres = '-o refreservation=none' if bootconfigs['refreservation'] == 'none' || bootconfigs['refreservation'].nil?
          ## If the root data set doesn't exist create it
          addsrtexists = execute(false, "#{@pfexec} zfs list | grep #{shrtpath} | awk '{ print $1 }' | head -n 1 || true")
          cinfo = shrtpath.to_s
          uii.info(I18n.t('vagrant_zones.bhyve_zone_dataset_additional_volume_root')) unless addsrtexists == shrtpath.to_s
          uii.info("  #{cinfo}") unless addsrtexists == shrtpath.to_s
          ## Create the Additional volume
          execute(false, "#{@pfexec} zfs create #{shrtpath}") unless addsrtexists == shrtpath.to_s
          cinfo = "#{dataset}, #{disk['size']}"
          uii.info(I18n.t('vagrant_zones.bhyve_zone_dataset_additional_volume'))
          uii.info("  #{cinfo}")
          execute(false, "#{@pfexec} zfs create #{sparse} #{refres} -V #{disk['size']} #{dataset}")
        end
      end

      # This helps us delete any associated datasets of the zone
      ## Future To-Do: Should probably split this up and clean it up
      def delete_dataset(uii)
        config = @machine.provider_config
        name = @machine.name
        # datadir = machine.data_dir
        bootconfigs = config.boot
        datasetpath = "#{bootconfigs['array']}/#{bootconfigs['dataset']}/#{name}"
        datasetroot = "#{datasetpath}/#{bootconfigs['volume_name']}"
        uii.info(I18n.t('vagrant_zones.delete_disks'))

        ## Check if Boot Dataset exists
        zp = datasetpath.delete_prefix('/').to_s
        dataset_boot_exists = execute(false, "#{@pfexec} zfs list | grep #{datasetroot} | awk '{ print $1 }' || true")

        ## Destroy Boot dataset
        uii.info(I18n.t('vagrant_zones.destroy_dataset')) if dataset_boot_exists == datasetroot.to_s
        uii.info("  #{datasetroot}") if dataset_boot_exists == datasetroot.to_s
        execute(false, "#{@pfexec} zfs destroy -r #{datasetroot}") if dataset_boot_exists == datasetroot.to_s
        ## Insert Error Checking Here in case disk is busy
        uii.info(I18n.t('vagrant_zones.boot_dataset_nil')) unless dataset_boot_exists == datasetroot.to_s

        ## Destroy Additional Disks
        unless config.additional_disks.nil?
          disks = config.additional_disks
          disks.each do |disk|
            diskpath = "#{disk['array']}/#{disk['dataset']}/#{name}"
            addataset = "#{diskpath}/#{disk['volume_name']}"
            cinfo = addataset.to_s
            dataset_exists = execute(false, "#{@pfexec} zfs list | grep #{addataset} | awk '{ print $1 }' || true")
            uii.info(I18n.t('vagrant_zones.bhyve_zone_dataset_additional_volume_destroy')) if dataset_exists == addataset
            uii.info("  #{cinfo}") if dataset_exists == addataset
            execute(false, "#{@pfexec} zfs destroy -r #{addataset}") if dataset_exists == addataset
            uii.info(I18n.t('vagrant_zones.additional_dataset_nil')) unless dataset_exists == addataset
            cinfo = diskpath.to_s
            addsrtexists = execute(false, "#{@pfexec} zfs list | grep #{diskpath} | awk '{ print $1 }' | head -n 1 || true")
            uii.info(I18n.t('vagrant_zones.addtl_volume_destroy_root')) if addsrtexists == diskpath && addsrtexists != zp.to_s
            uii.info("  #{cinfo}") if addsrtexists == diskpath && addsrtexists != zp.to_s
            execute(false, "#{@pfexec} zfs destroy -r #{diskpath}") if addsrtexists == diskpath && addsrtexists != zp.to_s
          end
        end

        ## Check if root dataset exists
        dataset_root_exists = execute(false, "#{@pfexec} zfs list | grep #{zp} | awk '{ print $1 }' | grep -v path || true")
        uii.info(I18n.t('vagrant_zones.destroy_root_dataset')) if dataset_root_exists == zp.to_s
        uii.info("  #{zp}") if dataset_root_exists == zp.to_s
        execute(false, "#{@pfexec} zfs destroy -r #{zp}") if dataset_root_exists == zp.to_s
        uii.info(I18n.t('vagrant_zones.root_dataset_nil')) unless dataset_root_exists == zp.to_s
      end

      ## zonecfg function for bhyve
      def zonecfgbhyve(uii, name, config, zcfg)
        return unless config.brand == 'bhyve'

        bootconfigs = config.boot
        datasetpath = "#{bootconfigs['array']}/#{bootconfigs['dataset']}/#{name}"
        datasetroot = "#{datasetpath}/#{bootconfigs['volume_name']}"
        execute(false, %(#{zcfg}"create ; set zonepath=/#{datasetpath}/path"))
        execute(false, %(#{zcfg}"set brand=#{config.brand}"))
        execute(false, %(#{zcfg}"set autoboot=#{config.autoboot}"))
        execute(false, %(#{zcfg}"set ip-type=exclusive"))
        execute(false, %(#{zcfg}"add attr; set name=acpi; set value=#{config.acpi}; set type=string; end;"))
        execute(false, %(#{zcfg}"add attr; set name=ram; set value=#{config.memory}; set type=string; end;"))
        execute(false, %(#{zcfg}"add attr; set name=bootrom; set value=#{firmware(uii)}; set type=string; end;"))
        execute(false, %(#{zcfg}"add attr; set name=hostbridge; set value=#{config.hostbridge}; set type=string; end;"))
        execute(false, %(#{zcfg}"add attr; set name=diskif; set value=#{config.diskif}; set type=string; end;"))
        execute(false, %(#{zcfg}"add attr; set name=netif; set value=#{config.netif}; set type=string; end;"))
        execute(false, %(#{zcfg}"add attr; set name=bootdisk; set value=#{datasetroot.delete_prefix('/')}; set type=string; end;"))
        execute(false, %(#{zcfg}"add attr; set name=type; set value=#{config.os_type}; set type=string; end;"))
        execute(false, %(#{zcfg}"add attr; set name=xhci; set value=#{config.xhci_enabled}; set type=string; end;"))
        execute(false, %(#{zcfg}"add device; set match=/dev/zvol/rdsk/#{datasetroot}; end;"))
        uii.info(I18n.t('vagrant_zones.bhyve_zone_config_gen'))
      end

      ## zonecfg function for lx
      def zonecfglx(uii, name, config, zcfg)
        return unless config.brand == 'lx'

        datasetpath = "#{config.boot['array']}/#{config.boot['dataset']}/#{name}"
        datasetroot = "#{datasetpath}/#{config.boot['volume_name']}"
        uii.info(I18n.t('vagrant_zones.lx_zone_config_gen'))
        @machine.config.vm.networks.each do |adaptertype, opts|
          next unless adaptertype.to_s == 'public_network'

          @ip = opts[:ip].to_s
          cinfo = "#{opts[:ip]}/#{opts[:netmask]}"
          @network = NetAddr.parse_net(cinfo)
          @defrouter = opts[:gateway]
        end
        execute(false, %(#{zcfg}"create ; set zonepath=/#{datasetpath}/path"))
        execute(false, %(#{zcfg}"set brand=#{config.brand}"))
        execute(false, %(#{zcfg}"set autoboot=#{config.autoboot}"))
        execute(false, %(#{zcfg}"add attr; set name=kernel-version; set value=#{config.kernel}; set type=string; end;"))
        cmss = ' add capped-memory; set physical='
        execute(false, %(#{zcfg + cmss}"#{config.memory}; set swap=#{config.kernel}; set locked=#{config.memory}; end;"))
        execute(false, %(#{zcfg}"add dataset; set name=#{datasetroot}; end;"))
        execute(false, %(#{zcfg}"set max-lwps=2000"))
      end

      ## zonecfg function for KVM
      def zonecfgkvm(uii, name, config, _zcfg)
        return unless config.brand == 'kvm'

        bootconfigs = config.boot
        config = @machine.provider_config
        datasetpath = "#{bootconfigs['array']}/#{bootconfigs['dataset']}/#{name}"
        datasetroot = "#{datasetpath}/#{bootconfigs['volume_name']}"
        uii.info(datasetroot) if config.debug
        ###### RESERVED ######
      end

      ## zonecfg function for Shared Disk Configurations
      def zonecfgshareddisks(uii, _name, config, zcfg)
        return unless config.shared_disk_enabled

        uii.info(I18n.t('vagrant_zones.setting_alt_shared_disk_configurations') + path.path)
        execute(false, %(#{zcfg}"add fs; set dir=/vagrant; set special=#{config.shared_dir}; set type=lofs; end;"))
      end

      ## zonecfg function for CPU Configurations
      def zonecfgcpu(uii, _name, config, zcfg)
        uii.info(I18n.t('vagrant_zones.zonecfgcpu')) if config.debug
        if config.cpu_configuration == 'simple' && (config.brand == 'bhyve' || config.brand == 'kvm')
          execute(false, %(#{zcfg}"add attr; set name=vcpus; set value=#{config.cpus}; set type=string; end;"))
        elsif config.cpu_configuration == 'complex' && (config.brand == 'bhyve' || config.brand == 'kvm')
          hash = config.complex_cpu_conf[0]
          cstring = %(sockets=#{hash['sockets']},cores=#{hash['cores']},threads=#{hash['threads']})
          execute(false, %(#{zcfg}'add attr; set name=vcpus; set value="#{cstring}"; set type=string; end;'))
        end
      end

      ## zonecfg function for CDROM Configurations
      def zonecfgcdrom(uii, _name, config, zcfg)
        return if config.cdroms.nil?

        cdroms = config.cdroms
        cdrun = 0
        cdroms.each do |cdrom|
          cdname = 'cdrom'
          uii.info(I18n.t('vagrant_zones.setting_cd_rom_configurations'))
          uii.info("  #{cdrom['path']}")
          cdname += cdrun.to_s if cdrun.positive?
          cdrun += 1
          shrtstrng = 'set type=lofs; add options nodevices; add options ro; end;'
          execute(false, %(#{zcfg}"add attr; set name=#{cdname}; set value=#{cdrom['path']}; set type=string; end;"))
          execute(false, %(#{zcfg}"add fs; set dir=#{cdrom['path']}; set special=#{cdrom['path']}; #{shrtstrng}"))
        end
      end

      ## zonecfg function for PCI Configurations
      def zonecfgpci(uii, _name, config, _zcfg)
        return if config.debug

        uii.info(I18n.t('vagrant_zones.pci')) if config.debug
        ##### RESERVED
      end

      ## zonecfg function for AdditionalDisks
      def zonecfgadditionaldisks(uii, name, config, zcfg)
        return if config.additional_disks.nil?

        diskrun = 0
        config.additional_disks.each do |disk|
          diskname = 'disk'
          dset = "#{disk['array']}/#{disk['dataset']}/#{name}/#{disk['volume_name']}"
          cinfo = "#{dset}, #{disk['size']}"
          uii.info(I18n.t('vagrant_zones.setting_additional_disks_configurations'))
          uii.info("  #{cinfo}")
          diskname += diskrun.to_s if diskrun.positive?
          diskrun += 1
          execute(false, %(#{zcfg}"add device; set match=/dev/zvol/rdsk/#{dset}; end;"))
          execute(false, %(#{zcfg}"add attr; set name=#{diskname}; set value=#{dset}; set type=string; end;"))
        end
      end

      ## zonecfg function for Console Access
      def zonecfgconsole(uii, _name, config, zcfg)
        return if config.console.nil? || config.console == 'disabled'

        port = if %w[console].include?(config.console) && config.consoleport.nil?
                 'socket,/tmp/vm.com1'
               elsif %w[webvnc].include?(config.console) || %w[vnc].include?(config.console)
                 config.console = 'vnc'
                 'on'
               else
                 config.consoleport
               end
        port += ',wait' if config.console_onboot
        cp = config.consoleport
        ch = config.consolehost
        cb = config.console_onboot
        ct = config.console
        cinfo = "Console type: #{ct}, State: #{port}, Port: #{cp},  Host: #{ch}, Wait: #{cb}"
        uii.info(I18n.t('vagrant_zones.setting_console_access'))
        uii.info("  #{cinfo}")
        execute(false, %(#{zcfg}"add attr; set name=#{ct}; set value=#{port}; set type=string; end;"))
      end

      ## zonecfg function for Cloud-init
      def zonecfgcloudinit(uii, _name, config, zcfg)
        return unless config.cloud_init_enabled

        cloudconfig = 'on' if config.cloud_init_conf.nil?
        cloudconfig = config.cloud_init_conf.to_s unless config.cloud_init_conf.nil?

        uii.info(I18n.t('vagrant_zones.setting_cloud_init_access'))
        execute(false, %(#{zcfg}"add attr; set name=cloud-init; set value=#{cloudconfig}; set type=string; end;"))

        ccid = config.cloud_init_dnsdomain
        uii.info(I18n.t('vagrant_zones.setting_cloud_dnsdomain')) unless ccid.nil?
        uii.info("  #{ccid}") unless ccid.nil?
        execute(false, %(#{zcfg}"add attr; set name=dns-domain; set value=#{ccid}; set type=string; end;")) unless ccid.nil?

        ccip = config.cloud_init_password
        uii.info(I18n.t('vagrant_zones.setting_cloud_password')) unless ccip.nil?
        uii.info("  #{ccip}") unless ccip.nil?
        execute(false, %(#{zcfg}"add attr; set name=password; set value=#{ccip}; set type=string; end;")) unless ccip.nil?

        cclir = config.dns
        dservers = []
        cclir['dns'].each do |ns|
          dservers.append(ns['nameserver'])
        end
        uii.info(I18n.t('vagrant_zones.setting_cloud_resolvers')) unless dservers.nil?
        uii.info("  #{dservers}") unless dservers.nil?
        execute(false, %(#{zcfg}"add attr; set name=resolvers; set value=#{dservers}; set type=string; end;")) unless dservers.nil?

        ccisk = config.cloud_init_sshkey
        uii.info(I18n.t('vagrant_zones.setting_cloud_ssh_key')) unless ccisk.nil?
        uii.info("  #{ccisk}") unless ccisk.nil?
        execute(false, %(#{zcfg}"add attr; set name=sshkey; set value=#{ccisk}; set type=string; end;")) unless ccisk.nil?
      end

      ## zonecfg function for for Networking
      def zonecfgnicconfig(uii, opts)
        allowed_address = allowedaddress(uii, opts)
        defrouter = opts[:gateway].to_s
        vnic_name = vname(uii, opts)
        config = @machine.provider_config
        uii.info(I18n.t('vagrant_zones.vnic_setup'))
        uii.info("  #{vnic_name}")
        strt = "#{@pfexec} zonecfg -z #{@machine.name} "
        cie = config.cloud_init_enabled
        aa = config.allowed_address
        case config.brand
        when 'lx'
          shrtstr1 = %(set allowed-address=#{allowed_address}; add property (name=gateway,value="#{defrouter}"); )
          shrtstr2 = %(add property (name=ips,value="#{allowed_address}"); add property (name=primary,value="true"); end;)
          execute(false, %(#{strt}set global-nic=auto; #{shrtstr1} #{shrtstr2}"))
        when 'bhyve'
          execute(false, %(#{strt}"add net; set physical=#{vnic_name}; end;")) unless cie
          execute(false, %(#{strt}"add net; set physical=#{vnic_name}; set allowed-address=#{allowed_address}; end;")) if cie && aa
          execute(false, %(#{strt}"add net; set physical=#{vnic_name}; end;")) if cie && !aa
        end
      end

      # This helps us set the zone configurations for the zone
      def zonecfg(uii)
        name = @machine.name
        config = @machine.provider_config
        zcfg = "#{@pfexec} zonecfg -z #{name} "
        ## Create LX zonecfg
        zonecfglx(uii, name, config, zcfg)
        ## Create bhyve zonecfg
        zonecfgbhyve(uii, name, config, zcfg)
        ## Create kvm zonecfg
        zonecfgkvm(uii, name, config, zcfg)
        ## Shared Disk Configurations
        zonecfgshareddisks(uii, name, config, zcfg)
        ## CPU Configurations
        zonecfgcpu(uii, name, config, zcfg)
        ## CDROM Configurations
        zonecfgcdrom(uii, name, config, zcfg)
        ### Passthrough PCI Devices
        zonecfgpci(uii, name, config, zcfg)
        ## Additional Disk Configurations
        zonecfgadditionaldisks(uii, name, config, zcfg)
        ## Console access configuration
        zonecfgconsole(uii, name, config, zcfg)
        ## Cloud-init settings
        zonecfgcloudinit(uii, name, config, zcfg)
        ## Nic Configurations
        network(uii, 'config')
      end

      ## Setup vnics for Zones using Zlogin
      def zonenicstpzloginsetup(uii, opts, config)
        vnic_name = vname(uii, opts)
        mac = macaddress(uii, opts)
        ## if mac is auto, then grab NIC from VNIC
        if mac == 'auto'
          mac = ''
          cmd = "#{@pfexec} dladm show-vnic #{vnic_name} | tail -n +2 |  awk '{ print $4 }'"
          vnicmac = execute(false, cmd.to_s)
          vnicmac.split(':').each { |x| mac += "#{format('%02x', x.to_i(16))}:" }
          mac = mac[0..-2]
        end

        zoneniczloginsetup_windows(uii, opts, mac) if config.os_type.to_s.match(/windows/)
        zoneniczloginsetup_netplan(uii, opts, mac) unless config.os_type.to_s.match(/windows/)
      end

      ## This setups the Netplan based OS Networking via Zlogin
      def zoneniczloginsetup_netplan(uii, opts, mac)
        zlogin(uii, 'rm -rf /etc/netplan/*.yaml')
        ip = ipaddress(uii, opts)
        vnic_name = vname(uii, opts)
        servers = dnsservers(uii, opts)
        shrtsubnet = IPAddr.new(opts[:netmask].to_s).to_i.to_s(2).count('1').to_s
        defrouter = opts[:gateway].to_s
        uii.info(I18n.t('vagrant_zones.configure_interface_using_vnic'))
        uii.info("  #{vnic_name}")
        netplan1 = %(network:\n  version: 2\n  ethernets:\n    #{vnic_name}:\n      match:\n        macaddress: #{mac}\n)
        netplan2 = %(      dhcp-identifier: mac\n      dhcp4: #{opts[:dhcp4]}\n      dhcp6: #{opts[:dhcp6]}\n)
        netplan3 = %(      set-name: #{vnic_name}\n      addresses: [#{ip}/#{shrtsubnet}]\n      gateway4: #{defrouter}\n)
        netplan4 = %(      nameservers:\n        addresses: [#{servers[0]['nameserver']} , #{servers[1]['nameserver']}] )
        netplan = netplan1 + netplan2 + netplan3 + netplan4
        cmd = "echo '#{netplan}' > /etc/netplan/#{vnic_name}.yaml"
        infomessage = I18n.t('vagrant_zones.netplan_applied_static') + "/etc/netplan/#{vnic_name}.yaml"
        uii.info(infomessage) if zlogin(uii, cmd)
        ## Apply the Configuration
        uii.info(I18n.t('vagrant_zones.netplan_applied')) if zlogin(uii, 'netplan apply')
      end

      # This ensures the zone is safe to boot
      def check_zone_support(uii)
        uii.info(I18n.t('vagrant_zones.preflight_checks'))
        config = @machine.provider_config
        ## Detect if Virtualbox is Running
        ## LX, KVM, and Bhyve cannot run conncurently with Virtualbox:
        ### https://illumos.topicbox-beta.com/groups/omnios-discuss/Tce3bbd08cace5349-M5fc864e9c1a7585b94a7c080
        uii.info(I18n.t('vagrant_zones.vbox_run_check'))
        result = execute(true, "#{@pfexec} VBoxManage list runningvms")
        raise Errors::VirtualBoxRunningConflictDetected if result.zero?

        ## https://man.omnios.org/man5/brands
        case config.brand
        when 'lx'
          uii.info(I18n.t('vagrant_zones.lx_check'))
        when 'ipkg'
          uii.info(I18n.t('vagrant_zones.ipkg_check'))
        when 'lipkg'
          uii.info(I18n.t('vagrant_zones.lipkg_check'))
        when 'pkgsrc'
          uii.info(I18n.t('vagrant_zones.pkgsrc_check'))
        when 'sparse'
          uii.info(I18n.t('vagrant_zones.sparse_check'))
        when 'kvm'
          ## https://man.omnios.org/man5/kvm
          uii.info(I18n.t('vagrant_zones.kvm_check'))
        when 'illumos'
          uii.info(I18n.t('vagrant_zones.illumos_check'))
        when 'bhyve'
          ## https://man.omnios.org/man5/bhyve
          ## Check for bhhwcompat
          result = execute(true, "#{@pfexec} test -f /usr/sbin/bhhwcompat ; echo $?")
          if result == 1
            bhhwcompaturl = 'https://downloads.omnios.org/misc/bhyve/bhhwcompat'
            execute(true, "#{@pfexec} curl -o /usr/sbin/bhhwcompat #{bhhwcompaturl} && #{@pfexec} chmod +x /usr/sbin/bhhwcompat")
            result = execute(true, "#{@pfexec} test -f /usr/sbin/bhhwcompat ; echo $?")
            raise Errors::MissingCompatCheckTool if result.zero?
          end

          # Check whether OmniOS version is lower than r30
          cutoff_release = '1510380'
          cutoff_release = cutoff_release[0..-2].to_i
          uii.info(I18n.t('vagrant_zones.bhyve_check'))
          uii.info("  #{cutoff_release}")
          release = File.open('/etc/release', &:readline)
          release = release.scan(/\w+/).values_at(-1)
          release = release[0][1..-2].to_i
          raise Errors::SystemVersionIsTooLow if release < cutoff_release

          # Check Bhyve compatability
          uii.info(I18n.t('vagrant_zones.bhyve_compat_check'))
          result = execute(false, "#{@pfexec} bhhwcompat -s")
          raise Errors::MissingBhyve if result.length == 1
        end
      end

      # This helps us set up the networking of the VM
      def setup(uii)
        config = @machine.provider_config
        uii.info(I18n.t('vagrant_zones.network_setup')) if config.brand && !config.cloud_init_enabled
        network(uii, 'setup') if config.brand == 'bhyve' && !config.cloud_init_enabled
      end

      ## this allows us a terminal to pass commands and manipulate the VM OS via serial/tty, I want to redo this at some point
      def zloginboot(uii)
        name = @machine.name
        config = @machine.provider_config
        lcheck = config.lcheck
        lcheck = ':~' if config.lcheck.nil?
        alcheck = config.alcheck
        alcheck = 'login:' if config.alcheck.nil?
        bstring = ' OK ' if config.booted_string.nil?
        bstring = config.booted_string unless config.booted_string.nil?
        zunlockboot = 'Importing ZFS root pool'
        zunlockboot = config.zunlockboot unless config.zunlockboot.nil?
        zunlockbootkey = config.zunlockbootkey unless config.zunlockbootkey.nil?
        pcheck = 'Password:'
        uii.info(I18n.t('vagrant_zones.automated-zlogin'))
        PTY.spawn("pfexec zlogin -C #{name}") do |zlogin_read, zlogin_write, pid|
          Timeout.timeout(config.setup_wait) do
            rsp = []

            loop do
              zlogin_read.expect(/\r\n/) { |line| rsp.push line }
              uii.info(rsp[-1]) if config.debug_boot
              sleep(2) if rsp[-1].to_s.match(/#{zunlockboot}/)
              zlogin_write.printf("#{zunlockbootkey}\n") if rsp[-1].to_s.match(/#{zunlockboot}/)
              zlogin_write.printf("\n") if rsp[-1].to_s.match(/#{zunlockboot}/)
              uii.info(I18n.t('vagrant_zones.automated-zbootunlock')) if rsp[-1].to_s.match(/#{zunlockboot}/)
              sleep(15) if rsp[-1].to_s.match(/#{bstring}/)
              zlogin_write.printf("\n") if rsp[-1].to_s.match(/#{bstring}/)
              break if rsp[-1].to_s.match(/#{bstring}/)
            end

            if zlogin_read.expect(/#{alcheck}/)
              uii.info(I18n.t('vagrant_zones.automated-zlogin-user'))
              zlogin_write.printf("#{user(@machine)}\n")
              sleep(config.login_wait)
            end

            if zlogin_read.expect(/#{pcheck}/)
              uii.info(I18n.t('vagrant_zones.automated-zlogin-pass'))
              zlogin_write.printf("#{vagrantuserpass(@machine)}\n")
              sleep(config.login_wait)
            end

            zlogin_write.printf("\n")
            if zlogin_read.expect(/#{lcheck}/)
              uii.info(I18n.t('vagrant_zones.automated-zlogin-root'))
              zlogin_write.printf("sudo su\n")
              sleep(config.login_wait)
              Process.kill('HUP', pid)
            end
          end
        end
      end

      def natloginboot(uii, metrics, interrupted)
        metrics ||= {}
        metrics['instance_dhcp_ssh_time'] = Util::Timer.time do
          retryable(on: Errors::TimeoutError, tries: 60) do
            # If we're interrupted don't worry about waiting
            next if interrupted

            loop do
              break if interrupted
              break if @machine.communicate.ready?
            end
          end
        end
        uii.info(I18n.t('vagrant_zones.dhcp_boot_ready') + " in #{metrics['instance_dhcp_ssh_time']} Seconds")
      end

      # This helps up wait for the boot of the vm by using zlogin
      def waitforboot(uii, metrics, interrupted)
        config = @machine.provider_config
        uii.info(I18n.t('vagrant_zones.wait_for_boot'))
        case config.brand
        when 'bhyve'
          return if config.cloud_init_enabled

          zloginboot(uii) if config.setup_method == 'zlogin' && !config.os_type.to_s.match(/windows/)
          zlogin_win_boot(uii) if config.setup_method == 'zlogin' && config.os_type.to_s.match(/windows/)
          natloginboot(uii, metrics, interrupted) if config.setup_method == 'dhcp'
        when 'lx'
          unless user_exists?(uii, config.vagrant_user)
            # zlogincommand(uii, %('echo nameserver 1.1.1.1 >> /etc/resolv.conf'))
            # zlogincommand(uii, %('echo nameserver 1.0.0.1 >> /etc/resolv.conf'))
            zlogincommand(uii, 'useradd -m -s /bin/bash -U vagrant')
            zlogincommand(uii, 'echo "vagrant ALL=(ALL:ALL) NOPASSWD:ALL" \\> /etc/sudoers.d/vagrant')
            zlogincommand(uii, 'mkdir -p /home/vagrant/.ssh')
            key_url = 'https://raw.githubusercontent.com/hashicorp/vagrant/master/keys/vagrant.pub'
            zlogincommand(uii, "curl #{key_url} -O /home/vagrant/.ssh/authorized_keys")

            id_rsa = 'https://raw.githubusercontent.com/hashicorp/vagrant/master/keys/vagrant'
            command = "#{@pfexec} curl #{id_rsa} -O id_rsa"
            Util::Subprocess.new command do |_stdout, stderr, _thread|
              uii.rewriting do |uisp|
                uisp.clear_line
                uisp.info(I18n.t('vagrant_zones.importing_vagrant_key'), new_line: false)
                uisp.report_progress(stderr, 100, false)
              end
            end
            uii.clear_line
            zlogincommand(uii, 'chown -R vagrant:vagrant /home/vagrant/.ssh')
            zlogincommand(uii, 'chmod 600 /home/vagrant/.ssh/authorized_keys')
          end
        end
      end

      ## This setups the Windows Networking via Zlogin
      def zoneniczloginsetup_windows(uii, opts, _mac)
        ip = ipaddress(uii, opts)
        vnic_name = vname(uii, opts)
        servers = dnsservers(uii, opts)
        defrouter = opts[:gateway].to_s
        uii.info(I18n.t('vagrant_zones.configure_win_interface_using_vnic'))
        sleep(60)

        ## Insert code to get the list of interfaces by mac address in order
        ## to set the proper VNIC name if using multiple adapters
        rename_adapter = %(netsh interface set interface name = "Ethernet" newname = "#{vnic_name}")
        cmd = %(netsh interface ipv4 set address name="#{vnic_name}" static #{ip} #{opts[:netmask]} #{defrouter})
        dns1 = %(netsh int ipv4 set dns name="#{vnic_name}" static #{servers[0]['nameserver']} primary validate=no)
        dns2 = %(netsh int ipv4 add dns name="#{vnic_name}" #{servers[1]['nameserver']} index=2 validate=no)

        uii.info(I18n.t('vagrant_zones.win_applied_rename_adapter')) if zlogin(uii, rename_adapter)
        uii.info(I18n.t('vagrant_zones.win_applied_static')) if zlogin(uii, cmd)
        uii.info(I18n.t('vagrant_zones.win_applied_dns1')) if zlogin(uii, dns1)
        uii.info(I18n.t('vagrant_zones.win_applied_dns2')) if zlogin(uii, dns2)
      end

      def zlogin_win_boot(uii)
        ## use Windows SAC to setup networking
        name = @machine.name
        config = @machine.provider_config
        event_cmd_available = 'EVENT: The CMD command is now available'
        event_channel_created = 'EVENT:   A new channel has been created'
        channel_access_prompt = 'Use any other key to view this channel'
        cmd = 'system32>'
        uii.info(I18n.t('vagrant_zones.automated-windows-zlogin'))
        PTY.spawn("pfexec zlogin -C #{name}") do |zlogin_read, zlogin_write, pid|
          Timeout.timeout(config.setup_wait) do
            uii.info(I18n.t('vagrant_zones.windows_skip_first_boot')) if zlogin_read.expect(/#{event_cmd_available}/)
            sleep(3)
            if zlogin_read.expect(/#{event_cmd_available}/)
              uii.info(I18n.t('vagrant_zones.windows_start_cmd'))
              zlogin_write.printf("cmd\n")
            end
            if zlogin_read.expect(/#{event_channel_created}/)
              uii.info(I18n.t('vagrant_zones.windows_access_session'))
              zlogin_write.printf("\e\t")
            end
            if zlogin_read.expect(/#{channel_access_prompt}/)
              uii.info(I18n.t('vagrant_zones.windows_access_session_presskey'))
              zlogin_write.printf('o')
            end
            if zlogin_read.expect(/Username:/)
              uii.info(I18n.t('vagrant_zones.windows_enter_username'))
              zlogin_write.printf("#{user(@machine)}\n")
            end
            if zlogin_read.expect(/Domain/)
              uii.info(I18n.t('vagrant_zones.windows_enter_domain'))
              zlogin_write.printf("\n")
            end
            if zlogin_read.expect(/Password/)
              uii.info(I18n.t('vagrant_zones.windows_enter_password'))
              zlogin_write.printf("#{vagrantuserpass(@machine)}\n")
            end
            if zlogin_read.expect(/#{cmd}/)
              uii.info(I18n.t('vagrant_zones.windows_cmd_accessible'))
              sleep(5)
              Process.kill('HUP', pid)
            end
          end
        end
      end

      # This gives us a console to the VM to issue commands
      def zlogin(uii, cmd)
        name = @machine.name
        config = @machine.provider_config
        rsp = []
        PTY.spawn("pfexec zlogin -C #{name}") do |zread, zwrite, pid|
          Timeout.timeout(config.setup_wait) do
            error_check = "echo \"Error Code: $?\"\n"
            error_check = "echo Error Code: %%ERRORLEVEL%% \r\n\r\n" if config.os_type.to_s.match(/windows/)
            runonce = true
            loop do
              zread.expect(/\n/) { |line| rsp.push line }
              puts(rsp[-1].to_s) if config.debug
              zwrite.printf("#{cmd}\r\n") if runonce
              zwrite.printf(error_check.to_s) if runonce
              runonce = false
              break if rsp[-1].to_s.match(/Error Code: 0/)

              em = "#{cmd} \nFailed with ==> #{rsp[-1]}"
              uii.info(I18n.t('vagrant_zones.console_failed') + em) if rsp[-1].to_s.match(/Error Code: \b(?!0\b)\d{1,4}\b/)
              raise Errors::ConsoleFailed if rsp[-1].to_s.match(/Error Code: \b(?!0\b)\d{1,4}\b/)
            end
          end
          Process.kill('HUP', pid)
        end
      end

      # This checks if the user exists on the VM, usually for LX zones
      def user_exists?(uii, user = 'vagrant')
        name = @machine.name
        config = @machine.provider_config
        ret = execute(true, "#{@pfexec} zlogin #{name} id -u #{user}")
        uii.info(I18n.t('vagrant_zones.userexists')) if config.debug
        return true if ret.zero?

        false
      end

      # This gives the user a terminal console
      def zlogincommand(uii, cmd)
        name = @machine.name
        config = @machine.provider_config
        uii.info(I18n.t('vagrant_zones.zonelogincmd')) if config.debug
        execute(false, "#{@pfexec} zlogin #{name} #{cmd}")
      end

      # This filters the vagrantuser
      def user(machine)
        config = machine.provider_config
        user = config.vagrant_user unless config.vagrant_user.nil?
        user = 'vagrant' if config.vagrant_user.nil?
        user
      end

      # This filters the userprivatekeypath
      def userprivatekeypath(machine)
        config = machine.provider_config
        userkey = config.vagrant_user_private_key_path.to_s
        if config.vagrant_user_private_key_path.to_s.nil?
          id_rsa = 'https://raw.githubusercontent.com/hashicorp/vagrant/master/keys/vagrant'
          file = './id_rsa'
          command = "#{@pfexec} curl #{id_rsa} -O #{file}"
          Util::Subprocess.new command do |_stdout, stderr, _thread|
            uii.rewriting do |uipkp|
              uipkp.clear_line
              uipkp.info(I18n.t('vagrant_zones.importing_vagrant_key'), new_line: false)
              uipkp.report_progress(stderr, 100, false)
            end
          end
          uii.clear_line
          userkey = './id_rsa'
        end
        userkey
      end

      # This filters the sshport
      def sshport(machine)
        config = machine.provider_config
        sshport = '22'
        sshport = config.sshport.to_s unless config.sshport.to_s.nil? || config.sshport.to_i.zero?
        # uii.info(I18n.t('vagrant_zones.sshport')) if config.debug
        sshport
      end

      # This filters the firmware
      def firmware(uii)
        config = @machine.provider_config
        uii.info(I18n.t('vagrant_zones.firmware')) if config.debug
        ft = case config.firmware_type
             when /compatability/
               'BHYVE_RELEASE_CSM'
             when /UEFI/
               'BHYVE_RELEASE'
             when /BIOS/
               'BHYVE_CSM'
             when /BHYVE_DEBUG/
               'UEFI_DEBUG'
             when /BHYVE_RELEASE_CSM/
               'BIOS_DEBUG'
             end
        ft.to_s
      end

      # This filters the rdpport
      def rdpport(uii)
        config = @machine.provider_config
        uii.info(I18n.t('vagrant_zones.rdpport')) if config.debug
        config.rdpport.to_s unless config.rdpport.to_s.nil?
      end

      # This filters the vagrantuserpass
      def vagrantuserpass(machine)
        config = machine.provider_config
        # uii.info(I18n.t('vagrant_zones.vagrantuserpass')) if config.debug
        config.vagrant_user_pass unless config.vagrant_user_pass.to_s.nil?
      end

      ## List ZFS Snapshots, helper function to sort and display
      def zfssnaplistdisp(zfs_snapshots, uii, index, disk)
        uii.info("\n Disk Number: #{index}\n Disk Path: #{disk}")
        zfssnapshots = zfs_snapshots.split(/\n/).reverse
        zfssnapshots << "Snapshot\t\t\t\tUsed\tAvailable\tRefer\tPath"
        pml, rml, aml, uml, sml = 0
        zfssnapshots.reverse.each do |snapshot|
          ar = snapshot.gsub(/\s+/m, ' ').strip.split
          sml = ar[0].length.to_i if ar[0].length.to_i > sml.to_i
          uml = ar[1].length.to_i if ar[1].length.to_i > uml.to_i
          aml = ar[2].length.to_i if ar[2].length.to_i > aml.to_i
          rml = ar[3].length.to_i if ar[3].length.to_i > rml.to_i
          pml = ar[4].length.to_i if ar[4].length.to_i > pml.to_i
        end
        zfssnapshots.reverse.each_with_index do |snapshot, si|
          ar = snapshot.gsub(/\s+/m, ' ').strip.split
          strg1 = "%<sym>5s %<s>-#{sml}s %<u>-#{uml}s %<a>-#{aml}s %<r>-#{rml}s %<p>-#{pml}s"
          strg2 = "%<si>5s %<s>-#{sml}s %<u>-#{uml}s %<a>-#{aml}s %<r>-#{rml}s %<p>-#{pml}s"
          if si.zero?
            puts format strg1.to_s, sym: '#', s: ar[0], u: ar[1], a: ar[2], r: ar[3], p: ar[4]
          else
            puts format strg2.to_s, si: si - 2, s: ar[0], u: ar[1], a: ar[2], r: ar[3], p: ar[4]
          end
        end
      end

      ## List ZFS Snapshots
      def zfssnaplist(datasets, opts, uii)
        # config = @machine.provider_config
        # name = @machine.name
        uii.info(I18n.t('vagrant_zones.zfs_snapshot_list'))
        datasets.each_with_index do |disk, index|
          zfs_snapshots = execute(false, "#{@pfexec} zfs list -t snapshot | grep #{disk} || true")
          next if zfs_snapshots.nil?

          ds = opts[:dataset].scan(/\D/).empty? unless opts[:dataset].nil?
          if ds
            next if opts[:dataset].to_i != index
          else
            next unless opts[:dataset] == disk || opts[:dataset].nil? || opts[:dataset] == 'all'
          end
          zfssnaplistdisp(zfs_snapshots, uii, index, disk)
        end
      end

      ## Create ZFS Snapshots
      def zfssnapcreate(datasets, opts, uii)
        uii.info(I18n.t('vagrant_zones.zfs_snapshot_create'))
        if opts[:dataset] == 'all'
          datasets.each do |disk|
            uii.info("  - #{disk}@#{opts[:snapshot_name]}")
            execute(false, "#{@pfexec} zfs snapshot #{disk}@#{opts[:snapshot_name]}")
          end
        else
          ds = opts[:dataset].scan(/\D/).empty? unless opts[:dataset].nil?
          if ds
            datasets.each_with_index do |disk, index|
              next unless opts[:dataset].to_i == index.to_i

              execute(false, "#{@pfexec} zfs snapshot #{disk}@#{opts[:snapshot_name]}")
              uii.info("  - #{disk}@#{opts[:snapshot_name]}")
            end
          else
            execute(false, "#{@pfexec} zfs snapshot #{opts[:dataset]}@#{opts[:snapshot_name]}") if datasets.include?(opts[:dataset])
            uii.info("  - #{opts[:dataset]}@#{opts[:snapshot_name]}") if datasets.include?(opts[:dataset])
          end
        end
      end

      ## Destroy ZFS Snapshots
      def zfssnapdestroy(datasets, opts, uii)
        uii.info(I18n.t('vagrant_zones.zfs_snapshot_destroy'))
        if opts[:dataset].to_s == 'all'
          datasets.each do |disk|
            output = execute(false, "#{@pfexec} zfs list -t snapshot -o name | grep #{disk}")
            ## Never delete the source when doing all
            output = output.split(/\n/).drop(1)
            ## Delete in Reverse order
            output.reverse.each do |snaps|
              cmd = "#{@pfexec} zfs destroy #{snaps}"
              execute(false, cmd)
              uii.info("  - #{snaps}")
            end
          end
        else
          ## Specify the dataset by number
          datasets.each_with_index do |disk, dindex|
            next unless dindex.to_i == opts[:dataset].to_i

            output = execute(false, "#{@pfexec} zfs list -t snapshot -o name | grep #{disk}")
            output = output.split(/\n/).drop(1)
            output.each_with_index do |snaps, spindex|
              if opts[:snapshot_name].to_i == spindex && opts[:snapshot_name].to_s != 'all'
                uii.info("  - #{snaps}")
                execute(false, "#{@pfexec} zfs destroy #{snaps}")
              end
              if opts[:snapshot_name].to_s == 'all'
                uii.info("  - #{snaps}")
                execute(false, "#{@pfexec} zfs destroy #{snaps}")
              end
            end
          end
          ## Specify the Dataset by path
          cmd = "#{@pfexec} zfs destroy #{opts[:dataset]}@#{opts[:snapshot_name]}"
          execute(false, cmd) if datasets.include?("#{opts[:dataset]}@#{opts[:snapshot_name]}")
        end
      end

      ## This will list Cron Jobs for Snapshots to take place
      def zfssnapcronlist(uii, disk, opts, cronjobs)
        return unless opts[:dataset].to_s == disk.to_s || opts[:dataset].to_s == 'all'

        # config = @machine.provider_config
        # name = @machine.name
        uii.info(I18n.t('vagrant_zones.cron_entries'))
        h = { h: 'hourly', d: 'daily', w: 'weekly', m: 'monthly' }
        h.each do |_k, d|
          next unless opts[:list] == d || opts[:list] == 'all'

          uii.info(cronjobs[d.to_sym]) unless cronjobs[d.to_sym].nil?
        end
      end

      ## This will delete Cron Jobs for Snapshots to take place
      def zfssnapcrondelete(uii, disk, opts, cronjobs)
        return unless opts[:dataset].to_s == disk.to_s || opts[:dataset].to_s == 'all'

        sc = "#{@pfexec} crontab"
        rmcr = "#{sc} -l | grep -v "
        h = { h: 'hourly', d: 'daily', w: 'weekly', m: 'monthly' }
        uii.info(I18n.t('vagrant_zones.cron_delete'))
        h.each do |_k, d|
          next unless opts[:delete] == d || opts[:delete] == 'all'

          cj = cronjobs[d.to_sym].to_s.gsub(/\*/, '\*')
          rc = "#{rmcr}'#{cj}' | #{sc}"
          uii.info("  - Removing Cron: #{cj}") unless cronjobs[d.to_sym].nil?
          execute(false, rc) unless cronjobs[d.to_sym].nil?
        end
      end

      ## This will set Cron Jobs for Snapshots to take place
      def zfssnapcronset(uii, disk, opts, cronjobs)
        return unless opts[:dataset].to_s == disk.to_s || opts[:dataset].to_s == 'all'

        config = @machine.provider_config
        name = @machine.name
        uii.info(I18n.t('vagrant_zones.cron_set'))
        snpshtr = config.snapshot_script.to_s
        shrtcr = "( #{@pfexec} crontab -l; echo "
        h = {}
        sf = { freq: opts[:set_frequency], rtn: opts[:set_frequency_rtn] }
        rtn = { h: 24, d: 8, w: 5, m: 1 }
        ct = { h: '0 1-23 * * * ', d: '0 0 * * 0-5 ', w: '0 0 * * 6 ', m: '0 0 1 * * ' }
        h[:hourly] = { rtn: rtn[:h], ct: ct[:h] }
        h[:daily] = { rtn: rtn[:d], ct: ct[:d] }
        h[:weekly] = { rtn: rtn[:w], ct: ct[:w] }
        h[:monthly] = { rtn: rtn[:m], ct: ct[:m] }
        h.each do |k, d|
          next unless (k.to_s == sf[:freq] || sf[:freq] == 'all') && cronjobs[k].nil?

          cj = "#{d[:ct]}#{snpshtr} -p #{k} -r -n #{sf[:rtn]} #{disk} # #{name}" unless sf[:rtn].nil?
          cj = "#{d[:ct]}#{snpshtr} -p #{k} -r -n #{d[:rtn]} #{disk} # #{name}" if sf[:rtn].nil?
          h[k] = { rtn: rtn[:h], ct: ct[:h], cj: cj }
          setcron = "#{shrtcr}'#{cj}' ) | #{@pfexec} crontab"
          uii.info("Setting Cron: #{setcron}")
          execute(false, setcron)
        end
      end

      ## Configure ZFS Snapshots Crons
      def zfssnapcron(datasets, opts, uii)
        name = @machine.name
        # config = @machine.provider_config
        crons = execute(false, "#{@pfexec} crontab -l").split("\n")
        rtnregex = '-p (weekly|monthly|daily|hourly)'
        opts[:dataset] = 'all' if opts[:dataset].nil?
        datasets.each do |disk|
          cronjobs = {}
          crons.each do |tasks|
            next if tasks.empty? || tasks[/^#/]

            case tasks[/#{rtnregex}/, 1]
            when 'hourly'
              hourly = tasks if tasks[/# #{name}/] && tasks[/#{disk}/]
              cronjobs.merge!(hourly: hourly) if tasks[/# #{name}/] && tasks[/#{disk}/]
            when 'daily'
              daily = tasks if tasks[/# #{name}/] && tasks[/#{disk}/]
              cronjobs.merge!(daily: daily) if tasks[/# #{name}/] && tasks[/#{disk}/]
            when 'weekly'
              weekly = tasks if tasks[/# #{name}/] && tasks[/#{disk}/]
              cronjobs.merge!(weekly: weekly) if tasks[/# #{name}/] && tasks[/#{disk}/]
            when 'monthly'
              monthly = tasks if tasks[/# #{name}/] && tasks[/#{disk}/]
              cronjobs.merge!(monthly: monthly) if tasks[/# #{name}/] && tasks[/#{disk}/]
            end
          end
          zfssnapcronlist(uii, disk, opts, cronjobs) unless opts[:list].nil?
          zfssnapcrondelete(uii, disk, opts, cronjobs) unless opts[:delete].nil?
          zfssnapcronset(uii, disk, opts, cronjobs) unless opts[:set_frequency].nil?
        end
      end

      # This helps us manage ZFS Snapshots
      def zfs(uii, job, opts)
        name = @machine.name
        config = @machine.provider_config
        bootconfigs = config.boot
        datasetroot = "#{bootconfigs['array']}/#{bootconfigs['dataset']}/#{name}/#{bootconfigs['volume_name']}"
        datasets = []
        datasets << datasetroot.to_s
        config.additional_disks&.each do |disk|
          additionaldataset = "#{disk['array']}/#{disk['dataset']}/#{name}/#{disk['volume_name']}"
          datasets << additionaldataset.to_s
        end
        case job
        when 'list'
          zfssnaplist(datasets, opts, uii)
        when 'create'
          zfssnapcreate(datasets, opts, uii)
        when 'destroy'
          zfssnapdestroy(datasets, opts, uii)
        when 'cron'
          zfssnapcron(datasets, opts, uii)
        end
      end

      # Halts the Zone, first via shutdown command, then a halt.
      def halt(uii)
        name = @machine.name
        config = @machine.provider_config

        ## Check state in zoneadm
        vm_state = execute(false, "#{@pfexec} zoneadm -z #{name} list -p | awk -F: '{ print $3 }'")
        uii.info(I18n.t('vagrant_zones.graceful_shutdown'))
        begin
          Timeout.timeout(config.clean_shutdown_time) do
            execute(false, "#{@pfexec} zoneadm -z #{name} shutdown") if vm_state == 'running'
          end
        rescue Timeout::Error
          uii.info(I18n.t('vagrant_zones.graceful_shutdown_failed') + config.clean_shutdown_time.to_s)
          begin
            Timeout.timeout(config.clean_shutdown_time) do
              execute(false, "#{@pfexec} zoneadm -z #{name} halt")
            end
          rescue Timeout::Error
            raise Errors::TimeoutHalt
          end
        end
      end

      # Destroys the Zone configurations and path
      def destroy(id)
        name = @machine.name
        id.info(I18n.t('vagrant_zones.leaving'))
        id.info(I18n.t('vagrant_zones.destroy_zone'))
        vm_state = execute(false, "#{@pfexec} zoneadm -z #{name} list -p | awk -F: '{ print $3 }'")

        ## If state is installed, uninstall from zoneadm and destroy from zonecfg
        if vm_state == 'installed'
          id.info(I18n.t('vagrant_zones.bhyve_zone_config_uninstall'))
          execute(false, "#{@pfexec} zoneadm -z #{name} uninstall -F")
          id.info(I18n.t('vagrant_zones.bhyve_zone_config_remove'))
          execute(false, "#{@pfexec} zonecfg -z #{name} delete -F")
        end

        ## If state is configured or incomplete, uninstall from destroy from zonecfg
        if %w[incomplete configured].include?(vm_state)
          id.info(I18n.t('vagrant_zones.bhyve_zone_config_remove'))
          execute(false, "#{@pfexec} zonecfg -z #{name} delete -F")
        end

        ### Nic Configurations
        state = 'delete'
        id.info(I18n.t('vagrant_zones.networking_int_remove'))
        network(id, state)
      end
    end
  end
end