published: 26th of November 2017
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 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 .
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 use one of these key combinations (Assuming English keyboard).
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)
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
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...
There you have it a Cisco csr1000v for use with the vagrant-libvirt provider.