From 75a999369a7d5dc7f11680274863e3efa38e40db Mon Sep 17 00:00:00 2001
From: Tobias Urdin <tobias@busybox.se>
Date: Thu, 28 Jun 2018 13:53:00 +0200
Subject: [PATCH] Add support for dynamic routing bpg dragent

This patch adds support to install and configure the
bgp dynamic routing agent. It also install the
dynamic-routing package since that is required by
the bgp dragent.

These packages already exists on Debian and Ubuntu but
since it was removed from RPM packages when dynamic-routing
was moved out of the Neutron tree there are work to add it here [1].
So until [1] is merged and hopefully backported to Queens for the latest
stable release this will work propery on RedHat based OS.

[1] https://review.rdoproject.org/r/#/c/7935/

Change-Id: Id8a97b337eff68860547e07e675b79bde94628ba
---
 .../openstackconfig.rb                        |  15 ++
 lib/puppet/type/neutron_bgp_dragent_config.rb |  28 ++
 manifests/agents/bgp_dragent.pp               |  98 +++++++
 manifests/config.pp                           |   6 +
 manifests/deps.pp                             |   1 +
 manifests/params.pp                           |   6 +
 .../add-bgp-dragent-c6b19e076b1acf0c.yaml     |   7 +
 .../neutron_agents_bgp_dragent_spec.rb        | 243 ++++++++++++++++++
 spec/classes/neutron_config_spec.rb           |   7 +
 .../openstackconfig_spec.rb                   |  74 ++++++
 .../type/neutron_bgp_dragent_config_spec.rb   |  23 ++
 11 files changed, 508 insertions(+)
 create mode 100644 lib/puppet/provider/neutron_bgp_dragent_config/openstackconfig.rb
 create mode 100644 lib/puppet/type/neutron_bgp_dragent_config.rb
 create mode 100644 manifests/agents/bgp_dragent.pp
 create mode 100644 releasenotes/notes/add-bgp-dragent-c6b19e076b1acf0c.yaml
 create mode 100644 spec/classes/neutron_agents_bgp_dragent_spec.rb
 create mode 100644 spec/unit/provider/neutron_bgp_dragent_config/openstackconfig_spec.rb
 create mode 100644 spec/unit/type/neutron_bgp_dragent_config_spec.rb

diff --git a/lib/puppet/provider/neutron_bgp_dragent_config/openstackconfig.rb b/lib/puppet/provider/neutron_bgp_dragent_config/openstackconfig.rb
new file mode 100644
index 000000000..02aa6b32b
--- /dev/null
+++ b/lib/puppet/provider/neutron_bgp_dragent_config/openstackconfig.rb
@@ -0,0 +1,15 @@
+Puppet::Type.type(:neutron_bgp_dragent_config).provide(
+  :openstackconfig,
+  :parent => Puppet::Type.type(:openstack_config).provider(:ruby)
+) do
+
+  def self.file_path
+    '/etc/neutron/bgp_dragent.ini'
+  end
+
+  # added for backwards compatibility with older versions of inifile
+  def file_path
+    self.class.file_path
+  end
+
+end
diff --git a/lib/puppet/type/neutron_bgp_dragent_config.rb b/lib/puppet/type/neutron_bgp_dragent_config.rb
new file mode 100644
index 000000000..058e93420
--- /dev/null
+++ b/lib/puppet/type/neutron_bgp_dragent_config.rb
@@ -0,0 +1,28 @@
+Puppet::Type.newtype(:neutron_bgp_dragent_config) do
+
+  ensurable
+
+  newparam(:name, :namevar => true) do
+    desc 'Section/setting name to manage in bgp dragent config.'
+    newvalues(/\S+\/\S+/)
+  end
+
+  newproperty(:value) do
+    desc 'The value of the setting to be defined.'
+    munge do |value|
+      value = value.to_s.strip
+      value.capitalize! if value =~ /^(true|false)$/i
+      value
+    end
+  end
+
+  newparam(:ensure_absent_val) do
+    desc 'A value that is specified as the value property will behave as if ensure => absent was specified'
+    defaultto('<SERVICE DEFAULT>')
+  end
+
+  autorequire(:package) do
+    ['neutron-dynamic-routing', 'neutron-bgp-dragent']
+  end
+
+end
diff --git a/manifests/agents/bgp_dragent.pp b/manifests/agents/bgp_dragent.pp
new file mode 100644
index 000000000..92f13465f
--- /dev/null
+++ b/manifests/agents/bgp_dragent.pp
@@ -0,0 +1,98 @@
+#
+# Copyright (C) 2018 Binero AB.
+#
+# Author: Tobias Urdin <tobias.urdin@binero.se>
+#
+# 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: neutron::agents::bgp_dragent
+#
+# Install and configure neutron BGP dragent from Neutron Dynamic Routing.
+#
+# === Parameters:
+#
+# [*package_ensure*]
+#   (Optional) The state of the package.
+#   Defaults to 'present'
+#
+# [*enabled*]
+#   (Optional) The state of the service.
+#   Defaults to true
+#
+# [*manage_service*]
+#   (Optional) Whether to start/stop the service.
+#   Defaults to true
+#
+# [*bgp_speaker_driver*]
+#   (Optional) The BGP speaker driver to use.
+#   Defaults to 'neutron_dynamic_routing.services.bgp.agent.driver.ryu.driver.RyuBgpDriver'
+#
+# [*bgp_router_id*]
+#   (Optional) The BGP router ID.
+#   Defaults to $::ipaddress
+#
+# [*purge_config*]
+#   (Optional) Whether to set only the specified config options in the BGP dragent config.
+#   Defaults to false.
+#
+class neutron::agents::bgp_dragent(
+  $package_ensure     = 'present',
+  $enabled            = true,
+  $manage_service     = true,
+  $bgp_speaker_driver = 'neutron_dynamic_routing.services.bgp.agent.driver.ryu.driver.RyuBgpDriver',
+  $bgp_router_id      = $::ipaddress,
+  $purge_config       = false,
+) {
+
+  include ::neutron::deps
+  include ::neutron::params
+
+  resources { 'neutron_bgp_dragent_config':
+    purge => $purge_config,
+  }
+
+  neutron_bgp_dragent_config {
+    'BGP/bgp_speaker_driver': value => $bgp_speaker_driver;
+    'BGP/bgp_router_id':      value => $bgp_router_id;
+  }
+
+  if $::neutron::params::dynamic_routing_package {
+    ensure_packages('neutron-dynamic-routing', {
+      ensure => $package_ensure,
+      name   => $::neutron::params::dynamic_routing_package,
+      tag    => ['openstack', 'neutron-package'],
+    })
+  }
+
+  if $::neutron::params::bgp_dragent_package {
+    ensure_packages('neutron-bgp-dragent', {
+      ensure => $package_ensure,
+      name   => $::neutron::params::bgp_dragent_package,
+      tag    => ['openstack', 'neutron-package'],
+    })
+  }
+
+  if $manage_service {
+    if $enabled {
+      $service_ensure = 'running'
+    } else {
+      $service_ensure = 'stopped'
+    }
+    service { 'neutron-bgp-dragent':
+      ensure => $service_ensure,
+      name   => $::neutron::params::bgp_dragent_service,
+      enable => $enabled,
+      tag    => 'neutron-service',
+    }
+  }
+}
diff --git a/manifests/config.pp b/manifests/config.pp
index 97e320b98..6a35d526d 100644
--- a/manifests/config.pp
+++ b/manifests/config.pp
@@ -63,6 +63,9 @@
 # [*vpnaas_agent_config*]
 #   (optional) Manage configuration of vpn_agent.ini
 #
+# [*bgp_dragent_config*]
+#   (optional) Manage configuration of bgp_dragent.ini
+#
 # [*plugin_linuxbridge_config*]
 #   (optional) Manage configuration of linuxbridge_conf.ini
 #
@@ -114,6 +117,7 @@ class neutron::config (
   $ovn_metadata_agent_config     = {},
   $metering_agent_config         = {},
   $vpnaas_agent_config           = {},
+  $bgp_dragent_config            = {},
   $plugin_linuxbridge_config     = {},
   $plugin_cisco_db_conn_config   = {},
   $plugin_cisco_l2network_config = {},
@@ -143,6 +147,7 @@ class neutron::config (
   validate_hash($ovn_metadata_agent_config)
   validate_hash($metering_agent_config)
   validate_hash($vpnaas_agent_config)
+  validate_hash($bgp_dragent_config)
   validate_hash($plugin_linuxbridge_config)
   validate_hash($plugin_cisco_db_conn_config)
   validate_hash($plugin_cisco_l2network_config)
@@ -167,6 +172,7 @@ class neutron::config (
   create_resources('neutron_metadata_agent_config', $metadata_agent_config)
   create_resources('neutron_metering_agent_config', $metering_agent_config)
   create_resources('neutron_vpnaas_agent_config', $vpnaas_agent_config)
+  create_resources('neutron_bgp_dragent_config', $bgp_dragent_config)
   create_resources('neutron_plugin_linuxbridge', $plugin_linuxbridge_config)
   create_resources('neutron_plugin_cisco_db_conn', $plugin_cisco_db_conn_config)
   create_resources('neutron_plugin_cisco_l2network', $plugin_cisco_l2network_config)
diff --git a/manifests/deps.pp b/manifests/deps.pp
index e6378b8d8..f6cc92a6a 100644
--- a/manifests/deps.pp
+++ b/manifests/deps.pp
@@ -50,6 +50,7 @@ class neutron::deps {
   Anchor['neutron::config::begin'] -> Neutron_lbaas_service_config<||> ~> Anchor['neutron::config::end']
   Anchor['neutron::config::begin'] -> Neutron_metadata_agent_config<||> ~> Anchor['neutron::config::end']
   Anchor['neutron::config::begin'] -> Neutron_metering_agent_config<||> ~> Anchor['neutron::config::end']
+  Anchor['neutron::config::begin'] -> Neutron_bgp_dragent_config<||> ~> Anchor['neutron::config::end']
   Anchor['neutron::config::begin'] -> Neutron_plugin_cisco_credentials<||> ~> Anchor['neutron::config::end']
   Anchor['neutron::config::begin'] -> Neutron_plugin_cisco_db_conn<||> ~> Anchor['neutron::config::end']
   Anchor['neutron::config::begin'] -> Neutron_plugin_cisco<||> ~> Anchor['neutron::config::end']
diff --git a/manifests/params.pp b/manifests/params.pp
index c41090086..3e42761e4 100644
--- a/manifests/params.pp
+++ b/manifests/params.pp
@@ -34,6 +34,7 @@ class neutron::params {
   $l3_agent_service            = 'neutron-l3-agent'
   $metadata_agent_service      = 'neutron-metadata-agent'
   $ovn_metadata_agent_service  = 'networking-ovn-metadata-agent'
+  $bgp_dragent_service         = 'neutron-bgp-dragent'
   $bagpipe_bgp_package         = 'openstack-bagpipe-bgp'
   $bgpvpn_bagpipe_package      = "python${pyvers}-networking-bagpipe"
   $bgpvpn_bagpipe_service      = 'bagpipe-bgp'
@@ -76,6 +77,8 @@ class neutron::params {
     $l2gw_agent_package                 = 'openstack-neutron-l2gw-agent'
     $l2gw_package                       = 'python2-networking-l2gw'
     $ovn_metadata_agent_package         = 'python-networking-ovn-metadata-agent'
+    $dynamic_routing_package            = 'openstack-neutron-dynamic-routing'
+    $bgp_dragent_package                = false
     if $::operatingsystemrelease =~ /^7.*/ or $::operatingsystem == 'Fedora' {
       $openswan_package = 'libreswan'
     } else {
@@ -100,6 +103,7 @@ class neutron::params {
       $api_service_name         = 'neutron-api'
       $rpc_package_name         = 'neutron-rpc-server'
       $rpc_service_name         = 'neutron-rpc-server'
+      $dynamic_routing_package  = 'neutron-dynamic-routing'
     } else {
       $ml2_server_package = 'neutron-plugin-ml2'
       $server_service           = 'neutron-server'
@@ -108,7 +112,9 @@ class neutron::params {
       $api_service_name         = false
       $rpc_package_name         = false
       $rpc_service_name         = false
+      $dynamic_routing_package  = 'python-neutron-dynamic-routing'
     }
+    $bgp_dragent_package        = 'neutron-bgp-dragent'
     $ovs_agent_package          = 'neutron-openvswitch-agent'
     $ovs_server_package         = 'neutron-plugin-openvswitch'
     $ovs_cleanup_service        = false
diff --git a/releasenotes/notes/add-bgp-dragent-c6b19e076b1acf0c.yaml b/releasenotes/notes/add-bgp-dragent-c6b19e076b1acf0c.yaml
new file mode 100644
index 000000000..f8fcd01e6
--- /dev/null
+++ b/releasenotes/notes/add-bgp-dragent-c6b19e076b1acf0c.yaml
@@ -0,0 +1,7 @@
+---
+features:
+  - |
+    New class neutron::agents::bgp_dragent that installs and manages the
+    neutron-dynamic-routing and neutron-bgp-dragent packages.
+    When you are using this feature you must enable the 'bgp' service plugin
+    by passing it in neutron::service_plugins.
diff --git a/spec/classes/neutron_agents_bgp_dragent_spec.rb b/spec/classes/neutron_agents_bgp_dragent_spec.rb
new file mode 100644
index 000000000..06dc9a183
--- /dev/null
+++ b/spec/classes/neutron_agents_bgp_dragent_spec.rb
@@ -0,0 +1,243 @@
+# Copyright (C) 2018 Binero AB.
+#
+# Author: Tobias Urdin <tobias.urdin@binero.se>
+#
+# 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.
+
+require 'spec_helper'
+
+describe 'neutron::agents::bgp_dragent' do
+
+  let :default_params do
+    {
+      :package_ensure     => 'present',
+      :enabled            => true,
+      :manage_service     => true,
+      :bgp_speaker_driver => 'neutron_dynamic_routing.services.bgp.agent.driver.ryu.driver.RyuBgpDriver',
+      :purge_config       => false,
+    }
+  end
+
+  let :params do
+    {
+    }
+  end
+
+  shared_examples 'neutron::agents::bgp_dragent' do
+    context 'with default params' do
+      it { should contain_class('neutron::deps') }
+      it { should contain_class('neutron::params') }
+
+      it { should contain_resources('neutron_bgp_dragent_config').with_purge(default_params[:purge_config]) }
+
+      it { should contain_neutron_bgp_dragent_config('BGP/bgp_speaker_driver').with_value(default_params[:bgp_speaker_driver]) }
+      it { should contain_neutron_bgp_dragent_config('BGP/bgp_router_id').with_value(facts[:ipaddress]) }
+    end
+
+    context 'with overridden params' do
+      before do
+        params.merge!( :bgp_speaker_driver => 'FakeDriver',
+                       :bgp_router_id => '4.3.2.1',
+                       :purge_config  => true )
+      end
+
+      it { should contain_resources('neutron_bgp_dragent_config').with_purge(true) }
+      it { should contain_neutron_bgp_dragent_config('BGP/bgp_speaker_driver').with_value('FakeDriver') }
+      it { should contain_neutron_bgp_dragent_config('BGP/bgp_router_id').with_value('4.3.2.1') }
+    end
+  end
+
+  shared_examples 'neutron::agents::bgp_dragent on RedHat' do
+    context 'with default params' do
+      it { should contain_package('neutron-dynamic-routing').with(
+        :ensure => default_params[:package_ensure],
+        :name   => platform_params[:dynamic_routing_package],
+        :tag    => ['openstack', 'neutron-package'],
+      )}
+
+      it { should_not contain_package('neutron-bgp-dragent') }
+
+      it { should contain_service('neutron-bgp-dragent').with(
+        :ensure => 'running',
+        :name   => platform_params[:bgp_dragent_service],
+        :enable => default_params[:enabled],
+        :tag    => 'neutron-service',
+      )}
+    end
+
+    context 'with overridden params' do
+      before do
+        params.merge!( :package_ensure => 'absent',
+                       :enabled        => false )
+      end
+
+      it { should contain_package('neutron-dynamic-routing').with(
+        :ensure => 'absent',
+        :name   => platform_params[:dynamic_routing_package],
+        :tag    => ['openstack', 'neutron-package'],
+      )}
+
+      it { should_not contain_package('neutron-bgp-dragent') }
+
+      it { should contain_service('neutron-bgp-dragent').with(
+        :ensure => 'stopped',
+        :name   => platform_params[:bgp_dragent_service],
+        :enable => false,
+        :tag    => 'neutron-service',
+      )}
+    end
+  end
+
+  shared_examples 'neutron::agents::bgp_dragent on Debian' do
+    before do
+      facts.merge!( :os_package_type => 'debian' )
+    end
+
+    context 'with default params' do
+      it { should contain_package('neutron-dynamic-routing').with(
+        :ensure => default_params[:package_ensure],
+        :name   => platform_params[:dynamic_routing_package],
+        :tag    => ['openstack', 'neutron-package'],
+      )}
+
+      it { should contain_package('neutron-bgp-dragent').with(
+        :ensure => default_params[:package_ensure],
+        :name   => platform_params[:bgp_dragent_package],
+        :tag    => ['openstack', 'neutron-package'],
+      )}
+
+      it { should contain_service('neutron-bgp-dragent').with(
+        :ensure => 'running',
+        :name   => platform_params[:bgp_dragent_service],
+        :enable => default_params[:enabled],
+        :tag    => 'neutron-service',
+      )}
+    end
+
+    context 'with overridden params' do
+      before do
+        params.merge!( :package_ensure => 'absent',
+                       :enabled        => false )
+      end
+
+      it { should contain_package('neutron-dynamic-routing').with(
+        :ensure => 'absent',
+        :name   => platform_params[:dynamic_routing_package],
+        :tag    => ['openstack', 'neutron-package'],
+      )}
+
+      it { should contain_package('neutron-bgp-dragent').with(
+        :ensure => 'absent',
+        :name   => platform_params[:bgp_dragent_package],
+        :tag    => ['openstack', 'neutron-package'],
+      )}
+
+      it { should contain_service('neutron-bgp-dragent').with(
+        :ensure => 'stopped',
+        :name   => platform_params[:bgp_dragent_service],
+        :enable => false,
+        :tag    => 'neutron-service',
+      )}
+    end
+  end
+
+  shared_examples 'neutron::agents::bgp_dragent on Ubuntu' do
+    context 'with default params' do
+      it { should contain_package('neutron-dynamic-routing').with(
+        :ensure => default_params[:package_ensure],
+        :name   => platform_params[:dynamic_routing_package],
+        :tag    => ['openstack', 'neutron-package'],
+      )}
+
+      it { should contain_package('neutron-bgp-dragent').with(
+        :ensure => default_params[:package_ensure],
+        :name   => platform_params[:bgp_dragent_package],
+        :tag    => ['openstack', 'neutron-package'],
+      )}
+
+      it { should contain_service('neutron-bgp-dragent').with(
+        :ensure => 'running',
+        :name   => platform_params[:bgp_dragent_service],
+        :enable => default_params[:enabled],
+        :tag    => 'neutron-service',
+      )}
+    end
+
+    context 'with overridden params' do
+      before do
+        params.merge!( :package_ensure => 'absent',
+                       :enabled        => false )
+      end
+
+      it { should contain_package('neutron-dynamic-routing').with(
+        :ensure => 'absent',
+        :name   => platform_params[:dynamic_routing_package],
+        :tag    => ['openstack', 'neutron-package'],
+      )}
+
+      it { should contain_package('neutron-bgp-dragent').with(
+        :ensure => 'absent',
+        :name   => platform_params[:bgp_dragent_package],
+        :tag    => ['openstack', 'neutron-package'],
+      )}
+
+      it { should contain_service('neutron-bgp-dragent').with(
+        :ensure => 'stopped',
+        :name   => platform_params[:bgp_dragent_service],
+        :enable => false,
+        :tag    => 'neutron-service',
+      )}
+    end
+  end
+
+  on_supported_os({
+    :supported_os => OSDefaults.get_supported_os
+  }).each do |os,facts|
+    context "on #{os}" do
+      let (:facts) do
+        facts.merge(OSDefaults.get_facts({:ipaddress => '1.2.3.4'}))
+      end
+
+      let (:platform_params) do
+        case facts[:osfamily]
+        when 'RedHat'
+          {
+            :dynamic_routing_package => 'openstack-neutron-dynamic-routing',
+            :bgp_dragent_package     => false,
+            :bgp_dragent_service     => 'neutron-bgp-dragent',
+          }
+        when 'Debian'
+          if facts[:operatingsystem] == 'Debian'
+            pkg = 'neutron-dynamic-routing'
+          else
+            pkg = 'python-neutron-dynamic-routing'
+          end
+          {
+            :dynamic_routing_package => pkg,
+            :bgp_dragent_package     => 'neutron-bgp-dragent',
+            :bgp_dragent_service     => 'neutron-bgp-dragent',
+          }
+        end
+      end
+
+      it_behaves_like 'neutron::agents::bgp_dragent'
+
+      case facts[:osfamily]
+      when 'RedHat'
+        it_behaves_like 'neutron::agents::bgp_dragent on RedHat'
+      when 'Debian'
+        it_behaves_like "neutron::agents::bgp_dragent on #{facts[:operatingsystem]}"
+      end
+    end
+  end
+end
diff --git a/spec/classes/neutron_config_spec.rb b/spec/classes/neutron_config_spec.rb
index dda7c9664..1b765cb92 100644
--- a/spec/classes/neutron_config_spec.rb
+++ b/spec/classes/neutron_config_spec.rb
@@ -64,6 +64,7 @@ describe 'neutron::config' do
         :metering_agent_config => config_hash,
         :vpnaas_agent_config   => config_hash,
         :l2gw_agent_config     => config_hash,
+        :bgp_dragent_config    => config_hash,
       }
     end
 
@@ -109,6 +110,12 @@ describe 'neutron::config' do
       is_expected.to contain_neutron_l2gw_agent_config('DEFAULT/baz').with_ensure('absent')
     end
 
+    it 'configures arbitrary bgp_dragent_config configurations' do
+      is_expected.to contain_neutron_bgp_dragent_config('DEFAULT/foo').with_value('fooValue')
+      is_expected.to contain_neutron_bgp_dragent_config('DEFAULT/bar').with_value('barValue')
+      is_expected.to contain_neutron_bgp_dragent_config('DEFAULT/baz').with_ensure('absent')
+    end
+
   end
 
   shared_examples_for 'neutron_plugin_config' do
diff --git a/spec/unit/provider/neutron_bgp_dragent_config/openstackconfig_spec.rb b/spec/unit/provider/neutron_bgp_dragent_config/openstackconfig_spec.rb
new file mode 100644
index 000000000..9f25ad148
--- /dev/null
+++ b/spec/unit/provider/neutron_bgp_dragent_config/openstackconfig_spec.rb
@@ -0,0 +1,74 @@
+$LOAD_PATH.push(
+  File.join(
+    File.dirname(__FILE__),
+    '..',
+    '..',
+    '..',
+    'fixtures',
+    'modules',
+    'inifile',
+    'lib')
+)
+$LOAD_PATH.push(
+  File.join(
+    File.dirname(__FILE__),
+    '..',
+    '..',
+    '..',
+    'fixtures',
+    'modules',
+    'openstacklib',
+    'lib')
+)
+
+require 'spec_helper'
+
+provider_class = Puppet::Type.type(:neutron_bgp_dragent_config).provider(:openstackconfig)
+
+describe provider_class do
+
+  it 'should default to the default setting when no other one is specified' do
+    resource = Puppet::Type::Neutron_bgp_dragent_config.new(
+      {
+        :name => 'DEFAULT/foo',
+        :value => 'bar'
+      }
+    )
+    provider = provider_class.new(resource)
+    expect(provider.section).to eq('DEFAULT')
+    expect(provider.setting).to eq('foo')
+    expect(provider.file_path).to eq('/etc/neutron/bgp_dragent.ini')
+  end
+
+  it 'should allow setting to be set explicitly' do
+    resource = Puppet::Type::Neutron_bgp_dragent_config.new(
+      {
+        :name => 'dude/foo',
+        :value => 'bar'
+      }
+    )
+    provider = provider_class.new(resource)
+    expect(provider.section).to eq('dude')
+    expect(provider.setting).to eq('foo')
+    expect(provider.file_path).to eq('/etc/neutron/bgp_dragent.ini')
+  end
+
+  it 'should ensure absent when <SERVICE DEFAULT> is specified as a value' do
+    resource = Puppet::Type::Neutron_bgp_dragent_config.new(
+      {:name => 'dude/foo', :value => '<SERVICE DEFAULT>'}
+    )
+    provider = provider_class.new(resource)
+    provider.exists?
+    expect(resource[:ensure]).to eq :absent
+  end
+
+  it 'should ensure absent when value matches ensure_absent_val' do
+    resource = Puppet::Type::Neutron_bgp_dragent_config.new(
+      {:name => 'dude/foo', :value => 'foo', :ensure_absent_val => 'foo' }
+    )
+    provider = provider_class.new(resource)
+    provider.exists?
+    expect(resource[:ensure]).to eq :absent
+  end
+
+end
diff --git a/spec/unit/type/neutron_bgp_dragent_config_spec.rb b/spec/unit/type/neutron_bgp_dragent_config_spec.rb
new file mode 100644
index 000000000..0268e820c
--- /dev/null
+++ b/spec/unit/type/neutron_bgp_dragent_config_spec.rb
@@ -0,0 +1,23 @@
+require 'puppet'
+require 'puppet/type/neutron_bgp_dragent_config'
+
+describe 'Puppet::Type.type(:neutron_bgp_dragent_config)' do
+
+  before :each do
+    @neutron_bgp_dragent_config = Puppet::Type.type(:neutron_bgp_dragent_config).new(:name => 'DEFAULT/foo', :value => 'bar')
+  end
+
+  it 'should autorequire the package that install the file' do
+    catalog = Puppet::Resource::Catalog.new
+    package1 = Puppet::Type.type(:package).new(:name => 'neutron-dynamic-routing')
+    package2 = Puppet::Type.type(:package).new(:name => 'neutron-bgp-dragent')
+    catalog.add_resource package1, package2, @neutron_bgp_dragent_config
+    dependency = @neutron_bgp_dragent_config.autorequire
+    expect(dependency.size).to eq(2)
+    expect(dependency[0].target).to eq(@neutron_bgp_dragent_config)
+    expect(dependency[0].source).to eq(package1)
+    expect(dependency[1].target).to eq(@neutron_bgp_dragent_config)
+    expect(dependency[1].source).to eq(package2)
+  end
+
+end