Deploying OpenDaylight

Daniel Farrell
Red Hat SDN Team


"State of ODL's Deployment Ecosystem"
"ODL's Deployment Building Blocks"
"Updates from ODL Integration/Packaging"

VERY QUICK: INTRO TO ME

Daniel Farrell
Software Engineer, Red Hat SDN Team

VERY QUICK: INTRO TO ME

Code!

VERY QUICK: INTRO TO ME

OpenDaylight Integration Committer

VERY QUICK: INTRO TO ME

(Soon to be Integration/Packaging)

VERY QUICK: INTRO TO ME

Robotics advisor
 

VERY QUICK: INTRO TO ME

Craft beer lover
 

VERY QUICK: INTRO TO ME

Or other interesting drinks

VERY QUICK: INTRO TO ME

  (Pedal) Biker
 

VERY QUICK: INTRO TO ME

High adventure generally
 

Outline

Outline

Three-layer stack

OUTLINE

Packaging layer

Outline

RPM

OUTLINE

Configuration Management Layer

OUTLINE

Puppet module

OUTLINE

Ansible role


OUTLINE

Pre-Configured Images Layer

Outline

Docker

Outline

Vagrant base box

Outline

Packer

Manual

Manual

"Just download and run"

Manual

Let's try it...

Manual

[~/sandbox]$ vagrant init -m centos/7
[~/sandbox]$ cat Vagrantfile
Vagrant.configure(2) do |config|
  config.vm.box = "centos/7"
end

Manual

[~/sandbox]$ vagrant up

Manual

[~/sandbox]$ vagrant ssh
[vagrant@localhost ~]$


Manual

[vagrant@localhost ~]$ curl -o distribution-karaf-0.3.0-Lithium.tar.gz \
                               <long tarball URL>

Manual

[vagrant@localhost ~]$ sudo mkdir /opt/opendaylight    

Manual

[vagrant@localhost ~]$ sudo tar -x
                                --strip-components=1 
                                --directory=/opt/opendaylight
                                -f <long tarball name>

Manual

[vagrant@localhost ~]$ sudo /opt/opendaylight/bin/karaf server
karaf: java command not found

Manual

[vagrant@localhost ~]$ sudo yum install -y java

Manual

vagrant@localhost ~]$ sudo /opt/opendaylight/bin/karaf server &

Manual

Running as root :(
[vagrant@localhost bin]$ ps -u -p `pgrep java` | awk {'print $1'}
root

Manual

Create `odl:odl` user:group?

Manual

Want a home dir for that user?

Manual

chown ODL's dir to `odl:odl`

Manual

Restart ODL service

Manual

(if only you had systemd support)

Manual

Login and configure Karaf features?

Manual

Port configuration?

Manual

Fine for devs

Manual

Automatic deployments?

Manual

OPNFV?

manual

First user experience?

manual

Modern users expect better

Manual

Modern deployments need better

Package Layer

PACKAGE LAYER

Handles package dependencies
(Java...)

PACKAGE LAYER

Lays down the basic files

PACKAGE LAYER

Creates required users/groups

PACKAGE LAYER

Sets permissions

PACKAGE LAYER

Configures systemd

PACKAGE LAYER

Current: RPMs

PACKAGE LAYER

Future: Also DEBs

RPM

RPM

CentOS Community Build System

RPM

Example

RPM

[opendaylight-3-candidate]
name=CentOS CBS OpenDaylight Lithium candidate repository
baseurl=http://cbs.centos.org/repos/nfv7-opendaylight-3-candidate/$basearch/os/
enabled=1
gpgcheck=0

RPM

Install ODL's repo
[~]$ sudo curl -o /etc/yum.repos.d/opendaylight-3-candidate.repo \
                   <URL to repo config>

RPM

Install ODL
[~]$ sudo yum install -y opendaylight
<snip>
Installed:
  opendaylight.noarch 0:3.0.0-2.el7
Complete!

RPM

Systemd integration
[~]$ sudo systemctl start opendaylight

RPM

Systemd integration
[~]$ sudo systemctl is-active opendaylight
active

RPM

RPM

[/opt/opendaylight/bin]$ ./client
<snip>
opendaylight-user@root>feature:install ...    

RPM

#endexample

RPM

Future: Signed RPMs

RPM

Future: ~Continuous Release
(Ex: 3.0.<many frequent releases>)

Config MANAGEMENT Layer

CONFIG MANAGEMENT LAYER

Installs ODL via package layer

CONFIG MANAGEMENT LAYER

Edits files to apply configuration
(Karaf features, port mappings)

CONFIG MANAGEMENT LAYER

Opens ports

CONFIG MANAGEMENT LAYER

Manages ODL's systemd service

Puppet

Puppet

Puppet Forge

Puppet

Stable

Puppet

Well documented

Puppet

We work to make contributing easy.

Puppet

OS support


Puppet

Community: Ubuntu support

Puppet

Supports tarball-based installs

Puppet

class { 'opendaylight':
  install_method => 'tarball',
  tarball_url    => '<URL to your custom tarball>',
  unitfile_url   => '<URL to your custom unitfile>',
}

Puppet

Major part of OPNFV

Puppet


[~]$ less genesis/puppet/opnfv/manifests/network.pp
<snip>
class { "opendaylight":
  features => [<OPNFV's Karaf features>],
}
<snip>      

Puppet

Well tested

PUPPET

rspec-puppet

Puppet

[~/puppet-opendaylight]$ bundle exec rake test

Puppet

At a high level...

Puppet

In detail...

Puppet

---> syntax:manifests
---> syntax:templates
---> syntax:hiera:yaml

Puppet

Finished in 14.14 seconds (files took 0.53374 seconds to load)
537 examples, 0 failures

Total resources:   17
Touched resources: 17
Resource coverage: 100.00%

Puppet

rspec-puppet
"We're saying what we expected we said"

Puppet

metadata-json-lint metadata.json

Puppet

Beaker

Puppet

Deploy against real VMs

Puppet

Verify resulting state

Puppet

Repeat for various configs

Puppet

At a high level...

Puppet

In detail...

Puppet

Bringing machine 'centos-7' up with 'virtualbox' provider...

centos-7 12:45:09$ yum install -y puppet

Puppet

centos-7 12:45:46$ puppet apply <test manifest>

Puppet

centos-7 12:49:37$ /bin/sh -c systemctl\ is-active\ opendaylight
active

centos-7 executed in 0.04 seconds
      should be running

Puppet

centos-7 12:49:37$ /bin/sh -c id\ odl
uid=1001(odl) gid=1001(odl) groups=1001(odl)

centos-7 executed in 0.04 seconds
      should exist

Puppet

centos-7 executed in 0.05 seconds
            should match /^featuresBoot=standard,ssh/

Puppet

Finished in 5 minutes 22 seconds (files took 1 minute 10.87 seconds to load)
51 examples, 0 failures

Puppet

Beaker is pretty great

Puppet

Example: Vagrant provisioner

Puppet

At a high level...

Puppet

  # Box that installs ODL via Puppet RPM method on CentOS 7
  config.vm.define "cent7_pup_rpm" do |cent7_pup_rpm|
    # Build Vagrant box based on CentOS 7
    cent7_pup_rpm.vm.box = "boxcutter/centos71"

    # Add EPEL repo for access to Puppet et al
    cent7_pup_rpm.vm.provision "shell", inline: "yum install -y epel-release"

    # Install Puppet
    cent7_pup_rpm.vm.provision "shell", inline: "yum install -y puppet"

    # Install OpenDaylight using its Puppet module
    cent7_pup_rpm.vm.provision "puppet" do |puppet|
      puppet.module_path = ["modules"]
      puppet.manifest_file = "odl_install.pp"
    end
  end

Puppet

In detail...

Puppet

Install EPEL, then Puppet

Puppet

Configure provisioner
    # Install OpenDaylight using its Puppet module
    cent7_pup_rpm.vm.provision "puppet" do |puppet|
      puppet.module_path = ["modules"]
      puppet.manifest_file = "odl_install.pp"
    end       

Puppet

      puppet.module_path = ["modules"]

Puppet

[~/vagrant-opendaylight]$ librarian-puppet install
[~/vagrant-opendaylight]$ ls modules
archive  java  opendaylight  stdlib

Puppet

[~/vagrant-opendaylight]$ cat Puppetfile
#!/usr/bin/env ruby

forge "https://forgeapi.puppetlabs.com"

mod 'dfarrell07-opendaylight',
  :git => 'git://github.com/dfarrell07/puppet-opendaylight.git',
  :ref => 'origin/master'

Puppet

      puppet.manifest_file = "odl_install.pp"

Puppet

[~/vagrant-opendaylight]$ cat manifests/odl_install.pp
class { 'opendaylight':
  extra_features => ['odl-ovsdb-openstack'],
}

Puppet

Provision the box

Puppet

[~/vagrant-opendaylight]$ vagrant up cent7_pup_rpm

Puppet

ODL installed
Notice: /Stage[main]/Opendaylight::Install/Yumrepo[opendaylight]/ensure: created
Notice: /Stage[main]/Opendaylight::Install/Package[opendaylight]/ensure: created

Puppet

Features configured
/Stage[main]/Opendaylight::Config/File[org.apache.karaf.features.cfg]/content: content changed '<hash>' to '<different hash>'

Puppet

Explore

Puppet

[~/vagrant-opendaylight]$ vagrant ssh cent7_pup_rpm
[vagrant@localhost ~]$

Puppet

[vagrant@localhost ~]$ sudo systemctl is-active opendaylight
active

Puppet

[vagrant@localhost ~]$ /vagrant/scripts/connect.sh

Puppet


Puppet

opendaylight-user@root>config:list | grep featuresBoot\ =
   featuresBoot = <default features>,odl-ovsdb-openstack

Puppet

opendaylight-user@root>feature:list | grep odl-ovsdb-openstack
odl-ovsdb-openstack | 1.1.0-Lithium | x | ovsdb-1.1.0-Lithium <snip>

Puppet

#endexample

Puppet

Con: Complexity vs Ansible
(for me, not for users)

Puppet

Con: Ecosystem quality


Puppet

Future: OS support updates

Puppet

Future: Beaker using containers for speed

Puppet

Move to Integration/Packaging

Puppet

Official ODL Puppet Forge account

Puppet

Future:  Stackforge? OpenStack Puppet mods?

Ansible

Ansible

Ansible Galaxy

Ansible

Simple

Ansible

[~/ansible-opendaylight]$ cat tasks/main.yml
---
- include: install_odl.yml
- include: configure_karaf_features.yml
- include: configure_nb_rest_port.yml
- include: open_nb_rest_port.yml
- include: start_odl.yml

Ansible

- name: Start ODL systemd service
  service:
    name=opendaylight
    enabled=yes
    state=started

Ansible

- name: Configure ODL Karaf features
  template:
    src=org.apache.karaf.features.cfg
    dest=/opt/opendaylight/etc/
    owner=odl
    group=odl
  notify:
    - Stop ODL
    - Cleanup Karaf
    - Start ODL

Ansible

[~/ansible-opendaylight]$ wc -l **/*.yml 
<snip>
191 total

Ansible

Rejects Puppet's style of testing
“don’t unit test your playbook"

“Ansible believes you should not need another framework to validate basic things of your infrastructure”

Ansible

So no rspec-puppet or Beaker

Ansible

Beaker was kinda nice...

Ansible

No tears for rspec-puppet

Ansible

Fail fast and clearly

Ansible

Focus on the deployment logic

Ansible

Example: Vagrant provisioner

Ansible

At a high level...

Ansible

  # Box that installs ODL via its Ansible role on CentOS 7
  config.vm.define "cent7_ansible" do |cent7_ansible|
    # Build Vagrant box based on CentOS 7
    cent7_ansible.vm.box = "boxcutter/centos71"

    # Install ODL using the Ansible provisioner
    cent7_ansible.vm.provision "ansible" do |ansible|
      # Path to Ansible playbook that installs ODL using ODL's Ansible role
      ansible.playbook = "provisioning/playbook.yml"
    end
  end

Ansible

In detail...

Ansible

      ansible.playbook = "provisioning/playbook.yml"

Ansible

[~/vagrant-opendaylight]$ cat provisioning/playbook.yml
---
- hosts: all
  sudo: yes
  roles:
    - opendaylight

ansible

Provision the box

Ansible

[~/vagrant-opendaylight]$ vagrant up cent7_ansible

ansible

At a high level...

Ansible

In detail...

Ansible

TASK: [opendaylight | Add ODL yum repo] ********************************** 
changed: [cent7_ansible]
TASK: [opendaylight | Install ODL via RPM repo] **************************
changed: [cent7_ansible]

Ansible

TASK: [opendaylight | Configure ODL Karaf features] ********************** 
changed: [cent7_ansible]

Ansible

TASK: [opendaylight | Configure ODL NB REST port] ************************ 
changed: [cent7_ansible]
TASK: [opendaylight | Check if FirewallD service is running] ************* 
ok: [cent7_ansible]
TASK: [opendaylight | Open ODL NB REST port via FirewallD] *************** 
skipping: [cent7_ansible]      

Ansible

TASK: [opendaylight | Start ODL systemd service] ************************* 
changed: [cent7_ansible]

Ansible

Explore

Ansible

[~/vagrant-opendaylight]$ vagrant ssh cent7_ansible
[vagrant@localhost ~]$

Ansible

[vagrant@localhost ~]$ sudo systemctl is-active opendaylight
active

Ansible

Example: Config change

Ansible

[~/vagrant-opendaylight]$ cat provisioning/playbook.yml
---
- hosts: all
  sudo: yes
  roles:
    - role: opendaylight
      extra_features: ['odl-ovsdb-openstack']

Ansible

[~/vagrant-opendaylight]$ vagrant provision cent7_ansible

ansible

At a high level...

Ansible

In detail...

Ansible

TASK: [opendaylight | Configure ODL Karaf features] ********************** 
changed: [cent7_ansible]

Ansible

NOTIFIED: [opendaylight | Stop ODL] ************************************** 
changed: [cent7_ansible]

NOTIFIED: [opendaylight | Cleanup Karaf] ********************************* 
changed: [cent7_ansible]

NOTIFIED: [opendaylight | Start ODL] ************************************* 
changed: [cent7_ansible]

Ansible

Explore

Ansible

[~/vagrant-opendaylight]$ vagrant ssh cent7_ansible

Ansible

[vagrant@localhost ~]$ sudo systemctl is-active opendaylight
active

Ansible

[vagrant@localhost ~]$ /vagrant/scripts/connect.sh


Ansible


Ansible

opendaylight-user@root>config:list | grep odl-ovsdb-openstack
featuresBoot = config,<snip>,odl-ovsdb-openstack

Ansible

opendaylight-user@root>feature:list | grep odl-ovsdb-openstack
odl-ovsdb-openstack | 1.1.0-Lithium | x | ovsdb-1.1.0-Lithium <snip>

Ansible

Example: Remote host

Ansible

[~]$ sudo ansible-galaxy install dfarrell07.opendaylight

Ansible

[~/sandbox]$ cat /etc/ansible/hosts
odl_box ansible_ssh_host=10.3.12.87 ansible_ssh_user=centos

Ansible

[~/sandbox]$ cat install_odl.yml
---
- hosts: odl_box
  sudo: yes
  roles:
    - dfarrell07.opendaylight

Ansible

[~/sandbox]$ ansible-playbook install_odl.yml

ansible

At a high level...

Ansible

#endexamples

Ansible

Future: Cluster support

Ansible

Future: Integrate ODL + OPNFV?

Ansible

Future: Wider OS support

Ansible

Future: Expanded use by Packer

Ansible

Future: Test in build system

ANSIBLE

Move to Integration/Packaging

ANSIBLE

Official ODL Ansible Galaxy account

Pre-Configured Images

PRE-CONFIGURED IMAGES

Environment with ODL installed and configured

PRE-CONFIGURED IMAGES

Built using config management layer

PRE-CONFIGURED IMAGES

Vagrant base boxes
(packaged VM images)

PRE-CONFIGURED IMAGES

Docker containers

Containers

Containers

Docker Hub

Containers

Example: One-liner Karaf shell

Containers

$ docker run -ti dfarrell07/odl:3.0.0 /opt/opendaylight/bin/karaf

Containers

$ docker ps
CONTACONTAINER ID   IMAGE                  COMMAND
b2869594fab3        dfarrell07/odl:3.0.0   "/opt/opendaylight/bin/karaf"

Containers

#endexamples

Containers

OPNFV Fuel uses containerized ODL

CONTAINERS

Future: Containers in CI

Containers

Future: Pre-configured test tools containers
 (via Packer)

CONTAINERS

Future: ODL clusters via containers

CONTAINERS

Future: Support other OSs

CONTAINERS

Future: Official ODL DockerHub account

Containers

Future: ~Continuous Release
(Ex: 3.0.<many frequent releases>)

Containers

Future: Test in build system

Vagrant base box


Vagrant Base Box

Best user experience?

Vagrant Base Box

Example

Vagrant Base Box

[~/sandbox]$ vagrant init -m dfarrell07/opendaylight
[~/sandbox]$ cat Vagrantfile
Vagrant.configure(2) do |config|
  config.vm.box = "dfarrell07/opendaylight"
end

Vagrant Base Box

[~/sandbox]$ vagrant up

Vagrant Base Box

    default: URL: https://atlas.hashicorp.com/dfarrell07/opendaylight
==> default: Adding box 'dfarrell07/opendaylight' (v3.0.0)

Vagrant Base Box

[~/sandbox]$ vagrant status
Current machine states:

default                   running (virtualbox)

Vagrant Base Box

[~/sandbox]$ vagrant ssh

Vagrant Base Box

[vagrant@localhost ~]$ sudo systemctl is-active opendaylight
active

Vagrant Base Box

#endexample

Vagrant Base Box

Future: Support libvirt provider

Vagrant Base Box

Future: Support other OSs

Vagrant Base Box

Future: Pre-configured test tool Vagrant boxes
 (via Packer)

Vagrant Base box

Future: Official ODL account

Vagrant Base Box

Future: ~Continuous Release
(Ex: 3.0.<many frequent releases>)

Vagrant Base box

Future: Test in build system

Packer

Packer

Creates ODL's Vagrant base box + Docker image

Packer

Simple

Packer

$ packer build -var-file=packer_vars.json centos.json

Packer

At a high level...

Packer

Details...

PACKER

Container+VM builds start in parallel

PACKER

Example: VM build first

Packer

Start with a fresh CentOS ISO
      "iso_urls":
        [
          <CentOS 7.1.1503 mirror URLs>
        ],
      "iso_checksum": "<CentOS 7.1.1503 hash>",      "iso_checksum_type": "sha256",

Packer

Low-level OS config via Kickstart
(partitions, bootloader, etc)

Packer

Builder -> Provisioners

Packer

Shell provisioner
  "provisioners": [
    {
      "type": "shell",
      "scripts":
        [
          "config_virtualbox.sh",
          "config_vagrant.sh",
          "config_ansible.sh"
        ],
<snip>

Packer

config_virtualbox.sh
VBox Guest Additions, various packages

Packer

config_vagrant.sh
Vagrant user, Vagrant SSH key, permissions

Packer

config_ansible.sh
Install Ansible and ODL's Ansible role

Packer

Shell provisioner -> Ansible provisioner

Packer

Ansible role installs+configures ODL
#..."provisioners": [
    {
      "type": "ansible-local",
      "playbook_file": "install_odl.yml"
    }

Packer

Provisioners -> Post Processors

Packer

Package as a Vagrant box
  "post-processors": [
    {
      "type": "vagrant",
      "compression_level": "9",
      "output": "opendaylight-{{ user `box_version` }}-centos-1503.box"
    }
<snip>

Packer

Builds finished. The artifacts of successful builds are:
--> 'virtualbox' provider box: opendaylight-3.0.0-centos-1503.box

Packer

[~/integration/packaging/packer]$ ls -rc | tail -n 1
opendaylight-3.0.0-centos-1503.box

Packer

[~/sandbox]$ vagrant box add --name "opendaylight" \
                             opendaylight-3.0.0-centos-1503.box

Packer

[~/sandbox]$ vagrant init -m opendaylight

Packer

[~/sandbox]$ cat Vagrantfile
Vagrant.configure(2) do |config|
  config.vm.box = "opendaylight"
end

Packer

[~/sandbox]$ vagrant up
==> default: Importing base box 'opendaylight'...

Packer

[~/sandbox]$ vagrant ssh

Packer

[vagrant@localhost ~]$ sudo systemctl is-active opendaylight
active

Packer

#endexample

PACKER

Example: Container build

Packer

Start from upstream CentOS container
      "type": "docker",
      "image": "centos:7.1.1503",

Packer

Builder -> Provisioners

Packer

Shell Provisioner
      "type": "shell",
      "scripts":
        [
          "config_docker.sh",
          "config_ansible.sh"
        ],

Packer

config_docker.sh
Permissions, minimal packages

PACKER

config_ansible.sh
Install Ansible and ODL's Ansible role

Packer

Ansible role installs+configures ODL
#..."provisioners": [
    {
      "type": "ansible-local",
      "playbook_file": "install_odl.yml"
    }

Packer

Provisioners -> Post Processors

Packer

Tag resulting container
    {
      "type": "docker-tag",
      "repository": "{{ user `docker_name` }}",
      "tag": "{{ user `docker_version` }}",
      "force": true,
      "only": ["docker"]
    }

Packer

Builds finished. The artifacts of successful builds are:
--> 'docker' provider: opendaylight/odl:3.0.0 image tagged

Packer

$ docker run -ti dfarrell07/odl:3.0.0 /opt/opendaylight/bin/karaf



Packer

#endexamples

Packer

Everything's in VCS

Packer

Common Ansible path
(powerful config, free updates)

Packer

Room for growth

Conclusion

Conclusion

ODL has a rich deployment toolset

Conclusion

Reusable, composable building blocks

Conclusion

Enables modern automatic deployments

Conclusion

Enables drive-by exploration

Conclusion

Focus on quality

Conclusion

Contributions welcome :)

Contact

Daniel Farrell
SDN broadcasts via Twitter:

General:
dfarrell@redhat.com
dfarrell07 on IRC, GitHub

Deploying OpenDaylight

By Daniel Farrell

Deploying OpenDaylight

Talk given at LinuxCon North America 2015

  • 2,762