From e8e49e3862f048eec016ddbb50b7c86a8348571b Mon Sep 17 00:00:00 2001 From: Sofer Athlan-Guyot Date: Tue, 5 Jan 2016 20:32:59 +0100 Subject: [PATCH] Correctly parse csv even with extra output. This patch ensure that the csv output is cleaned up from extra warning message from the cli. This has been addressed first here[1], then there[2] which had to be reverted there[3]. So here again a fix. Closes-bug: #1508511 [1] https://review.openstack.org/#/c/237610/3 [2] https://review.openstack.org/#/c/238156/ [3] https://review.openstack.org/#/c/262809/ Change-Id: I3a2e677c2bd349322cfb08d5dc73c1ced38c3f60 --- lib/puppet/provider/neutron.rb | 18 ++++++++++-- spec/unit/provider/neutron_spec.rb | 44 ++++++++++++++++++++++++++++-- 2 files changed, 56 insertions(+), 6 deletions(-) diff --git a/lib/puppet/provider/neutron.rb b/lib/puppet/provider/neutron.rb index 2fc77e73b..135165859 100644 --- a/lib/puppet/provider/neutron.rb +++ b/lib/puppet/provider/neutron.rb @@ -133,8 +133,8 @@ correctly configured.") def self.list_neutron_resources(type) ids = [] - list = auth_neutron("#{type}-list", '--format=csv', - '--column=id', '--quote=none') + list = cleanup_csv_with_id(auth_neutron("#{type}-list", '--format=csv', + '--column=id', '--quote=none')) if list.nil? raise(Puppet::ExecutionFailure, "Can't retrieve #{type}-list because Neutron or Keystone API is not available.") end @@ -177,7 +177,7 @@ correctly configured.") end headers = nil - CSV.parse(cmd_output) do |row| + CSV.parse(cleanup_csv(cmd_output)) do |row| if headers == nil headers = row else @@ -222,4 +222,16 @@ correctly configured.") hash end + def self.cleanup_csv(text) + # Ignore warnings - assume legitimate output starts with a double quoted + # string. Errors will be caught and raised prior to this + text = text.split("\n").drop_while { |line| line !~ /^\".*\"/ }.join("\n") + "#{text}\n" + end + + def self.cleanup_csv_with_id(text) + return nil if text.nil? + text = text.split("\n").drop_while { |line| line !~ /^\s*id$/ }.join("\n") + "#{text}\n" + end end diff --git a/spec/unit/provider/neutron_spec.rb b/spec/unit/provider/neutron_spec.rb index d27abddeb..3b767005c 100644 --- a/spec/unit/provider/neutron_spec.rb +++ b/spec/unit/provider/neutron_spec.rb @@ -131,9 +131,9 @@ describe Puppet::Provider::Neutron do it 'should exclude the column header' do output = <<-EOT - id - net1 - net2 +id +net1 +net2 EOT klass.expects(:auth_neutron).returns(output) result = klass.list_neutron_resources('foo') @@ -243,4 +243,42 @@ tenant_id="3056a91768d948d399f1d79051a7f221" end + describe 'garbage in the csv output' do + it '#list_router_ports' do + output = <<-EOT +/usr/lib/python2.7/dist-packages/urllib3/util/ssl_.py:90: InsecurePlatformWarning: A true SSLContext object is not available. This prevents urllib3 from configuring SSL appropriately and may cause certain SSL connections to fail. For more information, see https://urllib3.readthedocs.org/en/latest/security.html#insecureplatformwarning. + InsecurePlatformWarning +"id","name","mac_address","fixed_ips" +"1345e576-a21f-4c2e-b24a-b245639852ab","","fa:16:3e:e3:e6:38","{""subnet_id"": ""839a1d2d-2c6e-44fb-9a2b-9b011dce8c2f"", ""ip_address"": ""10.0.0.1""}" + EOT + expected = [{ "fixed_ips"=> + "{\"subnet_id\": \"839a1d2d-2c6e-44fb-9a2b-9b011dce8c2f\", \ +\"ip_address\": \"10.0.0.1\"}", + "name"=>"", + "subnet_id"=>"839a1d2d-2c6e-44fb-9a2b-9b011dce8c2f", + "id"=>"1345e576-a21f-4c2e-b24a-b245639852ab", + "mac_address"=>"fa:16:3e:e3:e6:38"}] + + klass.expects(:auth_neutron). + with('router-port-list', '--format=csv', 'router1'). + returns(output) + result = klass.list_router_ports('router1') + expect(result).to eql(expected) + end + + it '#list_neutron_resources' do + output = <<-EOT +/usr/lib/python2.7/dist-packages/urllib3/util/ssl_.py:90: InsecurePlatformWarning: A true SSLContext object is not available. This prevents urllib3 from configuring SSL appropriately and may cause certain SSL connections to fail. For more information, see https://urllib3.readthedocs.org/en/latest/security.html#insecureplatformwarning. + InsecurePlatformWarning +id +4a305398-d806-46c5-a6aa-dcd6a4a99330 + EOT + klass.expects(:auth_neutron). + with('subnet-list', '--format=csv', '--column=id', '--quote=none'). + returns(output) + expected = ['4a305398-d806-46c5-a6aa-dcd6a4a99330'] + result = klass.list_neutron_resources('subnet') + expect(result).to eql(expected) + end + end end