From efa9181201d33a6bcc4dbe0a482a5d213b6fb5fd Mon Sep 17 00:00:00 2001 From: Clayton O'Neill Date: Mon, 16 Mar 2015 22:35:04 -0400 Subject: [PATCH] Properly handle embedded newlines in csv When parsing the response from the OpenStack client values (like keystone tenant descriptions) can have embedded newline. To avoid this issue, we drop lines that don't start with a double quoted value until the first one we find. Change-Id: Ie952161b503d2c46637e6a6e1c83b2dfce1c03a7 --- lib/puppet/provider/openstack.rb | 12 +++++++---- spec/unit/provider/openstack_spec.rb | 32 ++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/lib/puppet/provider/openstack.rb b/lib/puppet/provider/openstack.rb index c47df095..ec1cffe2 100644 --- a/lib/puppet/provider/openstack.rb +++ b/lib/puppet/provider/openstack.rb @@ -51,10 +51,7 @@ class Puppet::Provider::Openstack < Puppet::Provider begin if(action == 'list') response = openstack(service, action, '--quiet', '--format', 'csv', args) - # Ignore warnings - assume legitimate output starts with a double quote - # Errors will be caught and raised prior to this - response = response.split("\n").select { |line| line =~ /^\".*\",\".*\"/ }.join("\n") - response = CSV.parse(response.to_s) + response = parse_csv(response) keys = response.delete_at(0) # ID,Name,Description,Enabled rv = response.collect do |line| hash = {} @@ -180,4 +177,11 @@ class Puppet::Provider::Openstack < Puppet::Provider self.class.get_credentials_from_env end + def self.parse_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") + return CSV.parse(text + "\n") + end + end diff --git a/spec/unit/provider/openstack_spec.rb b/spec/unit/provider/openstack_spec.rb index 447f3f6c..c5f5efe1 100644 --- a/spec/unit/provider/openstack_spec.rb +++ b/spec/unit/provider/openstack_spec.rb @@ -225,4 +225,36 @@ Enabled="True" end + describe 'parse_csv' do + context 'with mixed stderr' do + text = "ERROR: Testing\n\"field\",\"test\",1,2,3\n" + csv = Puppet::Provider::Openstack.parse_csv(text) + it 'should ignore non-CSV text at the beginning of the input' do + expect(csv).to be_kind_of(Array) + expect(csv[0]).to match_array(['field', 'test', '1', '2', '3']) + expect(csv.size).to eq(1) + end + end + + context 'with \r\n line endings' do + text = "ERROR: Testing\r\n\"field\",\"test\",1,2,3\r\n" + csv = Puppet::Provider::Openstack.parse_csv(text) + it 'ignore the carriage returns' do + expect(csv).to be_kind_of(Array) + expect(csv[0]).to match_array(['field', 'test', '1', '2', '3']) + expect(csv.size).to eq(1) + end + end + + context 'with embedded newlines' do + text = "ERROR: Testing\n\"field\",\"te\nst\",1,2,3\n" + csv = Puppet::Provider::Openstack.parse_csv(text) + it 'should parse correctly' do + expect(csv).to be_kind_of(Array) + expect(csv[0]).to match_array(['field', "te\nst", '1', '2', '3']) + expect(csv.size).to eq(1) + end + end + end + end