Introduction

Recently I converted from using the Virtualbox provider for Vagrant to using the Libvirt provider. This post will cover how to create a Cisco csr1000v Vagrant box for use with the vagrant-libvirt provider.

For reference the following software will be used in this post.

  • Cisco csr1000v - 3.15.00.S.155-2.S
  • Vagrant - Vagrant 1.9.6
  • vagrant-libvirt - 0.4.0
  • Ubuntu - 1604

Download

Cisco does not provide a Vagrant Libvirt box, but they do provide a qcow2 image. You will need to download the qcow2 from the Cisco software download section.

Search for csr1000v and download csr1000v-universalk9.03.15.00.S.155-2.S-std.qcow2. Note: A CCO account is required to download the software but its free to register and no support contract is required.

Install

Create and change into directory for csr1000v files. I like to keep my custom vagrant boxes under ~/vagrant/boxes/.


mkdir -p ~/vagrant/boxes/cisco/csr1kv
cd ~/vagrant/boxes/cisco/csr1kv
            

Copy the qcow2 file downloaded earlier to the ~/vagrant/boxes/cisco/csr1kv directory.


cp ~/Downloads/csr1000v-universalk9.03.15.00.S.155-2.S-std.qcow2 .
          

The maintainers of the vagrant-libvirt plugin have a script that can be used to convert qcow2 images to a vagrant box. Download the libvirt conversion script.


curl -O https://raw.githubusercontent.com/vagrant-libvirt/vagrant-libvirt/master/tools/create_box.sh
          

Now lets build the csr1000v VM and apply a bootstrap configuration.


virt-install \
    --connect=qemu:///system \
    --name=csr1000v \
    --os-type=linux \
    --os-variant=rhel4 \
    --arch=x86_64 \
    --cpu host \
    --vcpus=1 \
    --hvm \
    --ram=4096 \
    --disk path=csr1000v-universalk9.03.15.00.S.155-2.S-std.qcow2,bus=ide,format=qcow2 \
    --network=network:vagrant-libvirt,model=virtio \
    --import
          

A virtual terminal will open that can be used to configure the VM, as far as I am aware you cannot copy and past into this terminal so it is not very convenient. Once the VM is booted configure the VM to use the serial port instead of the virtual console.


enable
conf t
platform console serial
end 
copy system:running-config nvram:startup-config 
reload
          

When the VM reboots, conenct via the console port and apply the bootstrap configuration.


virsh console csr1000v
          

Once connected apply the bootstrap configuration.


en
conf t
hostname csr
ip domain-name lab.local
!
crypto key generate rsa modulus 2048
ip ssh version 2
!
aaa new-model
!
aaa authentication login default local
aaa authorization exec default local
!
username vagrant privilege 15 secret vagrant
!
ip ssh pubkey-chain
  username vagrant
    key-hash ssh-rsa DD3BB82E850406E9ABFFA80AC0046ED6
!
!
interface GigabitEthernet1
  description vagrant-management
  ip address dhcp
  no shutdown
!
end
wr mem
          

Check the IP address assigned to interface GigabitEthernet1.


show ip int brie

# output
Interface              IP-Address      OK? Method Status                Protocol
GigabitEthernet1       192.168.121.227 YES DHCP   up                    up   
          

To exit the console press and hold CTRL and SHIFT while pressing 6 then ].

Now confirm that it is possible to SSH to the VM with the insecure_private_key.


# from host shell
ssh vagrant@192.168.121.227 -i ~/.vagrant.d/insecure_private_key

# now logged into guest csr
csr#   
          

If you can successfully SSH to the csr1000v with the insecure_private_key its time to package the VM into a Vagrant box. First shutdown the VM.


virsh shutdown csr1000v

# output
Domain csr1000v is being shutdown
          

Create a metadata.json file with the following contents.


{"provider":"libvirt","format":"qcow2","virtual_size":8}
          

Use the previously downloaded create_box.sh script to make a Vagrant box from the qcow2 image.


bash create_box.sh csr1000v-universalk9.03.15.00.S.155-2.S-std.qcow2

# output
{8}
==> Creating box, tarring and gzipping
./metadata.json
./Vagrantfile
./box.img
Total bytes written: 1369313280 (1.3GiB, 33MiB/s)
==> csr1000v-universalk9.03.15.00.S.155-2.S-std.box created
==> You can now add the box:
==>   'vagrant box add csr1000v-universalk9.03.15.00.S.155-2.S-std.box --name csr1000v-universalk9.03.15.00.S.155-2.S-std'
          

Create a metadata file called csr1kv.json so that the box is added with the correct version number.


{
  "name": "cisco/csr1000v",
  "description": "Cisco csr1000v",
  "versions": [
    {
      "version": "03.15.00.S-155-2-S",
      "providers": [
        {
          "name": "libvirt",
          "url": "file:///home/bradmin/vagrant/boxes/cisco/csr1kv/csr1000v-universalk9.03.15.00.S.155-2.S-std.box"
        }
      ]
    }
  ]
}
          

Add the box to Vagrant using the csr1kv.json file.


vagrant box add csr1kv.json

# output
==> box: Loading metadata for box 'csr1kv.json'
    box: URL: file:///home/bradmin/vagrant/boxes/cisco/csr1kv.json
==> box: Adding box 'cisco/csr1000v' (v03.15.00.S-155-2-S) for provider: libvirt
    box: Unpacking necessary files from: file:///home/bradmin/vagrant/boxes/cisco/csr1000v-universalk9.03.15.00.S.155-2.S-std.box
==> box: Successfully added box 'cisco/csr1000v' (v03.15.00.S-155-2-S) for 'libvirt'!
          

Confirm the csr1000v box was added successfully.


vagrant box list

# output
CumulusCommunity/cumulus-vx          (libvirt, 3.4.2)
CumulusCommunity/cumulus-vx          (libvirt, 3.4.3)
CumulusCommunity/cumulus-vx          (virtualbox, 3.4.1)
arista/veos                          (libvirt, 4.18.1F)
arista/veos                          (virtualbox, 4.16.9M)
arista/veos                          (virtualbox, 4.17.5M)
arista/veos                          (virtualbox, 4.18.1F)
centos/7                             (libvirt, 1708.01)
centos/7                             (virtualbox, 1705.02)
cisco/asav                           (virtualbox, 9.8.1)
cisco/csr1000v                       (libvirt, 03.15.00.S-155-2-S)
cisco/csr1000v                       (virtualbox, 03.15.00)
          

Vagrantfile

Use this Vagrantfile to test out the new csr1000v Vagrant box.


# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure("2") do |config|
  config.vm.box = "cisco/csr1000v"

  # Turn off shared folders
  config.vm.synced_folder ".", "/vagrant", disabled: true

  # Do not try to insert new SSH key
  config.ssh.insert_key = false

  # Give VM time to boot
  config.vm.boot_timeout = 180

  # Set guest type to prevent guest type detection
  config.vm.guest = :freebsd

  # Provider-specific configuration
  config.vm.provider :libvirt do |domain|
    domain.nic_adapter_count = 8
    domain.memory = 4096
    domain.cpus = 2
    domain.driver = "kvm"
  end

end              
            

Note: I found that the VM will crash on boot if the config.vm.guest parameter is not configured. It looks like Vagrant tries to determine the guest OS type for use with post build provisioining tasks. Since we will not be performing any of that, statically configuring the value to something looks to disable the OS detection step.

Testing

Ok, with that all said and done lets vagrant up


vagrant up

# output
Bringing machine 'default' up with 'libvirt' provider...
==> default: Creating image (snapshot of base box volume).
==> default: Creating domain with the following settings...
==> default:  -- Name:              cisco-test_default
==> default:  -- Domain type:       kvm
==> default:  -- Cpus:              2
==> default:  -- Feature:           acpi
==> default:  -- Feature:           apic
==> default:  -- Feature:           pae
==> default:  -- Memory:            4096M
==> default:  -- Management MAC:    
==> default:  -- Loader:            
==> default:  -- Base box:          cisco/csr1000v
==> default:  -- Storage pool:      default
==> default:  -- Image:             /var/lib/libvirt/images/cisco-test_default.img (8G)
==> default:  -- Volume Cache:      default
==> default:  -- Kernel:            
==> default:  -- Initrd:            
==> default:  -- Graphics Type:     vnc
==> default:  -- Graphics Port:     5900
==> default:  -- Graphics IP:       127.0.0.1
==> default:  -- Graphics Password: Not defined
==> default:  -- Video Type:        cirrus
==> default:  -- Video VRAM:        9216
==> default:  -- Sound Type:	
==> default:  -- Keymap:            en-us
==> default:  -- TPM Path:          
==> default:  -- INPUT:             type=mouse, bus=ps2
==> default: Creating shared folders metadata...
==> default: Starting domain.
==> default: Waiting for domain to get an IP address...
==> default: Waiting for SSH to become available...
==> default: Configuring and enabling network interfaces...
          

Now SSH into csr1000v.


# from host shell
vagrant ssh

# now in csr1000v shell
csr#show inventory 
NAME: "Chassis", DESCR: "Cisco CSR1000V Chassis"
PID: CSR1000V          , VID: V00, SN: 9NNML42HBX8

NAME: "module R0", DESCR: "Cisco CSR1000V Route Processor"
PID: CSR1000V          , VID: V00, SN: JAB1303001C

NAME: "module F0", DESCR: "Cisco CSR1000V Embedded Services Processor"
PID: CSR1000V          , VID:    , SN:            
          

Good stuff our csr1000v is ready to go, finally clean up the box.


# from host shell              
vagrant destroy -f

# output
==> default: Removing domain...
        

Summary

There you have it a Cisco csr1000v for use with the vagrant-libvirt provider.

Links

https://www.cisco.com/c/en/us/td/docs/routers/csr1000/software/configuration/b_CSR1000v_Configuration_Guide/b_CSR1000v_Configuration_Guide_chapter_0101.pdf
https://www.ibm.com/support/knowledgecenter/en/linuxonibm/liaat/liaatvirtinstalloptions.htm
https://superuser.com/questions/1267567/vagrant-with-freebsd-guest-and-windows-10-host-fails-to-connect






















Published: 2017-11-26