From f0324311a044a59f002a418b4625d8545c6f0b75 Mon Sep 17 00:00:00 2001
From: Alejandro Andreu <alejandro@midokura.com>
Date: Tue, 26 Jul 2016 15:52:50 +0200
Subject: [PATCH] Adds GW type/class (both BGP and static uplinks)

Change-Id: I52a6cce14566469d67c07fd488972a245bc7b73f
---
 files/gateway/functions                       | 369 ++++++++++++++++++
 .../midonet_gateway/midonet_api_caller.rb     | 309 ---------------
 .../midonet_gateway_bgp/midonet_api_caller.rb | 217 ++++++++++
 lib/puppet/type/midonet_gateway.rb            | 159 --------
 lib/puppet/type/midonet_gateway_bgp.rb        | 150 +++++++
 manifests/gateway/static.pp                   | 127 ++++++
 spec/classes/midonet_cluster_spec.rb          |  24 --
 spec/classes/midonet_gateway_static_spec.rb   |  29 ++
 .../midonet_api_caller_spec.rb                | 190 ++++-----
 .../midonet_api_caller_spec.rb                | 108 +++++
 .../puppet/type/midonet_gateway_bgp_spec.rb   |  73 ++++
 spec/unit/puppet/type/midonet_gateway_spec.rb | 202 ----------
 .../gateway/create_fake_uplink_l2.sh.erb      | 105 +++++
 templates/gateway/midorc.erb                  |  58 +++
 14 files changed, 1306 insertions(+), 814 deletions(-)
 create mode 100644 files/gateway/functions
 delete mode 100644 lib/puppet/provider/midonet_gateway/midonet_api_caller.rb
 create mode 100644 lib/puppet/provider/midonet_gateway_bgp/midonet_api_caller.rb
 delete mode 100644 lib/puppet/type/midonet_gateway.rb
 create mode 100644 lib/puppet/type/midonet_gateway_bgp.rb
 create mode 100644 manifests/gateway/static.pp
 delete mode 100644 spec/classes/midonet_cluster_spec.rb
 create mode 100644 spec/classes/midonet_gateway_static_spec.rb
 create mode 100644 spec/unit/puppet/provider/midonet_gateway_bgp/midonet_api_caller_spec.rb
 create mode 100644 spec/unit/puppet/type/midonet_gateway_bgp_spec.rb
 delete mode 100644 spec/unit/puppet/type/midonet_gateway_spec.rb
 create mode 100644 templates/gateway/create_fake_uplink_l2.sh.erb
 create mode 100644 templates/gateway/midorc.erb

diff --git a/files/gateway/functions b/files/gateway/functions
new file mode 100644
index 0000000..3b8b189
--- /dev/null
+++ b/files/gateway/functions
@@ -0,0 +1,369 @@
+#!/usr/bin/env bash
+
+# Copyright 2016 Midokura SARL
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Useful common functions are defined here.  Some of them were shamelessly
+# stolen from devstack.
+
+# Save trace setting
+XTRACE=$(set +o | grep xtrace)
+set +o xtrace
+
+# Control Functions
+# -----------------
+
+# Prints line number and "message" in warning format
+# warn $LINENO "message"
+function warn {
+    local exitcode=$?
+    local xtrace=$(set +o | grep xtrace)
+    set +o xtrace
+    local msg="[WARNING] ${BASH_SOURCE[2]}:$1 $2"
+    echo $msg 1>&2;
+    if [[ -n ${LOGDIR} ]]; then
+        echo $msg >> "${LOGDIR}/error.log"
+    fi
+    $xtrace
+    return $exitcode
+}
+
+# Prints backtrace info
+# filename:lineno:function
+# backtrace level
+function backtrace {
+    local level=$1
+    local deep=$((${#BASH_SOURCE[@]} - 1))
+    echo "[Call Trace]"
+    while [ $level -le $deep ]; do
+        echo "${BASH_SOURCE[$deep]}:${BASH_LINENO[$deep-1]}:${FUNCNAME[$deep-1]}"
+        deep=$((deep - 1))
+    done
+}
+
+# Prints line number and "message" in error format
+# err $LINENO "message"
+function err {
+    local exitcode=$?
+    local xtrace=$(set +o | grep xtrace)
+    set +o xtrace
+    local msg="[ERROR] ${BASH_SOURCE[2]}:$1 $2"
+    echo $msg 1>&2;
+    if [[ -n ${LOGDIR} ]]; then
+        echo $msg >> "${LOGDIR}/error.log"
+    fi
+    $xtrace
+    return $exitcode
+}
+
+# Prints line number and "message" then exits
+# die $LINENO "message"
+function die {
+    local exitcode=$?
+    set +o xtrace
+    local line=$1; shift
+    if [ $exitcode == 0 ]; then
+        exitcode=1
+    fi
+    backtrace 2
+    err $line "$*"
+    # Give buffers a second to flush
+    sleep 1
+    exit $exitcode
+}
+
+# Checks an environment variable is not set or has length 0 OR if the
+# exit code is non-zero and prints "message" and exits
+# NOTE: env-var is the variable name without a '$'
+# die_if_not_set $LINENO env-var "message"
+function die_if_not_set {
+    local exitcode=$?
+    local xtrace=$(set +o | grep xtrace)
+    set +o xtrace
+    local line=$1; shift
+    local evar=$1; shift
+    if ! is_set $evar || [ $exitcode != 0 ]; then
+        die $line "$*"
+    fi
+    $xtrace
+}
+
+# Test if the named environment variable is set and not zero length
+# is_set env-var
+function is_set {
+    local var=\$"$1"
+    eval "[ -n \"$var\" ]" # For ex.: sh -c "[ -n \"$var\" ]" would be better, but several exercises depends on this
+}
+
+
+# Package Functions
+# -----------------
+
+# Wrapper for ``apt-get``
+# apt_get operation package [package ...]
+function apt_get {
+    sudo DEBIAN_FRONTEND=noninteractive \
+        apt-get --option "Dpkg::Options::=--force-confnew" --assume-yes "$@"
+}
+
+# Update package repository
+# Uses globals ``NO_UPDATE_REPOS``, ``REPOS_UPDATED``, ``RETRY_UPDATE``
+# install_package package [package ...]
+function update_package_repo {
+    NO_UPDATE_REPOS=${NO_UPDATE_REPOS:-False}
+    REPOS_UPDATED=${REPOS_UPDATED:-False}
+
+    if [[ "$NO_UPDATE_REPOS" = "True" ]]; then
+        return 0
+    fi
+
+    local xtrace=$(set +o | grep xtrace)
+    set +o xtrace
+    if [[ "$REPOS_UPDATED" != "True" ]]; then
+        # if there are transient errors pulling the updates, that's fine.
+        # It may be secondary repositories that we don't really care about.
+        apt_get update  || /bin/true
+        REPOS_UPDATED=True
+    fi
+    $xtrace
+}
+
+# Package installer
+# install_package package [package ...]
+function install_package {
+    update_package_repo
+    apt_get install --no-install-recommends "$@"
+}
+
+# Function to tell if a package is installed
+# is_package_installed package [package ...]
+function is_package_installed {
+    dpkg -s "$@" > /dev/null 2> /dev/null
+}
+
+
+# System Functions
+# -----------------
+
+# Service wrapper to stop services
+# stop_service service-name
+# Checks if kmod is loaded
+function is_kmod_loaded {
+    lsmod | grep -w $1 >& /dev/null
+}
+
+
+# Process Functions
+# -----------------
+
+function is_screen_running {
+    type -p screen > /dev/null && screen -ls | egrep -q "[0-9]\.$1"
+}
+
+function create_screen {
+    local name=$1
+    screen -d -m -S $name -t shell -s /bin/bash
+    sleep 1
+
+    # Set a reasonable status bar
+    SCREEN_HARDSTATUS='%{= .} %-Lw%{= .}%> %n%f %t*%{= .}%+Lw%< %-=%{g}(%{d}%H/%l%{g})'
+    screen -r $name -X hardstatus alwayslastline "$SCREEN_HARDSTATUS"
+    screen -r $name -X setenv PROMPT_COMMAND /bin/true
+}
+
+
+# Helper to launch a process in a named screen
+# Uses globals ``CURRENT_LOG_TIME``, ``LOGDIR``,
+# ``SERVICE_DIR``
+# screen_process name "command-line"
+# Run a command in a shell in a screen window
+function screen_process {
+    local name=$1
+    local command="$2"
+
+    SERVICE_DIR=${SERVICE_DIR:-/tmp/status}
+    mkdir -p ${SERVICE_DIR}/${SCREEN_NAME}
+
+    # Append the process to the screen rc file
+    screen_rc ${SCREEN_NAME} "$name" "$command"
+
+    screen -S ${SCREEN_NAME} -X screen -t $name
+
+    if [[ -n ${LOGDIR} ]]; then
+        screen -S ${SCREEN_NAME} -p $name -X logfile ${LOGDIR}/${name}.log.${CURRENT_LOG_TIME}
+        screen -S ${SCREEN_NAME} -p $name -X log on
+        ln -sf ${LOGDIR}/${name}.log.${CURRENT_LOG_TIME} ${LOGDIR}/${name}.log
+    fi
+
+    # sleep to allow bash to be ready to be send the command - we are
+    # creating a new window in screen and then sends characters, so if
+    # bash isn't running by the time we send the command, nothing happens
+    sleep 3
+
+    NL=`echo -ne '\015'`
+    screen -S ${SCREEN_NAME} -p $name -X stuff "$command & echo \$! >$SERVICE_DIR/${SCREEN_NAME}/${name}.pid; fg || echo \"$name failed to start\" | tee \"$SERVICE_DIR/${SCREEN_NAME}/${name}.failure\"$NL"
+}
+
+# _run_process() is designed to be backgrounded by run_process() to simulate a
+# fork.  It includes the dirty work of closing extra filehandles and preparing log
+# files to produce the same logs as screen_it().  The log filename is derived
+# from the service name.
+# _run_process service "command-line"
+function _run_process {
+    local service=$1
+    local command="$2"
+
+    # Undo logging redirections and close the extra descriptors
+    exec 1>&3
+    exec 2>&3
+    exec 3>&-
+    exec 6>&-
+
+    local real_logfile="${LOGDIR}/${service}.log.${CURRENT_LOG_TIME}"
+    if [[ -n ${LOGDIR} ]]; then
+        exec 1>&"$real_logfile" 2>&1
+        ln -sf "$real_logfile" ${LOGDIR}/${service}.log
+
+        # Hack to get stdout from the Python interpreter for the logs.
+        export PYTHONUNBUFFERED=1
+    fi
+
+    SERVICE_DIR=${SERVICE_DIR:-/tmp/status}
+    mkdir -p ${SERVICE_DIR}/${SCREEN_NAME}
+    setsid $command & echo $! > ${SERVICE_DIR}/${SCREEN_NAME}/${service}.pid
+
+    # Just silently exit this process
+    exit 0
+}
+
+# Run a single service under screen or directly
+# If the command includes shell metachatacters (;<>*) it must be run using a shell
+# run_process service "command-line"
+function run_process {
+    local service=$1
+    local command="$2"
+
+    if [[ "$USE_SCREEN" = "True" ]]; then
+        screen_process "$service" "cd $TOP_DIR && $command"
+    else
+        # Spawn directly without screen
+        cd $TOP_DIR
+        _run_process "$service" "$command" &
+        cd -
+    fi
+}
+
+# Screen rc file builder
+# Uses globals ``SCREENRC``
+# screen_rc service "command-line"
+function screen_rc {
+    local screen=$1
+    SCREENRC=$DEVMIDO_DIR/$screen-screenrc
+    if [[ ! -e $SCREENRC ]]; then
+        # Name the screen session
+        echo "sessionname $screen" > $SCREENRC
+        # Set a reasonable statusbar
+        echo "hardstatus alwayslastline '$SCREEN_HARDSTATUS'" >> $SCREENRC
+        # Some distributions override PROMPT_COMMAND for the screen terminal type - turn that off
+        echo "setenv PROMPT_COMMAND /bin/true" >> $SCREENRC
+        echo "screen -t shell bash" >> $SCREENRC
+    fi
+    # If this service doesn't already exist in the screenrc file
+    if ! grep $1 $SCREENRC 2>&1 > /dev/null; then
+        NL=`echo -ne '\015'`
+        echo "screen -t $1 bash" >> $SCREENRC
+        echo "stuff \"$2$NL\"" >> $SCREENRC
+
+        if [[ -n ${LOGDIR} ]]; then
+            echo "logfile ${LOGDIR}/${1}.log.${CURRENT_LOG_TIME}" >>$SCREENRC
+            echo "log on" >>$SCREENRC
+        fi
+    fi
+}
+
+# Set an option in an INI file
+# iniset config-file section option value
+function iniset {
+    local xtrace=$(set +o | grep xtrace)
+    set +o xtrace
+    local file=$1
+    local section=$2
+    local option=$3
+    local value=$4
+
+    [[ -z $section || -z $option ]] && return
+
+    if ! grep -q "^\[$section\]" "$file" 2>/dev/null; then
+        # Add section at the end
+        echo -e "\n[$section]" >>"$file"
+    fi
+    if ! ini_has_option "$file" "$section" "$option"; then
+        # Add it
+        sed -i -e "/^\[$section\]/ a\\
+$option = $value
+" "$file"
+    else
+        local sep=$(echo -ne "\x01")
+        # Replace it
+        sed -i -e '/^\['${section}'\]/,/^\[.*\]/ s'${sep}'^\('${option}'[ \t]*=[ \t]*\).*$'${sep}'\1'"${value}"${sep} "$file"
+    fi
+    $xtrace
+}
+
+# Determinate is the given option present in the INI file
+# ini_has_option config-file section option
+function ini_has_option {
+    local xtrace=$(set +o | grep xtrace)
+    set +o xtrace
+    local file=$1
+    local section=$2
+    local option=$3
+    local line
+
+    line=$(sed -ne "/^\[$section\]/,/^\[.*\]/ { /^$option[ \t]*=/ p; }" "$file")
+    $xtrace
+    [ -n "$line" ]
+}
+
+function stop_process {
+    local service=$1
+
+    # Kill via pid if we have one available
+    pkill -F $SERVICE_DIR/$SCREEN_NAME/$service.pid
+    rm $SERVICE_DIR/$SCREEN_NAME/$service.pid
+    screen -S $SCREEN_NAME -p $service -X kill
+}
+
+
+# MN Functions
+# ------------
+
+# Wrapper for mn-conf command
+# Uses globals ``ZOOKEEPER_HOSTS``
+function configure_mn {
+    local value="$2"
+
+    # quote with "" only when necessary.  we don't always quote because
+    # mn-conf complains for quoted booleans.  eg. "false"
+    if [[ "${value}" =~ ":" || "${value}" = "" ]]; then
+        value="\"${value}\""
+    fi
+
+    # In some commands, mn-conf creates a local file, which requires root
+    # access.  For simplicity, always call mn-conf with root for now.
+    echo $1 : "${value}" | MIDO_ZOOKEEPER_HOSTS="$ZOOKEEPER_HOSTS" sudo mn-conf set
+}
+
+# Restore xtrace
+$XTRACE
diff --git a/lib/puppet/provider/midonet_gateway/midonet_api_caller.rb b/lib/puppet/provider/midonet_gateway/midonet_api_caller.rb
deleted file mode 100644
index 1a0abee..0000000
--- a/lib/puppet/provider/midonet_gateway/midonet_api_caller.rb
+++ /dev/null
@@ -1,309 +0,0 @@
-if RUBY_VERSION == '1.8.7'
-    require 'rubygems'
-end
-
-require 'uri'
-require 'faraday'
-require 'json'
-
-Puppet::Type.type(:midonet_gateway).provide(:midonet_api_caller) do
-
-  def create
-    define_connection(resource[:midonet_api_url])
-    # For each remote BGP peer, create a virtual port on
-    # the MidoNet Provider Router that is going to be used
-    # for the BGP communication. Connection to midonet api
-    # is assumed
-
-    router_id = call_get_provider_router()[0]['id']
-
-    message = Hash.new
-    message['portAddress'] = resource[:bgp_port]["port_address"]
-    message['networkAddress'] = resource[:bgp_port]["net_prefix"]
-    message['networkLength'] = resource[:bgp_port]["net_length"].to_i
-    message['type'] = "Router"
-
-    port = call_create_uplink_port(router_id, message)
-    port_id = port[0]['id']
-
-    # Configure BGP on the virtual ports. Port is
-    # assumed created
-    remote_peers = resource[:remote_peers]
-    if remote_peers.class == Hash
-       remote_peers = [remote_peers]
-    end
-    remote_peers.each do |rp|
-      message = Hash.new
-      message['localAS'] = resource[:local_as]
-      message['peerAS'] = rp["as"]
-      message['peerAddr'] = rp["ip"]
-
-      call_add_bgp_to_port(port_id, message)
-    end
-
-    # Add route for 'MidoNet Provider Router' uplink port
-    message = Hash.new
-    message['type'] = "Normal"
-    message['srcNetworkAddr'] = "0.0.0.0"
-    message['srcNetworkLength'] = 0
-    message['dstNetworkAddr'] = resource[:bgp_port]["net_prefix"]
-    message['dstNetworkLength'] = resource[:bgp_port]["net_length"].to_i
-    message['weight'] = 100
-    message['nextHopPort'] = port_id
-
-    call_add_route_for_uplink_port(router_id, message)
-
-    # In order to provide external connectivity for hosted
-    # virtual machines, the floating IP network has to be
-    # advertised to the BGP peers. BGP connection is assumed created
-    bgp_connections = call_get_bgp_connections(port_id)
-
-    #TODO(carmela): make this modification more elegant... or whatever
-    advertise_networks = resource[:advertise_net]
-    if advertise_networks.class == Hash
-       advertise_networks = [advertise_networks]
-    end
-    bgp_connections.each do |bgp_c|
-      advertise_networks.each do |net|
-        message = Hash.new
-        message['nwPrefix'] = net["net_prefix"]
-        message['prefixLength'] = net["net_length"]
-
-        bgp_id = bgp_c["id"]
-        call_advertise_route_to_bgp(bgp_id, message)
-      end
-    end
-
-    # Bind the MidoNet Provider Router’s virtual ports to
-    # the physical network interfaces on the Gateway Nodes.
-    # Host and port are assumed created. Interface name should
-    # be an string
-    host_id = call_get_host()[0]['id']
-
-    message = Hash.new
-    message['interfaceName'] = resource[:interface]
-    message['portId'] = port_id
-
-    call_bind_port_to_interface(host_id, message)
-
-    # Configure a stateful port group
-    spg = call_get_stateful_port_group()
-    if spg.empty?
-      message = Hash.new
-      message['name'] = "uplink-spg"
-      message['stateful'] = "true"
-      message['tenantId'] = call_get_tenant()
-
-      spg = call_create_stateful_port_group(message)
-    end
-
-    # Add the ports to the port group
-    message = Hash.new
-    message['portId'] = port_id
-
-    call_add_ports_to_port_group(spg[0]["id"], message)
-  end
-
-  def destroy
-    define_connection(resource[:midonet_api_url])
-
-    router_id = call_get_provider_router()[0]['id']
-    port_address = resource[:bgp_port]['port_address']
-
-    port = call_get_uplink_port(router_id, port_address)
-    port_id = port[0]["id"]
-
-    # Delete the stateful port group
-    #    TODO(carmela): delete only in case is the last port on the port group
-    #    port_group_id = call_get_stateful_port_group()[0]['id']
-    #    call_delete_stateful_port_group(port_group_id)
-
-    # Delete uplink port
-    call_delete_uplink_port(port_id)
-  end
-
-  def exists?
-    define_connection(resource[:midonet_api_url])
-
-    router = call_get_provider_router()
-    if router.empty?
-      raise 'MidoNet Provider Router does not exist. We cannot create uplink ports'
-    end
-
-    host = call_get_host()
-    if host.empty?
-      raise 'There is no MidoNet agent running on this host'
-    end
-
-    uplink_port = call_get_uplink_port(router[0]['id'], resource[:bgp_port]['port_address'])
-    if uplink_port.empty?
-      return false
-    end
-
-    return true
-  end
-
-  def define_connection(url)
-
-    @connection = Faraday.new(:url => url,
-                              :ssl => { :verify =>false }) do |builder|
-        builder.request(:retry, {
-          :max        => 5,
-          :interval   => 0.05,
-          :exceptions => [
-            Faraday::Error::TimeoutError,
-            Faraday::ConnectionFailed,
-            Errno::ETIMEDOUT,
-            'Timeout::Error',
-          ],
-        })
-        builder.request(:basic_auth, resource[:username], resource[:password])
-        builder.adapter(:net_http)
-    end
-
-    @connection.headers['X-Auth-Token'] = call_get_token()
-  end
-
-  def call_get_token()
-    res = @connection.get do |req|
-      req.url "/midonet-api/login"
-    end
-    return JSON.parse(res.body)['key']
-  end
-
-  def call_get_tenant()
-    res = @connection.get do |req|
-      req.url "/midonet-api/tenants"
-    end
-    return JSON.parse(res.body)[0]['id']
-  end
-
-  def call_get_provider_router()
-    res = @connection.get do |req|
-      req.url "/midonet-api/routers"
-    end
-    output = JSON.parse(res.body)
-    return output.select { |name| name['name'] == resource[:router]}
-  end
-
-  def call_get_stateful_port_group()
-    res = @connection.get do |req|
-      req.url "/midonet-api/port_groups"
-    end
-    output = JSON.parse(res.body)
-    return output.select { |name| name['name'] == 'uplink-spg'}
-
-  end
-
-  def call_get_uplink_port(router_id, port_address)
-    res = @connection.get do |req|
-      req.url "/midonet-api/routers/#{router_id}/ports"
-    end
-    output =  JSON.parse(res.body)
-    return output.select { |port| port['portAddress'] == port_address }
-
-  end
-
-  def call_get_host()
-    res = @connection.get do |req|
-      req.url "/midonet-api/hosts"
-    end
-    output = JSON.parse(res.body)
-    return output.select{ |host| host['name'] == resource[:hostname].to_s }
-  end
-
-  def call_create_uplink_port(router_id, message)
-    res = @connection.post do |req|
-      req.url "/midonet-api/routers/#{router_id}/ports"
-      req.headers['Content-Type'] = "application/vnd.org.midonet.Port-v2+json"
-      req.body = message.to_json
-    end
-    return call_get_uplink_port(router_id, message["portAddress"])
-  end
-
-  def call_delete_uplink_port(port_id)
-    res = @connection.delete do |req|
-      req.url "/midonet-api/ports/#{port_id}"
-    end
-  end
-
-  def call_add_bgp_to_port(port_id, message)
-    res = @connection.post do |req|
-      req.url "/midonet-api/ports/#{port_id}/bgps"
-      req.headers['Content-Type'] = "application/vnd.org.midonet.Bgp-v1+json"
-      req.body = message.to_json
-    end
-  end
-
-  def call_add_route_for_uplink_port(router_id, message)
-    res = @connection.post do |req|
-      req.url "/midonet-api/routers/#{router_id}/routes"
-      req.headers['Content-Type'] = "application/vnd.org.midonet.Route-v1+json"
-      req.body = message.to_json
-    end
-  end
-
-  def call_get_bgp_connections(port_id)
-    res = @connection.get do |req|
-      req.url "/midonet-api/ports/#{port_id}/bgps"
-    end
-    output = JSON.parse(res.body)
-    return output
-  end
-
-  def call_advertise_route_to_bgp(bgp_id, message)
-    res = @connection.post do |req|
-      req.url "/midonet-api/bgps/#{bgp_id}/ad_routes"
-      req.headers['Content-Type'] = "application/vnd.org.midonet.AdRoute-v1+json"
-      req.body = message.to_json
-    end
-  end
-
-  def call_bind_port_to_interface(host_id, message)
-    res = @connection.post do |req|
-      req.url "/midonet-api/hosts/#{host_id}/ports"
-      req.headers['Content-Type'] = "application/vnd.org.midonet.HostInterfacePort-v1+json"
-      req.body = message.to_json
-    end
-  end
-
-  def call_create_stateful_port_group(message)
-    res = @connection.post do |req|
-      req.url "/midonet-api/port_groups"
-      req.headers['Content-Type'] = "application/vnd.org.midonet.PortGroup-v1+json"
-      req.body = message.to_json
-    end
-    return call_get_stateful_port_group()
-  end
-
-  def call_add_ports_to_port_group(port_group_id, message)
-    res = @connection.post do |req|
-      req.url "/midonet-api/port_groups/#{port_group_id}/ports"
-      req.headers['Content-Type'] = "application/vnd.org.midonet.PortGroupPort-v1+json"
-      req.body = message.to_json
-    end
-  end
-
-  def call_delete_stateful_port_group(port_group_id)
-    res = @connection.delete do |req|
-      req.url "/midonet-api/port_groups/#{port_group_id}"
-    end
-  end
-
-  private :call_add_bgp_to_port
-          :call_add_ports_to_port_group
-          :call_add_route_for_uplink_port
-          :call_advertise_route_to_bgp
-          :call_bind_port_to_interface
-          :call_create_stateful_port_group
-          :call_create_uplink_port
-          :call_delete_stateful_port_group
-          :call_delete_uplink_port
-          :call_get_bgp_connections
-          :call_get_host
-          :call_get_stateful_port_group
-          :call_get_provider_router
-          :call_get_tenant
-          :call_get_uplink_port
-          :define_connection
-end
diff --git a/lib/puppet/provider/midonet_gateway_bgp/midonet_api_caller.rb b/lib/puppet/provider/midonet_gateway_bgp/midonet_api_caller.rb
new file mode 100644
index 0000000..62aca34
--- /dev/null
+++ b/lib/puppet/provider/midonet_gateway_bgp/midonet_api_caller.rb
@@ -0,0 +1,217 @@
+if RUBY_VERSION == '1.8.7'
+    require 'rubygems'
+end
+
+require 'uri'
+require 'faraday'
+require 'json'
+
+Puppet::Type.type(:midonet_gateway_bgp).provide(:midonet_api_caller) do
+
+  def create
+
+    define_connection(resource[:midonet_api_url])
+
+    # Get the edge router uuid
+    provider_router = call_get_provider_router()[0]
+    provider_router_id = provider_router['id']
+
+    # Assign local ASN to the provider router
+    asn = provider_router['asNumber']
+    call_assign_asn(provider_router_id, resource[:bgp_local_as_number]) unless asn == resource[:bgp_local_as_number]
+
+    # Sync BGP peers
+    bgp_neighbors = call_get_bgp_peers(provider_router_id)
+    m = Array.new
+    bgp_neighbors.each do |bgp_neighbor|
+      n = { "ip_address" => bgp_neighbor["address"],
+        "remote_asn" => bgp_neighbor["asNumber"] }
+      m << n
+    end
+    tbd_peers = m - resource[:bgp_neighbors]
+    tba_peers = resource[:bgp_neighbors] - m
+
+    tba_peers.each { |a| call_add_bgp_peer(provider_router_id, a['ip_address'], a['remote_asn']) }
+    tbd_peers.each do |d|
+      bgp_peer_id = bgp_neighbors.select { |bgp_neighbor| bgp_neighbor['asNumber'] == d['remote_asn'] }[0]["id"]
+      call_delete_bgp_peer(bgp_peer_id)
+    end
+
+    # Advertise floating IP networks
+    bgp_advertised_networks = call_get_bgp_networks(provider_router_id)
+    j = Array.new
+    bgp_advertised_networks.each do |bgp_advertised_network|
+      k = [ bgp_advertised_network["subnetAddress"], bgp_advertised_network["subnetLength"] ].join("/")
+      j << k
+    end
+    tbd_bgp_networks = j - resource[:bgp_advertised_networks]
+    tba_bgp_networks = resource[:bgp_advertised_networks] - j
+    tba_bgp_networks.each { |a| call_advertise_bgp_network(provider_router_id, a) }
+    tbd_bgp_networks.each do |d|
+      bgp_network_id = bgp_advertised_networks.select { |bgp_advertised_network| bgp_advertised_network['subnetAddress'] == d.split("/")[0] && bgp_advertised_network['subnetLength'] == d.split("/")[1] }[0]["id"]
+      call_delete_bgp_network(provider_router_id, bgp_network_id)
+    end
+  end
+
+  def destroy
+
+    define_connection(resource[:midonet_api_url])
+
+    # Get the edge router uuid
+    provider_router_id = call_get_provider_router()[0]['id']
+
+    # "Unset" asNumber by setting it to -1 (default value)
+    call_assign_asn(provider_router_id, "-1")
+
+    # Remove BGP peers from router
+    bgp_peers = call_get_bgp_peers(provider_router_id)
+    bgp_peers.each do |bgp_peer|
+      call_delete_bgp_peer(bgp_peer["id"])
+    end
+
+    # De-advertise floating IP networks
+    bgp_networks = call_get_bgp_networks(provider_router_id)
+    bgp_networks.each do |bgp_network|
+      call_delete_bgp_network(bgp_network)
+    end
+  end
+
+  def exists?
+
+    define_connection(resource[:midonet_api_url])
+
+    # Get the edge router uuid
+    provider_router = call_get_provider_router()[0]
+    provider_router_id = provider_router['id']
+    result_array = Array.new
+
+    # Check if local ASN is the same
+    result_array.push(provider_router["asNumber"] == resource[:bgp_local_as_number])
+    # Check if BGP neighbors are the same
+    bgp_neighbors = call_get_bgp_peers(provider_router_id)
+    m = Array.new
+    bgp_neighbors.each do |bgp_neighbor|
+      n = { "ip_address" => bgp_neighbor["address"],
+        "remote_asn" => bgp_neighbor["asNumber"] }
+      m << n
+    end
+    result_array.push(m == resource[:bgp_neighbors])
+    # Check if advertised networks are the same
+    bgp_advertised_networks = call_get_bgp_networks(provider_router_id)
+    j = Array.new
+    bgp_advertised_networks.each do |bgp_advertised_network|
+      k = [ bgp_advertised_network["subnetAddress"], bgp_advertised_network["subnetLength"] ].join("/")
+      j << k
+    end
+    result_array.push(j == resource[:bgp_advertised_networks])
+
+    # Test if all tests are positive
+    return result_array.uniq == [true]
+
+  end
+
+  def define_connection(url)
+
+    @connection = Faraday.new(:url => url,
+                              :ssl => { :verify =>false }) do |builder|
+        builder.request(:retry, {
+          :max        => 5,
+          :interval   => 0.05,
+          :exceptions => [
+            Faraday::Error::TimeoutError,
+            Faraday::ConnectionFailed,
+            Errno::ETIMEDOUT,
+            'Timeout::Error',
+          ],
+        })
+        builder.request(:basic_auth, resource[:username], resource[:password])
+        builder.adapter(:net_http)
+    end
+
+    @connection.headers['X-Auth-Token'] = call_get_token()
+  end
+
+  def call_get_token()
+    res = @connection.get do |req|
+      req.url "/midonet-api/login"
+    end
+    return JSON.parse(res.body)['key']
+  end
+
+  def call_get_provider_router()
+    res = @connection.get do |req|
+      req.url "/midonet-api/routers"
+    end
+    output = JSON.parse(res.body)
+    provider_router = output.select { |r| r['name'] == resource[:router]}
+    raise "Router #{resource[:router]} does not exist" if provider_router.empty?
+    return provider_router
+  end
+
+  def call_assign_asn( provider_router_id, bgp_local_as_number )
+    res = @connection.post do |req|
+      req.url "/midonet-api/routers"
+      req.headers['Content-Type'] = "application/vnd.org.midonet.Router-v3+json"
+      req.body = { 'id' => provider_router_id,
+                   'asNumber' => bgp_local_as_number }.to_json
+    end
+  end
+
+  def call_add_bgp_peer( provider_router_id, ip_address, remote_asn )
+    res = @connection.post do |req|
+      req.url "/midonet-api/#{provider_router_id}/bgp_peers"
+      req.headers['Content-Type'] = "application/vnd.org.midonet.BgpPeer-v1+json"
+      req.body = { 'address' => ip_address,
+                   'asNumber' => remote_asn }.to_json
+    end
+  end
+
+  def call_advertise_bgp_network( provider_router_id, bgp_advertised_network )
+    subnet_address, subnet_length = bgp_advertised_network.split("/")
+    res = @connection.post do |req|
+      req.url "/midonet-api/#{provider_router_id}/bgp_networks"
+      req.headers['Content-Type'] = "application/vnd.org.midonet.BgpNetwork-v1+json"
+      req.body = { 'subnetAddress' => subnet_address,
+                   'subnetLength'  => subnet_length }.to_json
+    end
+  end
+
+  def call_delete_bgp_peer(bgp_peer_id)
+    res = @connection.delete do |req|
+      req.url "/midonet-api/bgp_peers/#{bgp_peer_id}"
+    end
+  end
+
+  def call_delete_bgp_network(bgp_network)
+    res = @connection.delete do |req|
+      req.url "/midonet-api/bgp_networks/#{bgp_network}"
+    end
+  end
+
+  def call_get_bgp_peers(provider_router_id)
+    res = @connection.get do |req|
+      req.url "/midonet-api/routers/#{provider_router_id}/bgp_peers"
+    end
+    output = JSON.parse(res.body)
+    return output
+  end
+
+  def call_get_bgp_networks(provider_router_id)
+    res = @connection.get do |req|
+      req.url "/midonet-api/routers/#{provider_router_id}/bgp_networks"
+    end
+    output = JSON.parse(res.body)
+    return output.map { |e| e["id"] }
+  end
+
+  private :call_get_provider_router
+          :define_connection
+          :call_assign_asn
+          :call_add_bgp_peer
+          :call_get_bgp_networks
+          :call_get_bgp_peers
+          :call_delete_bgp_network
+          :call_delete_bgp_peer
+          :call_advertise_bgp_network
+
+end
diff --git a/lib/puppet/type/midonet_gateway.rb b/lib/puppet/type/midonet_gateway.rb
deleted file mode 100644
index 0cd8055..0000000
--- a/lib/puppet/type/midonet_gateway.rb
+++ /dev/null
@@ -1,159 +0,0 @@
-require 'uri'
-require 'facter'
-
-Puppet::Type.newtype(:midonet_gateway) do
-  @doc = %q{BGP Uplink Configuration
-
-      Example:
-
-        midonet_gateway {'hostname':
-           midonet_api_url => 'http://controller:8080',
-           username        => 'admin',
-           password        => 'admin',
-           tenant_name     => 'admin',
-           interface       => 'eth1',
-           local_as        => '64512',
-           bgp_port        => { 'port_address' => '198.51.100.2', 'net_prefix' => '198.51.100.0', 'net_length' => '30'},
-           remote_peers    => [ { 'as' => '64513', 'ip' => '198.51.100.1' },
-                                    { 'as' => '64513', 'ip' => '203.0.113.1' } ],
-           advertise_net   => [ { 'net_prefix' => '192.0.2.0', 'net_length' => '24' } ]
-        }
-  }
-
-  ensurable
-
-  autorequire(:package) do ['midolman'] end
-
-  newparam(:hostname, :namevar => true) do
-    desc 'Hostname of the host that will act as gateway in a MidoNet managed cloud'
-    # Regex obtained from StackOverflow question:
-    # http://stackoverflow.com/questions/1418423/the-hostname-regex
-    validate do |value|
-      unless value =~ /^(?=.{1,255}$)[0-9A-Za-z](?:(?:[0-9A-Za-z]|-){0,61}[0-9A-Za-z])?(?:\.[0-9A-Za-z](?:(?:[0-9A-Za-z]|-){0,61}[0-9A-Za-z])?)*\.?$/
-        raise ArgumentError, "'%s' is not a valid hostname" % value
-      end
-    end
-  end
-
-  newparam(:midonet_api_url) do
-    desc 'MidoNet API endpoint to connect to'
-    validate do |value|
-      unless value =~ /\A#{URI::regexp(['http', 'https'])}\z/
-        raise ArgumentError, "'%s' is not a valid URI" % value
-      end
-    end
-  end
-
-  newparam(:username) do
-    desc 'Username of the admin user in keystone'
-    defaultto 'admin'
-    validate do |value|
-      unless value =~ /\w+$/
-        raise ArgumentError, "'%s' is not a valid username" % value
-      end
-    end
-  end
-
-  newparam(:password) do
-    desc 'Password of the admin user in keystone'
-    defaultto 'admin'
-    validate do |value|
-      unless value =~ /\w+$/
-        raise ArgumentError, "'%s' is not a valid password" % value
-      end
-    end
-  end
-
-  newparam(:tenant_name) do
-    desc 'Tenant name of the admin user'
-    defaultto 'admin'
-    validate do |value|
-      unless value =~ /\w+$/
-        raise ArgumentError, "'%s' is not a tenant name" % value
-      end
-    end
-  end
-
-  newparam(:interface) do
-    desc "Physical interface where the MidoNet Provider Router's port is binded to"
-    defaultto 'eth0'
-    validate do |value|
-      unless value =~ /^\w+(.\d+)?$/
-        raise ArgumentError, "'%s' is not a valid interface" % value
-      end
-    end
-  end
-
-  newparam(:local_as) do
-    desc "Local AS number"
-    validate do |value|
-      unless value =~ /\d+/
-        raise ArgumentError, "'%s' is not a valid AS" % value
-      end
-    end
-  end
-
-  newparam(:remote_peers) do
-    desc "#to be filled"
-    defaultto []
-    validate do |value|
-      if value.class == Hash
-        value = [value]
-      end
-      value.each do |rp|
-        unless rp["as"] =~ /\d+/
-          raise ArgumentError, "'%s' is not a valid AS name" % rp["as"]
-        end
-        unless rp["ip"] =~ /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/
-          raise ArgumentError, "'%s' is not a valid IP address" % rp["ip"]
-        end
-      end
-    end
-  end
-
-  newparam(:bgp_port) do
-    desc "#to be filled"
-    validate do |value|
-      [:port_address, :net_prefix, :net_length].all? {|key| value.key? key}
-      unless value["port_address"] =~ /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/
-        raise ArgumentError, "'%s' is not a valid IP address" % value["port_address"]
-      end
-      unless value["net_prefix"] =~ /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/
-        raise ArgumentError, "'%s' is not a valid IPv4 network address" % value["net_prefix"]
-      end
-      unless value["net_length"] =~ /\d{2}/
-        raise ArgumentError, "'%s' is not a valid network prefix length" % value["net_length"]
-      end
-    end
-  end
-
-  newparam(:router) do
-    desc "The MidoNet's internal Provider router that acts as the gateway router of the cloud"
-    defaultto 'MidoNet Provider Router'
-    validate do |value|
-      unless value =~ /\w+$/
-        raise ArgumentError, "'%s' is not a valid router name" % value
-      end
-    end
-  end
-
-  newparam(:advertise_net) do
-    desc 'Floating IP network to be avertised to the BGP peers'
-    defaultto []
-    validate do |value|
-      if value.class == Hash
-        value = [value]
-      end
-      value.each do |an|
-        unless an["net_prefix"] =~ /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/
-          raise ArgumentError, "'%s' is not a valid IPv4 network address" % an["net_prefix"]
-        end
-        unless an["net_length"] =~ /\d{2}/
-          raise ArgumentError, "'%s' is not a valid network prefix length" % an["net_length"]
-        end
-      end
-    end
-  end
-
-end
-
diff --git a/lib/puppet/type/midonet_gateway_bgp.rb b/lib/puppet/type/midonet_gateway_bgp.rb
new file mode 100644
index 0000000..bff0a7f
--- /dev/null
+++ b/lib/puppet/type/midonet_gateway_bgp.rb
@@ -0,0 +1,150 @@
+require 'uri'
+require 'facter'
+
+Puppet::Type.newtype(:midonet_gateway_bgp) do
+  @doc = %q{This type is used to configure a gateway node, considering the
+  uplink is of type BGP. What it does:
+    1) Assign an AS number to the edge router
+    2) Assign BGP peers
+    3) Advertise BGP networks
+
+    Usage:
+
+    midonet_gateway_bgp { 'edge_router':
+      bgp_local_as_number     => '65432',
+      bgp_advertised_networks => [
+        '200.0.0.0/24',
+        '12.0.140.0/16',
+      ],
+      bgp_neighbors           => [
+        {
+          'ip_address' => '200.0.1.1',
+          'remote_asn' => '34512'
+        },
+        {
+          'ip_address' => '12.0.140.1',
+          'remote_asn' => '24125'
+        }
+      ],
+      midonet_api_url         => 'http://controller:8181',
+      username                => 'admin',
+      password                => 'admin',
+    }
+  }
+
+  ensurable
+
+  newparam(:bgp_local_as_number) do
+    desc "AS number of the local BGP autonomous system.  If you have an RIR
+      registered AS number, use it.  If you don't have an RIR registered AS
+      number, use any of the RFC 1930's reserved AS number.  It should be an
+      integer.  Only applicable when uplink_type=='bgp'."
+    validate do |value|
+      unless value =~ /^\d+$/
+        raise ArgumentError, "'%s' is not a valid AS number" % value
+      end
+    end
+  end
+
+  newparam(:bgp_advertised_networks) do
+    desc "Networks advertised to the remote BGP autonomous system.  This usually
+      should be the same as floating IP networks defined in neutron.  It should
+      be an array of strings, each of which should be a network address
+      in either \"IP/Prefix_Length\" notation (\"192.0.2.0/24\") or
+      \"IP/Subnet_Mask\" nonation(\"192.0.2.0/255.255.255.0\").  Only applicable
+      when uplink_type=='bgp'.  A more elaborate example will be:
+
+        [ '192.0.2.128/25', '198.51.100.128/25', '203.0.113.128/25' ]"
+    validate do |value|
+      unless value.class == Array && value.length > 0
+        raise ArgumentError, "#{value} is not an Array"
+      else
+        value.each do |e|
+          unless e.class == String && e =~ /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\/\d+$/
+            raise ArgumentError, "#{e} is not a valid IP address"
+          end
+        end
+      end
+    end
+  end
+
+  newparam(:bgp_neighbors) do
+    desc " An array containing hashes that describe a remote BGP peer. These
+    hashes must have two parameters:
+     - 'ip_address': IP address of the peer
+     - 'remote_asn': Peer's AS number
+
+    A real life example will look like:
+    [
+      {
+        'ip_address' => '203.0.113.1',
+        'remote_asn' => '64513'
+      },
+      {
+        'ip_address' => '198.51.100.1',
+        'remote_asn' => '64514'
+      }
+    ]
+    "
+    validate do |value|
+      unless value.class == Array && value.length > 0
+        raise ArgumentError, "'%s' is not an array" % value
+      else
+        value.each do |e|
+          unless e.class == Hash && e.key?("ip_address") && e.key?("remote_asn")
+            raise ArgumentError, "'%s' doesn't contain parameters 'ip_address' and/or 'remote_asn'" % value
+          else
+            unless e["ip_address"] =~ /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/
+              raise ArgumentError, "#{e['ip_address']} is not a valid IP address"
+            end
+            unless e["remote_asn"] =~ /^\d+$/
+              raise ArgumentError, "#{e['remote_asn']} is not a valid AS number"
+            end
+          end
+        end
+      end
+    end
+  end
+
+  autorequire(:package) do ['midolman'] end
+
+  newparam(:midonet_api_url) do
+    desc 'MidoNet API endpoint to connect to'
+    validate do |value|
+      unless value =~ /\A#{URI::regexp(['http', 'https'])}\z/
+        raise ArgumentError, "'%s' is not a valid URI" % value
+      end
+    end
+  end
+
+  newparam(:username) do
+    desc 'Username of the admin user in keystone'
+    defaultto 'admin'
+    validate do |value|
+      unless value =~ /\w+$/
+        raise ArgumentError, "'%s' is not a valid username" % value
+      end
+    end
+  end
+
+  newparam(:password) do
+    desc 'Password of the admin user in keystone'
+    defaultto 'admin'
+    validate do |value|
+      unless value =~ /\w+$/
+        raise ArgumentError, "'%s' is not a valid password" % value
+      end
+    end
+  end
+
+  newparam(:router, :namevar => true) do
+    desc "The MidoNet's internal Provider router that acts as the gateway router of the cloud"
+    defaultto 'MidoNet Provider Router'
+    validate do |value|
+      unless value =~ /\w+$/
+        raise ArgumentError, "'%s' is not a valid router name" % value
+      end
+    end
+  end
+
+end
diff --git a/manifests/gateway/static.pp b/manifests/gateway/static.pp
new file mode 100644
index 0000000..42d36b5
--- /dev/null
+++ b/manifests/gateway/static.pp
@@ -0,0 +1,127 @@
+# == Class: midonet::gateway::static
+#
+# Set up a fake uplink with static routing on a gateway node
+#
+# === Parameters
+#
+# [*network_id*]
+#   (Mandatory) Name of the bridge that will be created through midonet-cli
+#
+# [*cidr*]
+#   (Mandatory) Network that will be assigned to the fake uplink
+#
+# [*gateway_ip*]
+#   (Mandatory) Gateway IP through which the packets will go
+#
+# [*service_host*]
+#   (Mandatory) Host where the Midonet API runs
+#
+# [*service_dir*]
+#   (Mandatory) Folder on which to place the pidfile and some other temporary
+#   files for the well functioning of this script (ex: /tmp/status)
+#
+# [*zookeeper_hosts*]
+#   (Mandatory) Comma-separated list of zookeeper hosts. These are a hash consisting of two
+#   fields, 'ip' and 'port'. Example: [ { 'ip' => '12.153.140.2', 'port' => '2181'}]
+#
+# [*api_port*]
+#   (Mandatory) Port that the Midonet API binds
+#
+# [*scripts_dir*]
+#   (Optional) Path where to place the necessary scripts
+#
+# [*ensure_scripts*]
+#   (Optional) Status of the scripts
+#
+# [*mido_db_user*]
+#   (Optional) Username to authenticate against the DB
+#
+# [*mido_db_password*]
+#   (Optional) Password to authenticate against the DB
+#
+# === Examples
+#
+# The easiest way to run the class is:
+#
+#      class { 'midonet::gateway::static':
+#        network_id => 'example_netid',
+#        cidr => '200.0.0.1/24',
+#        gateway_ip => '200.0.0.1',
+#        service_host => '127.0.0.1',
+#        service_dir => '/tmp/status',
+#        zookeeper_hosts => [
+#          {
+#            'ip'=>'127.0.0.1',
+#            'port'=>'2181'
+#          }
+#        ],
+#        api_port => '8181'
+#      }
+#
+# === Authors
+#
+# Midonet (http://midonet.org)
+#
+# === Copyright
+#
+# Copyright (c) 2016 Midokura SARL, All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+class midonet::gateway::static (
+  $network_id,
+  $cidr,
+  $gateway_ip,
+  $service_host,
+  $service_dir,
+  $zookeeper_hosts,
+  $api_port,
+  $scripts_dir       = '/tmp',
+  $uplink_script     = 'create_fake_uplink_l2.sh',
+  $midorc_script     = 'midorc',
+  $functions_script  = 'functions',
+  $ensure_scripts    = 'present',
+  $mido_db_user      = 'admin',
+  $mido_db_password  = 'admin',
+) {
+
+  # Install screen, as it's needed by the script
+  package { 'screen': ensure => installed }
+
+  # Place script and helper files before executing it
+  file { 'fake_uplink_script':
+    ensure  => $ensure_scripts,
+    path    => "${scripts_dir}/create_fake_uplink_l2.sh",
+    content => template('midonet/gateway/create_fake_uplink_l2.sh.erb'),
+  }
+  file { 'midorc':
+    ensure  => $ensure_scripts,
+    path    => "${scripts_dir}/midorc",
+    content => template('midonet/gateway/midorc.erb'),
+  }
+  file { 'functions':
+    ensure  => $ensure_scripts,
+    path    => "${scripts_dir}/functions",
+    source  => 'puppet:///modules/midonet/gateway/functions',
+    require => Package['screen'],
+  }
+
+  # Finally, execute the script
+  exec { "/bin/bash ${scripts_dir}/create_fake_uplink_l2.sh":
+    require => [
+      File['fake_uplink_script', 'midorc', 'functions'],
+      Package['python-midonetclient'],
+    ]
+  }
+}
diff --git a/spec/classes/midonet_cluster_spec.rb b/spec/classes/midonet_cluster_spec.rb
deleted file mode 100644
index adb95f2..0000000
--- a/spec/classes/midonet_cluster_spec.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-require 'spec_helper'
-
-describe 'midonet::cluster' do
-  context 'with parameters' do
-    let :facts do
-      {
-        :osfamily       => 'Debian',
-        :lsbdistid      => 'Ubuntu',
-        :lsbdistrelease => '16.04',
-      }
-    end
-    let :params do
-      {
-        :zookeeper_hosts       => ['{ "ip" => "127.0.0.1", "port" => "2181" }'],
-        :cassandra_servers      => [ '127.0.0.1' ],
-        :cassandra_rep_factor => '3',
-        :keystone_admin_token => 'ADMIN_TOKEN',
-        :keystone_host => '127.0.0.1',
-      }
-    end
-    it { is_expected.to contain_class('midonet::cluster::install') }
-    it { is_expected.to contain_class('midonet::cluster::run') }
-  end
-end
diff --git a/spec/classes/midonet_gateway_static_spec.rb b/spec/classes/midonet_gateway_static_spec.rb
new file mode 100644
index 0000000..ac64d4f
--- /dev/null
+++ b/spec/classes/midonet_gateway_static_spec.rb
@@ -0,0 +1,29 @@
+require 'spec_helper'
+
+describe 'midonet::gateway::static' do
+  context 'with parameters' do
+    let :facts do
+      {
+        :osfamily       => 'Debian',
+        :lsbdistid      => 'Ubuntu',
+        :lsbdistrelease => '16.04',
+      }
+    end
+    let :params do
+      {
+        :network_id => 'example_netid',
+        :cidr => '200.0.0.1/24',
+        :gateway_ip => '200.0.0.1',
+        :service_host => '127.0.0.1',
+        :service_dir => '/tmp/status',
+        :zookeeper_hosts => [ { 'ip' => '127.0.0.1', 'port' => '2181' } ],
+        :api_port => '8181'
+      }
+    end
+    it { is_expected.to contain_package('screen').with_ensure('installed') }
+    it { is_expected.to contain_file('fake_uplink_script').with_ensure('present') }
+    it { is_expected.to contain_file('midorc').with_ensure('present') }
+    it { is_expected.to contain_file('functions').with_ensure('present') }
+    it { is_expected.to contain_exec('/bin/bash /tmp/create_fake_uplink_l2.sh') }
+  end
+end
diff --git a/spec/unit/puppet/provider/midonet_gateway/midonet_api_caller_spec.rb b/spec/unit/puppet/provider/midonet_gateway/midonet_api_caller_spec.rb
index d70eec7..3d57309 100644
--- a/spec/unit/puppet/provider/midonet_gateway/midonet_api_caller_spec.rb
+++ b/spec/unit/puppet/provider/midonet_gateway/midonet_api_caller_spec.rb
@@ -1,158 +1,108 @@
 require 'spec_helper'
 
-describe Puppet::Type.type(:midonet_gateway).provider(:midonet_api_caller) do
+describe Puppet::Type.type(:midonet_gateway_bgp).provider(:midonet_api_caller) do
 
   let(:provider) { described_class.new(resource) }
 
-  let(:resource) { Puppet::Type.type(:midonet_gateway).new(
-    {
-      :ensure              => :present,
-      :hostname            => 'compute.midonet',
-      :midonet_api_url     => 'http://controller:8080',
-      :username            => 'admin',
-      :password            => 'admin',
-      :interface           => 'eth0',
-      :local_as            => '64512',
-      :bgp_port            => { 'port_address' => '198.51.100.2', 'net_prefix' => '198.51.100.0', 'net_length' => '30' },
-      :remote_peers        => [ { 'as' => '64513', 'ip' => '198.51.100.1' },
-                                { 'as' => '64513', 'ip' => '203.0.113.1' } ],
-      :advertise_net       => [ { 'net_prefix' => '192.0.2.0', 'net_length' => '24' } ]
-    }
-  )}
+  let(:resource) do
+    Puppet::Type::type(:midonet_gateway_bgp).new(
+    :router                  => 'edge_router',
+    :midonet_api_url         => 'http://controller:8080/midonet-api',
+    :username                => 'admin',
+    :password                => 'admin',
+    :bgp_local_as_number     => '64512',
+    :bgp_neighbors           => [
+      {
+        'ip_address' => '200.100.98.7',
+        'remote_asn' => '45237',
+      },
+      {
+        'ip_address' => '182.24.63.2',
+        'remote_asn' => '45235',
+      },
+    ],
+    :bgp_advertised_networks => [ '200.0.0.0/24', '200.0.20.0/24' ] )
+  end
 
   describe 'BGP configuration happy path' do
-    # - Create virtual ports for each remote BGP peer
-    # - Configure BGP on the virtual ports or remove config if needed
-    # - Advertise routes
-    # - Bind virtual ports to physical network interfaces
-    # - Configure stateful port group and delete it if needed
-    # - Add ports to the port group and remove them if needed
 
+    # 1) Assign AS number to router
+    # 2) Assign BGP neighbors to routers
+    # 3) Advertise floating IP network
+    # 4) Delete BGP neighbors
+    # 5) De-advertise networks
+
+    # Other parameters are returned by default, but only this one is needed for
+    # testing purposes
+    # More info: https://docs.midonet.org/docs/latest/rest-api/content/router.html
     let(:routers) {
       [
         {
          "id"   => "e6a53892-03bf-4f16-8212-e4d76ad204e3",
-         "name" => "MidoNet Provider Router"
+         "name" => "edge_router"
         }
       ]
     }
-
-    let(:ports) {
+    # Other parameters are returned by default, but only this one is needed for
+    # testing purposes
+    # More info: https://docs.midonet.org/docs/latest/rest-api/content/bgp-peer.html
+    let(:bgp_peers) {
       [
         {
-          "hostId"        => "b3f2f63e-02a6-459a-af0f-44eeac441a09",
-          "interfaceName" => "eth0",
-          "id"            => "20b169b1-ec0a-4639-8479-44b63e016935"
+          "id" => "4a5e4356-3417-4c60-9cf8-7516aedb7067",
         }
       ]
     }
-
-    let(:bgps) {
+    # Other parameters are returned by default, but only this one is needed for
+    # testing purposes
+    # More info: https://docs.midonet.org/docs/latest/rest-api/content/bgp-network.html
+    let(:bgp_networks) {
       [
         {
-          "id"          => "4a5e4356-3417-4c60-9cf8-7516aedb7067",
-          "localAS"     => "64512",
-          "peerAS"      => "64513",
-          "peerAddr"    => "198.51.100.1",
-          "portId"      => "f9e61b88-0a26-4d56-8f47-eb5da37225e0"
-        }
-      ]
-    }
-
-    let(:port_groups) {
-      [
-        {
-          "id"       => "711401b7-bf6f-4afd-8ab2-94b4342a0310",
-          "name"     => "uplink-spg",
-          "stateful" => "true"
-        }
-      ]
-    }
-
-    let(:hosts) {
-      [
-        {
-          "id"   => "b3f2f63e-02a6-459a-af0f-44eeac441a09",
-          "name" => "compute.midonet"
-        }
-      ]
-    }
-
-    let(:tenants) {
-      [
-        {
-          "id"   => "4486908d-8e15-4f01-b3b4-86f9def0fa04",
-          "name" => "4486908d-8e15-4f01-b3b4-86f9def0fa04"
+          "id" => "4a5e4356-3417-4c60-9cf8-7516abcd1234",
         }
       ]
     }
 
     before :each do
-      allow(provider).to receive(:call_create_uplink_port).and_return(ports)
-      allow(provider).to receive(:call_get_provider_router).and_return(routers)
-      allow(provider).to receive(:call_get_host_id).and_return(hosts[0]['id'])
-      allow(provider).to receive(:call_get_host).and_return(hosts)
-      allow(provider).to receive(:call_add_bgp_to_port)
-      allow(provider).to receive(:call_get_bgp_connections).and_return(bgps)
-      allow(provider).to receive(:call_advertise_route_to_bgp)
-      allow(provider).to receive(:call_bind_port_to_interface)
-      allow(provider).to receive(:call_get_stateful_port_group).and_return(port_groups)
-      allow(provider).to receive(:call_add_ports_to_port_group)
-      allow(provider).to receive(:call_delete_uplink_port).and_return(ports)
-      allow(provider).to receive(:call_unbind_port_from_interface)
-      allow(provider).to receive(:call_remove_ports_from_port_group)
-      allow(provider).to receive(:call_get_uplink_port).and_return(ports)
-      allow(provider).to receive(:call_add_route_for_uplink_port)
       allow(provider).to receive(:call_get_token).and_return('thisisafaketoken')
-      allow(provider).to receive(:call_get_tenant).and_return(tenants)
+      allow(provider).to receive(:call_get_provider_router).and_return(routers)
+      allow(provider).to receive(:call_assign_asn)
+      allow(provider).to receive(:call_add_bgp_peer)
+      allow(provider).to receive(:call_advertise_bgp_network)
+      allow(provider).to receive(:call_get_bgp_peers).and_return(bgp_peers)
+      allow(provider).to receive(:call_delete_bgp_peer)
+      allow(provider).to receive(:call_get_bgp_networks).and_return(bgp_networks.map { |e| e['id'] })
+      allow(provider).to receive(:call_delete_bgp_network)
     end
 
-    it 'creates virtual ports for each remote BGP peer, advertises routes,
-      binds virtual ports, configures stateful port group and adds ports to it' do
-      # Expectations over the 'create' call
+    it 'follows happy path (BGP)' do
       expect(provider).to receive(:call_get_provider_router)
-      expect(provider).to receive(:call_create_uplink_port).with(routers[0]['id'], {'portAddress'    => resource[:bgp_port]['port_address'],
-                                                                                    'networkAddress' => resource[:bgp_port]['net_prefix'],
-                                                                                    'networkLength'  => resource[:bgp_port]['net_length'].to_i,
-                                                                                    'type' => 'Router'})
-      expect(provider).to receive(:call_get_bgp_connections).with(ports[0]['id'])
-      expect(provider).to receive(:call_add_bgp_to_port).with(ports[0]['id'], {'localAS'  => resource[:local_as],
-                                                                               'peerAS'   => resource[:remote_peers][0]['as'],
-                                                                               'peerAddr' => resource[:remote_peers][0]['ip']}).once
-      expect(provider).to receive(:call_add_bgp_to_port).with(ports[0]['id'], {'localAS'  => resource[:local_as],
-                                                                               'peerAS'   => resource[:remote_peers][1]['as'],
-                                                                               'peerAddr' => resource[:remote_peers][1]['ip']}).once
-      expect(provider).to receive(:call_add_route_for_uplink_port).with(routers[0]['id'], {'type'             => 'Normal',
-                                                                                           'srcNetworkAddr'   => '0.0.0.0',
-                                                                                           'srcNetworkLength' => 0,
-                                                                                           'dstNetworkAddr'   => resource[:bgp_port]['net_prefix'],
-                                                                                           'dstNetworkLength' => resource[:bgp_port]['net_length'].to_i,
-                                                                                           'weight'           => 100,
-                                                                                           'nextHopPort'      => ports[0]['id']})
-      expect(provider).to receive(:call_advertise_route_to_bgp).with(bgps[0]['id'], {'nwPrefix'     => resource[:advertise_net][0]['net_prefix'],
-                                                                                     'prefixLength' => resource[:advertise_net][0]['net_length']}).once
-      expect(provider).to receive(:call_bind_port_to_interface).with(hosts[0]['id'], {'interfaceName' => resource[:interface],
-                                                                                      'portId'        => '20b169b1-ec0a-4639-8479-44b63e016935'})
-      expect(provider).not_to receive(:call_create_stateful_port_group)
-      expect(provider).to receive(:call_get_stateful_port_group)
-      expect(provider).to receive(:call_add_ports_to_port_group).with(port_groups[0]['id'], {'portId' => '20b169b1-ec0a-4639-8479-44b63e016935'})
+      expect(provider).to receive(:call_assign_asn)
+      expect(provider).to receive(:call_add_bgp_peer).with(routers[0]['id'], '200.100.98.7', '45237')
+      expect(provider).to receive(:call_add_bgp_peer).with(routers[0]['id'], '182.24.63.2', '45235')
+      expect(provider).to receive(:call_advertise_bgp_network).with(routers[0]['id'], '200.0.0.0/24')
+      expect(provider).to receive(:call_advertise_bgp_network).with(routers[0]['id'], '200.0.20.0/24')
+      expect(provider).to receive(:call_get_bgp_peers).with(routers[0]['id'])
+      expect(provider).to receive(:call_delete_bgp_peer).with(bgp_peers[0]['id'])
+      expect(provider).to receive(:call_get_bgp_networks).with(routers[0]['id'])
+      expect(provider).to receive(:call_delete_bgp_network).with(bgp_networks[0]['id'])
       provider.create
-    end
-
-    it 'deletes uplink port, port_group, and unconfigures BGP' do
-      # Expectations over the 'destroy' call
-      expect(provider).to receive(:call_get_provider_router)
-      expect(provider).to receive(:call_get_uplink_port)
-      expect(provider).to receive(:call_delete_uplink_port).with(ports[0]['id'])
       provider.destroy
     end
 
-    it 'exists with default method returns' do
-      # Expectations over the 'exists' call
-      expect(provider).to receive(:call_get_provider_router).and_return(routers)
-      expect(provider).to receive(:call_get_host).and_return(hosts)
-      expect(provider).to receive(:call_get_uplink_port).with(routers[0]['id'], resource[:bgp_port]['port_address']).and_return(ports)
-      expect(provider.exists?).to eq true
+    it 'deletes BGP peers, and stops advertising the floating IP network' do
+      expect(provider).to receive(:call_get_provider_router)
+      expect(provider).to receive(:call_get_bgp_peers).with(routers[0]['id'])
+      expect(provider).to receive(:call_delete_bgp_peer).with(bgp_peers[0]['id'])
+      expect(provider).to receive(:call_get_bgp_networks).with(routers[0]['id'])
+      expect(provider).to receive(:call_delete_bgp_network).with(bgp_networks[0]['id'])
+      provider.destroy
+    end
+
+    it 'checks if a given provider router exists' do
+      expect(provider).to receive(:call_get_provider_router)
+      provider.exists?
     end
   end
 end
diff --git a/spec/unit/puppet/provider/midonet_gateway_bgp/midonet_api_caller_spec.rb b/spec/unit/puppet/provider/midonet_gateway_bgp/midonet_api_caller_spec.rb
new file mode 100644
index 0000000..3d57309
--- /dev/null
+++ b/spec/unit/puppet/provider/midonet_gateway_bgp/midonet_api_caller_spec.rb
@@ -0,0 +1,108 @@
+require 'spec_helper'
+
+describe Puppet::Type.type(:midonet_gateway_bgp).provider(:midonet_api_caller) do
+
+  let(:provider) { described_class.new(resource) }
+
+  let(:resource) do
+    Puppet::Type::type(:midonet_gateway_bgp).new(
+    :router                  => 'edge_router',
+    :midonet_api_url         => 'http://controller:8080/midonet-api',
+    :username                => 'admin',
+    :password                => 'admin',
+    :bgp_local_as_number     => '64512',
+    :bgp_neighbors           => [
+      {
+        'ip_address' => '200.100.98.7',
+        'remote_asn' => '45237',
+      },
+      {
+        'ip_address' => '182.24.63.2',
+        'remote_asn' => '45235',
+      },
+    ],
+    :bgp_advertised_networks => [ '200.0.0.0/24', '200.0.20.0/24' ] )
+  end
+
+  describe 'BGP configuration happy path' do
+
+    # 1) Assign AS number to router
+    # 2) Assign BGP neighbors to routers
+    # 3) Advertise floating IP network
+    # 4) Delete BGP neighbors
+    # 5) De-advertise networks
+
+    # Other parameters are returned by default, but only this one is needed for
+    # testing purposes
+    # More info: https://docs.midonet.org/docs/latest/rest-api/content/router.html
+    let(:routers) {
+      [
+        {
+         "id"   => "e6a53892-03bf-4f16-8212-e4d76ad204e3",
+         "name" => "edge_router"
+        }
+      ]
+    }
+    # Other parameters are returned by default, but only this one is needed for
+    # testing purposes
+    # More info: https://docs.midonet.org/docs/latest/rest-api/content/bgp-peer.html
+    let(:bgp_peers) {
+      [
+        {
+          "id" => "4a5e4356-3417-4c60-9cf8-7516aedb7067",
+        }
+      ]
+    }
+    # Other parameters are returned by default, but only this one is needed for
+    # testing purposes
+    # More info: https://docs.midonet.org/docs/latest/rest-api/content/bgp-network.html
+    let(:bgp_networks) {
+      [
+        {
+          "id" => "4a5e4356-3417-4c60-9cf8-7516abcd1234",
+        }
+      ]
+    }
+
+    before :each do
+      allow(provider).to receive(:call_get_token).and_return('thisisafaketoken')
+      allow(provider).to receive(:call_get_provider_router).and_return(routers)
+      allow(provider).to receive(:call_assign_asn)
+      allow(provider).to receive(:call_add_bgp_peer)
+      allow(provider).to receive(:call_advertise_bgp_network)
+      allow(provider).to receive(:call_get_bgp_peers).and_return(bgp_peers)
+      allow(provider).to receive(:call_delete_bgp_peer)
+      allow(provider).to receive(:call_get_bgp_networks).and_return(bgp_networks.map { |e| e['id'] })
+      allow(provider).to receive(:call_delete_bgp_network)
+    end
+
+    it 'follows happy path (BGP)' do
+      expect(provider).to receive(:call_get_provider_router)
+      expect(provider).to receive(:call_assign_asn)
+      expect(provider).to receive(:call_add_bgp_peer).with(routers[0]['id'], '200.100.98.7', '45237')
+      expect(provider).to receive(:call_add_bgp_peer).with(routers[0]['id'], '182.24.63.2', '45235')
+      expect(provider).to receive(:call_advertise_bgp_network).with(routers[0]['id'], '200.0.0.0/24')
+      expect(provider).to receive(:call_advertise_bgp_network).with(routers[0]['id'], '200.0.20.0/24')
+      expect(provider).to receive(:call_get_bgp_peers).with(routers[0]['id'])
+      expect(provider).to receive(:call_delete_bgp_peer).with(bgp_peers[0]['id'])
+      expect(provider).to receive(:call_get_bgp_networks).with(routers[0]['id'])
+      expect(provider).to receive(:call_delete_bgp_network).with(bgp_networks[0]['id'])
+      provider.create
+      provider.destroy
+    end
+
+    it 'deletes BGP peers, and stops advertising the floating IP network' do
+      expect(provider).to receive(:call_get_provider_router)
+      expect(provider).to receive(:call_get_bgp_peers).with(routers[0]['id'])
+      expect(provider).to receive(:call_delete_bgp_peer).with(bgp_peers[0]['id'])
+      expect(provider).to receive(:call_get_bgp_networks).with(routers[0]['id'])
+      expect(provider).to receive(:call_delete_bgp_network).with(bgp_networks[0]['id'])
+      provider.destroy
+    end
+
+    it 'checks if a given provider router exists' do
+      expect(provider).to receive(:call_get_provider_router)
+      provider.exists?
+    end
+  end
+end
diff --git a/spec/unit/puppet/type/midonet_gateway_bgp_spec.rb b/spec/unit/puppet/type/midonet_gateway_bgp_spec.rb
new file mode 100644
index 0000000..7291e64
--- /dev/null
+++ b/spec/unit/puppet/type/midonet_gateway_bgp_spec.rb
@@ -0,0 +1,73 @@
+require 'spec_helper'
+require 'puppet'
+require 'puppet/type/midonet_gateway_bgp'
+require 'facter'
+
+describe Puppet::Type::type(:midonet_gateway_bgp) do
+
+  context 'on default values (bgp)' do
+    let(:resource) do
+      Puppet::Type::type(:midonet_gateway_bgp).new(
+      :router                  => 'edge_router',
+      :midonet_api_url         => 'http://controller:8080/midonet-api',
+      :username                => 'admin',
+      :password                => 'admin',
+      :bgp_local_as_number     => '64512',
+      :bgp_neighbors           => [
+        {
+          'ip_address' => '200.100.98.7',
+          'remote_asn' => '45237',
+        },
+        {
+          'ip_address' => '182.24.63.2',
+          'remote_asn' => '45235',
+        },
+      ],
+      :bgp_advertised_networks => [ '200.0.0.0/24', '200.0.20.0/24' ] )
+    end
+
+    it 'assign the default values' do
+      expect(resource[:username]).to eq 'admin'
+      expect(resource[:password]).to eq 'admin'
+      expect(resource[:router]).to eq 'edge_router'
+      expect(resource[:bgp_local_as_number]).to eq '64512'
+    end
+  end
+
+  context 'on invalid api url' do
+    it do
+      expect {
+        Puppet::Type.type(:midonet_gateway_bgp).new(
+        :router          => 'edge_router',
+        :midonet_api_url => '87.23.43.2:8080/midonet-api',
+        :username        => 'admin',
+        :password        => 'admin')
+      }.to raise_error(Puppet::ResourceError)
+    end
+  end
+
+  context 'on invalid bgp neighbors' do
+    it do
+      expect {
+        Puppet::Type.type(:midonet_gateway_bgp).new(
+        :router        => 'edge_router',
+        :bgp_neighbors => '["12.13.14.15"]',
+        :username      => 'admin',
+        :password      => 'admin')
+      }.to raise_error(Puppet::ResourceError)
+    end
+  end
+
+  context 'on advertising invalid networks' do
+    it do
+      expect {
+        Puppet::Type.type(:midonet_gateway_bgp).new(
+        :router                  => 'edge_router',
+        :bgp_advertised_networks => ["12.13.14.15", "11.33.44.55/12"],
+        :username                => 'admin',
+        :password                => 'admin')
+      }.to raise_error(Puppet::ResourceError)
+    end
+  end
+
+end
diff --git a/spec/unit/puppet/type/midonet_gateway_spec.rb b/spec/unit/puppet/type/midonet_gateway_spec.rb
deleted file mode 100644
index 37907a8..0000000
--- a/spec/unit/puppet/type/midonet_gateway_spec.rb
+++ /dev/null
@@ -1,202 +0,0 @@
-require 'spec_helper'
-require 'puppet'
-require 'puppet/type/midonet_gateway'
-require 'facter'
-
-describe Puppet::Type::type(:midonet_gateway) do
-
-    context 'on default values' do
-        let(:resource) do
-            Puppet::Type::type(:midonet_gateway).new(
-                :hostname        => Facter['hostname'].value,
-                :midonet_api_url => 'http://controller:8080/midonet-api',
-                :username        => 'admin',
-                :password        => 'admin',
-                :interface       => 'eth0',
-                :local_as        => '64512',
-                :bgp_port        => { 'port_address' => '198.51.100.2', 'net_prefix' => '198.51.100.0', 'net_length' => '30'},
-                :remote_peers    => [ { 'as' => '64513', 'ip' => '198.51.100.1' },
-                                      { 'as' => '64513', 'ip' => '203.0.113.1' } ],
-                :advertise_net   => [ { 'net_prefix' => '192.0.2.0', 'net_length' => '24' } ])
-
-        end
-
-        it 'assign the default values' do
-            expect(resource[:username]).to eq 'admin'
-            expect(resource[:password]).to eq 'admin'
-            expect(resource[:tenant_name]).to eq 'admin'
-            expect(resource[:interface]).to eq 'eth0'
-            expect(resource[:router]).to eq 'MidoNet Provider Router'
-        end
-    end
-
-    context 'on invalid hostname' do
-        it do
-            expect {
-                Puppet::Type.type(:midonet_gateway).new(
-                    :hostname        => '_invalid_hostname.local',
-                    :midonet_api_url => 'http://87.23.43.2:8080/midonet-api',
-                    :username        => 'admin',
-                    :password        => 'admin')
-                }.to raise_error(Puppet::ResourceError)
-        end
-    end
-
-    context 'on invalid api url' do
-        it do
-            expect {
-                Puppet::Type.type(:midonet_gateway).new(
-                    :hostname        => Facter['hostname'].value,
-                    :midonet_api_url => '87.23.43.2:8080/midonet-api',
-                    :username        => 'admin',
-                    :password        => 'admin')
-                }.to raise_error(Puppet::ResourceError)
-        end
-    end
-
-    context 'on tenant_name valid value' do
-        let(:resource) do
-            Puppet::Type.type(:midonet_gateway).new(
-                :hostname        => Facter['hostname'].value,
-                :midonet_api_url => 'http://87.23.43.2:8080/midonet-api',
-                :username        => 'admin',
-                :password        => 'admin',
-                :tenant_name     => 'midokura')
-        end
-
-        it 'assign to it' do
-            expect(resource[:tenant_name]).to eq 'midokura'
-        end
-    end
-
-    context 'on valid interface name without vlan tag' do
-        let(:resource) do
-            Puppet::Type.type(:midonet_gateway).new(
-                :hostname        => Facter['hostname'].value,
-                :midonet_api_url => 'http://87.23.43.2:8080/midonet-api',
-                :username        => 'admin',
-                :password        => 'admin',
-                :interface       => 'eth0')
-        end
-
-        it 'assign to it' do
-            expect(resource[:interface]).to eq 'eth0'
-        end
-    end
-
-    context 'on valid interface name with vlan tag' do
-        let(:resource) do
-            Puppet::Type.type(:midonet_gateway).new(
-                :hostname        => Facter['hostname'].value,
-                :midonet_api_url => 'http://87.23.43.2:8080/midonet-api',
-                :username        => 'admin',
-                :password        => 'admin',
-                :interface       => 'eth0.9')
-        end
-
-        it 'assign to it' do
-            expect(resource[:interface]).to eq 'eth0.9'
-        end
-    end
-
-    context 'on invalid interface name' do
-        it  do
-          expect {
-            Puppet::Type.type(:midonet_gateway).new(
-                :hostname        => Facter['hostname'].value,
-                :midonet_api_url => 'http://87.23.43.2:8080/midonet-api',
-                :username        => 'admin',
-                :password        => 'admin',
-                :interface       => 'eth0.9a')
-          }.to raise_error(Puppet::ResourceError)
-        end
-    end
-
-    context 'on valid local AS name' do
-        let(:resource) do
-            Puppet::Type.type(:midonet_gateway).new(
-                :hostname        => Facter['hostname'].value,
-                :midonet_api_url => 'http://87.23.43.2:8080/midonet-api',
-                :username        => 'admin',
-                :password        => 'admin',
-                :local_as        => '64512')
-        end
-
-        it 'assign to it' do
-            expect(resource[:local_as]).to eq '64512'
-        end
-    end
-
-    context 'on invalid local AS name' do
-        it do
-            expect {
-                Puppet::Type.type(:midonet_gateway).new(
-                    :hostname        => Facter['hostname'].value,
-                    :midonet_api_url => 'http://87.23.43.2:8080/midonet-api',
-                    :username        => 'admin',
-                    :password        => 'admin',
-                    :local_as        => 'fake')
-                }.to raise_error(Puppet::ResourceError)
-        end
-    end
-
-    context 'on invalid BGP port' do
-        it do
-            expect {
-                Puppet::Type.type(:midonet_gateway).new(
-                    :hostname        => Facter['hostname'].value,
-                    :midonet_api_url => 'http://87.23.43.2:8080/midonet-api',
-                    :username        => 'admin',
-                    :password        => 'admin',
-                    :bgp_port        => { 'port_address' => '_198.51.100.2',
-                                          'net_prefix'  => '198.51.100.0',
-                                          'net_length'   => '30' })
-                }.to raise_error(Puppet::ResourceError)
-        end
-    end
-
-    context 'on invalid remote BGP peers AS name and IP' do
-        it do
-            expect {
-                Puppet::Type.type(:midonet_gateway).new(
-                    :hostname        => Facter['hostname'].value,
-                    :midonet_api_url => 'http://87.23.43.2:8080/midonet-api',
-                    :username        => 'admin',
-                    :password        => 'admin',
-                    :remote_peers    => [ { 'as' => 'fake',
-                                            'ip' => '_198.51.100.1' } ])
-                }.to raise_error(Puppet::ResourceError)
-        end
-    end
-
-    context 'on valid router name' do
-        let(:resource) do
-            Puppet::Type.type(:midonet_gateway).new(
-                :hostname        => Facter['hostname'].value,
-                :midonet_api_url => 'http://87.23.43.2:8080/midonet-api',
-                :username        => 'admin',
-                :password        => 'admin',
-                :router          => 'MidoNet Provider Router')
-        end
-
-        it 'assign to it' do
-            expect(resource[:router]).to eq 'MidoNet Provider Router'
-        end
-    end
-
-    context 'on invalid advertise network' do
-        it do
-            expect {
-                Puppet::Type.type(:midonet_gateway).new(
-                    :hostname        => Facter['hostname'].value,
-                    :midonet_api_url => 'http://87.23.43.2:8080/midonet-api',
-                    :username        => 'admin',
-                    :password        => 'admin',
-                    :advertise_net   => [ { 'net_prefix' => '_192.0.2.0',
-                                            'net_length' => '24' } ] )
-                }.to raise_error(Puppet::ResourceError)
-        end
-    end
-
-end
-
diff --git a/templates/gateway/create_fake_uplink_l2.sh.erb b/templates/gateway/create_fake_uplink_l2.sh.erb
new file mode 100644
index 0000000..95e1edd
--- /dev/null
+++ b/templates/gateway/create_fake_uplink_l2.sh.erb
@@ -0,0 +1,105 @@
+#!/usr/bin/env bash
+
+# Copyright 2016 Midokura SARL
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# This script creates the fake uplink assuming that midonet is running
+# correctly.  It takes the IP address CIDR as its argument which gets
+# routed into the MidoNet provider router.  CIDR is defaulted to
+# 172.24.4.0/24 with the gateway 172.24.4.1, but you can override by:
+#
+#      ./create_fake_uplink_l2.sh <network_id> 172.24.4.0/24 172.24.4.1
+# or
+#      CIDR=172.24.4.0/24 GATEWAY_IP=172.24.4.1 NETWORK_ID=<network_id> \
+#           ./create_fake_uplink.sh
+#
+
+function usage() {
+    echo "Usage: $0 <NETWORK_ID> <CIDR> <GATEWAY_IP>]" 1>&2;
+    exit 1;
+}
+
+NETWORK_ID=<%= @network_id %>
+CIDR=<%= @cidr %>
+GATEWAY_IP=<%= @gateway_ip %>
+
+if [ -z "${NETWORK_ID}" ] || [ -z "${CIDR}" ] || [ -z "${GATEWAY_IP}" ]; then
+    usage
+fi
+
+echo "NETWORK_ID = $NETWORK_ID"
+echo "CIDR = $CIDR"
+echo "GATEWAY_IP = $GATEWAY_IP"
+
+OLD_IFS=$IFS
+IFS='/'; read -ra CIDR_SPLIT <<< "$CIDR"
+NET_LEN=${CIDR_SPLIT[1]}
+IFS=$OLD_IFS
+
+# Save the top directory and source the functions and midorc
+TOP_DIR=$(cd $(dirname "$0") && pwd)
+source $TOP_DIR/midorc
+source $TOP_DIR/functions
+
+set -e
+set -x
+
+# Get the host id of the devstack machine
+HOST_ID=$(midonet-cli -e host list | awk '{ print $2 }')
+die_if_not_set $LINENO HOST_ID "FAILED to obtain host id"
+echo "Host: ${HOST_ID}"
+
+# Check if the default tunnel zone exists
+TZ_NAME='DEFAULT'
+TZ_ID=$(midonet-cli -e list tunnel-zone name $TZ_NAME | awk '{ print $2 }')
+if [[ -z "$TZ_ID" ]]; then
+    TZ_ID=$(midonet-cli -e create tunnel-zone name $TZ_NAME type gre)
+fi
+echo "Tunnel Zone: ${TZ_ID}"
+
+# Check if the host is a member of the tunnel zone
+TZ_MEMBER=$(midonet-cli -e tunnel-zone $TZ_ID list member host $HOST_ID \
+    address $GATEWAY_IP)
+if [[ -z "$TZ_MEMBER" ]]; then
+    TZ_MEMBER=$(midonet-cli -e tunnel-zone $TZ_ID add member host $HOST_ID \
+        address $GATEWAY_IP)
+fi
+echo "Tunnel Zone Member: ${TZ_MEMBER}"
+
+# Check if we need to bind - we assume that if 'veth1' is bound, then it must
+# exist, and so does veth0
+BINDING=$(midonet-cli -e host $HOST_ID list binding interface veth1)
+if [[ -z "$BINDING" ]]; then
+
+    # Create the veth interfaces
+    sudo ip link add type veth
+    sudo ip addr flush veth0
+    sudo ip addr flush veth1
+    sudo ip link set dev veth0 up
+    sudo ip link set dev veth1 up
+
+    PORT_ID=$(midonet-cli -e bridge $NETWORK_ID add port)
+    echo "Port: ${PORT_ID}"
+
+    BINDING=$(midonet-cli -e host $HOST_ID add binding \
+        port bridge $NETWORK_ID port $PORT_ID interface veth1)
+fi
+echo "Binding: ${BINDING}"
+
+# Add the gateway address to the other veth
+if ! ip addr | grep veth0 | grep $GATEWAY_IP; then
+    sudo ip addr add $GATEWAY_IP/$NET_LEN dev veth0
+fi
+
+echo "Successfully created fake uplink"
diff --git a/templates/gateway/midorc.erb b/templates/gateway/midorc.erb
new file mode 100644
index 0000000..04792b1
--- /dev/null
+++ b/templates/gateway/midorc.erb
@@ -0,0 +1,58 @@
+#!/usr/bin/env bash
+
+# Copyright 2016 Midokura SARL
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# If you want to override these variables, create a file called 'localrc'
+# and place it in the same directory as this file.
+
+# rc file(s) location
+RC_DIR=$(cd $(dirname "${BASH_SOURCE:-$0}") && pwd)
+
+# allow local overrides of env variables
+if [[ -f $RC_DIR/localrc ]]; then
+    source $RC_DIR/localrc
+fi
+
+# IP address/hostname to use for the services
+SERVICE_HOST=<%= @service_host %>
+
+# Directory where all the service files will live
+SERVICE_DIR=<%= @service_dir %>
+
+USE_SCREEN="True"
+
+# ZK Hosts (comma delimited)
+<%- zkarr = Array.new -%>
+<%- @zookeeper_hosts.each do |s| -%>
+  <%- zkarr.push("#{s['ip']}:#{s['port'] ||= 2181 }") -%>
+<%- end -%>
+ZOOKEEPER_HOSTS=<%= zkarr.join(",") %>
+
+# MidoNet API port and URI
+API_PORT=<%= @api_port %>
+API_URI=http://$SERVICE_HOST:$API_PORT/midonet-api
+
+MIDO_DB_USER=<%= @mido_db_user %>
+MIDO_DB_PASSWORD=<%= @mido_db_password %>
+
+# MidoNet Client
+# --------------
+
+# Auth variables. They are exported so that you could source this file and
+# run midonet-cli using these credentials
+export MIDO_API_URL=$API_URI
+export MIDO_USER=${MIDO_USER:-admin}
+export MIDO_PROJECT_ID=${MIDO_PROJECT_ID:-admin}
+export MIDO_PASSWORD=${MIDO_PASSWORD:-midonet}