| Kea 3.0.2-git

versioned_csv_file.cc
Go to the documentation of this file.
1// Copyright (C) 2015-2021 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#include <config.h>
8
9#include <util/versioned_csv_file.h>
10
11 namespace isc {
12 namespace util {
13
14 VersionedCSVFile::VersionedCSVFile(const std::string& filename)
15 : CSVFile(filename), columns_(0), valid_column_count_(0),
16 minimum_valid_columns_(0), input_header_count_(0),
17 input_schema_state_(CURRENT) {
18}
19
20 VersionedCSVFile::~VersionedCSVFile() {
21}
22
23 void
24 VersionedCSVFile::addColumn(const std::string& name,
25 const std::string& version,
26 const std::string& default_value) {
27 CSVFile::addColumn(name);
28 columns_.push_back(VersionedColumnPtr(new VersionedColumn(name, version,
29 default_value)));
30}
31
32 void
33 VersionedCSVFile::setMinimumValidColumns(const std::string& column_name) {
34 try {
35 int index = getColumnIndex(column_name);
36 minimum_valid_columns_ = index + 1;
37
38 } catch (...) {
39 isc_throw(VersionedCSVFileError,
40 "setMinimumValidColumns: " << column_name << " is not "
41 "defined");
42 }
43}
44
45 size_t
46 VersionedCSVFile::getMinimumValidColumns() const {
47 return (minimum_valid_columns_);
48}
49
50 size_t
51 VersionedCSVFile::getValidColumnCount() const {
52 return (valid_column_count_);
53}
54
55 size_t
56 VersionedCSVFile::getInputHeaderCount() const {
57 return (input_header_count_);
58}
59
60 void
61 VersionedCSVFile::open(const bool seek_to_end) {
62 if (getColumnCount() == 0) {
63 isc_throw(VersionedCSVFileError,
64 "no schema has been defined, cannot open CSV file :"
65 << getFilename());
66 }
67
68 CSVFile::open(seek_to_end);
69}
70
71 void
72 VersionedCSVFile::recreate() {
73 if (getColumnCount() == 0) {
74 isc_throw(VersionedCSVFileError,
75 "no schema has been defined, cannot create CSV file :"
76 << getFilename());
77 }
78
79 CSVFile::recreate();
80 // For new files they always match.
81 input_header_count_ = valid_column_count_ = getColumnCount();
82}
83
84 VersionedCSVFile::InputSchemaState
85 VersionedCSVFile::getInputSchemaState() const {
86 return (input_schema_state_);
87}
88
89 bool
90 VersionedCSVFile::needsConversion() const {
91 return (input_schema_state_ != CURRENT);
92}
93
94std::string
95 VersionedCSVFile::getInputSchemaVersion() const {
96 if (getValidColumnCount() > 0) {
97 return (getVersionedColumn(getValidColumnCount() - 1)->version_);
98 }
99
100 return ("undefined");
101}
102
103std::string
104 VersionedCSVFile::getSchemaVersion() const {
105 if (getColumnCount() > 0) {
106 return (getVersionedColumn(getColumnCount() - 1)->version_);
107 }
108
109 return ("undefined");
110}
111
112 const VersionedColumnPtr&
113 VersionedCSVFile::getVersionedColumn(const size_t index) const {
114 if (index >= getColumnCount()) {
115 isc_throw(isc::OutOfRange, "versioned column index " << index
116 << " out of range; CSV file : " << getFilename()
117 << " only has " << getColumnCount() << " columns ");
118 }
119
120 return (columns_[index]);
121}
122
123 bool
124 VersionedCSVFile::next(CSVRow& row) {
125 setReadMsg("success");
126 // Use base class to physical read the row, but skip its row
127 // validation
128 CSVFile::next(row, true);
129 if (row == CSVFile::EMPTY_ROW()) {
130 return(true);
131 }
132
133 bool row_valid = true;
134 switch(getInputSchemaState()) {
135 case CURRENT:
136 // All rows must match than the current schema
137 if (row.getValuesCount() != getColumnCount()) {
138 columnCountError(row, "must match current schema");
139 row_valid = false;
140 }
141 break;
142
143 case NEEDS_UPGRADE:
144 // The input header met the minimum column count but
145 // is less than the current schema so:
146 // Rows must not be shorter than the valid column count
147 // and not longer than the current schema
148 if (row.getValuesCount() < getValidColumnCount()) {
149 columnCountError(row, "too few columns to upgrade");
150 row_valid = false;
151 } else if (row.getValuesCount() > getColumnCount()) {
152 columnCountError(row, "too many columns to upgrade");
153 row_valid = false;
154 } else {
155 // Add any missing values
156 for (size_t index = row.getValuesCount();
157 index < getColumnCount(); ++index) {
158 row.append(columns_[index]->default_value_);
159 }
160 }
161 break;
162
163 case NEEDS_DOWNGRADE:
164 // The input header exceeded current schema so:
165 // Rows may be as long as input header but not shorter than
166 // the current schema
167 if (row.getValuesCount() < getColumnCount()) {
168 columnCountError(row, "too few columns to downgrade");
169 } else if (row.getValuesCount() > getInputHeaderCount()) {
170 columnCountError(row, "too many columns to downgrade");
171 } else {
172 // Toss any the extra columns
173 row.trim(row.getValuesCount() - getColumnCount());
174 }
175 break;
176 }
177
178 return (row_valid);
179}
180
181 void
182 VersionedCSVFile::columnCountError(const CSVRow& row,
183 const std::string& reason) {
184 std::ostringstream s;
185 s << "Invalid number of columns: "
186 << row.getValuesCount() << " in row: '" << row
187 << "', file: '" << getFilename() << "' : " << reason;
188 setReadMsg(s.str());
189}
190
191 bool
192 VersionedCSVFile::validateHeader(const CSVRow& header) {
193 if (getColumnCount() == 0) {
194 isc_throw(VersionedCSVFileError,
195 "cannot validate header, no schema has been defined");
196 }
197
198 input_header_count_ = header.getValuesCount();
199
200 // Iterate over the number of columns in the header, testing
201 // each against the defined column in the same position.
202 // If there is a mismatch, bail.
203 size_t i = 0;
204 for ( ; i < getInputHeaderCount() && i < getColumnCount(); ++i) {
205 if (getColumnName(i) != header.readAt(i)) {
206 std::ostringstream s;
207 s << " - header contains an invalid column: '"
208 << header.readAt(i) << "'";
209 setReadMsg(s.str());
210 return (false);
211 }
212 }
213
214 // If we found too few valid columns, then we cannot convert this
215 // file. It's too old, too corrupt, or not a Kea file.
216 if (i < getMinimumValidColumns()) {
217 std::ostringstream s;
218 s << " - header has only " << i << " valid column(s), "
219 << "it must have at least " << getMinimumValidColumns();
220 setReadMsg(s.str());
221 return (false);
222 }
223
224 // Remember the number of valid columns we found. When this number
225 // is less than the number of defined columns, then we have an older
226 // version of the lease file. We'll need this value to validate
227 // and upgrade data rows.
228 valid_column_count_ = i;
229
230 if (getValidColumnCount() < getColumnCount()) {
231 input_schema_state_ = NEEDS_UPGRADE;
232 } else if (getInputHeaderCount() > getColumnCount()) {
233 // If there are more values in the header than defined columns
234 // then, we'll drop the extra. This allows someone to attempt to
235 // downgrade if need be.
236 input_schema_state_ = NEEDS_DOWNGRADE;
237 std::ostringstream s;
238 s << " - header has " << getInputHeaderCount() - getColumnCount()
239 << " extra column(s), these will be ignored";
240 setReadMsg(s.str());
241 }
242
243 return (true);
244}
245
246} // end of isc::util namespace
247} // end of isc namespace
isc::OutOfRange
A generic exception that is thrown if a parameter given to a method would refer to or modify out-of-r...
Definition exceptions/exceptions.h:115
isc::util::CSVFile::getColumnName
std::string getColumnName(const size_t col_index) const
Returns the name of the column.
Definition csv_file.cc:247
isc::util::CSVFile::getColumnCount
size_t getColumnCount() const
Returns the number of columns in the file.
Definition csv_file.h:403
isc::util::CSVFile::EMPTY_ROW
static CSVRow EMPTY_ROW()
Represents empty row.
Definition csv_file.h:491
isc::util::CSVFile::setReadMsg
void setReadMsg(const std::string &read_msg)
Sets error message after row validation.
Definition csv_file.h:486
isc::util::CSVFile::CSVFile
CSVFile(const std::string &filename)
Constructor.
Definition csv_file.cc:114
isc::util::CSVFile::getFilename
std::string getFilename() const
Returns the path to the CSV file.
Definition csv_file.h:408
isc::util::CSVFile::recreate
virtual void recreate()
Creates a new CSV file.
Definition csv_file.cc:370
isc::util::CSVFile::addColumn
void addColumn(const std::string &col_name)
Adds new column name.
Definition csv_file.cc:147
isc::util::CSVFile::getColumnIndex
size_t getColumnIndex(const std::string &col_name) const
Returns the index of the column having specified name.
Definition csv_file.cc:237
isc::util::CSVFile::open
virtual void open(const bool seek_to_end=false)
Opens existing file or creates a new one.
Definition csv_file.cc:302
isc::util::CSVFile::next
bool next(CSVRow &row, const bool skip_validation=false)
Reads next row from CSV file.
Definition csv_file.cc:257
isc::util::CSVRow
Represents a single row of the CSV file.
Definition csv_file.h:51
isc::util::CSVRow::getValuesCount
size_t getValuesCount() const
Returns number of values in a CSV row.
Definition csv_file.h:85
isc::util::CSVRow::trim
void trim(const size_t count)
Trims a given number of elements from the end of a row.
Definition csv_file.cc:95
isc::util::CSVRow::readAt
std::string readAt(const size_t at) const
Retrieves a value from the internal container.
Definition csv_file.cc:60
isc::util::CSVRow::append
void append(const T value)
Appends the value as a new column.
Definition csv_file.h:220
isc::util::VersionedCSVFileError
Exception thrown when an error occurs during CSV file processing.
Definition versioned_csv_file.h:16
isc::util::VersionedCSVFile::needsConversion
bool needsConversion() const
Returns true if the input file schema state is not CURRENT.
Definition versioned_csv_file.cc:90
isc::util::VersionedCSVFile::open
virtual void open(const bool seek_to_end=false)
Opens existing file or creates a new one.
Definition versioned_csv_file.cc:61
isc::util::VersionedCSVFile::~VersionedCSVFile
virtual ~VersionedCSVFile()
Destructor.
Definition versioned_csv_file.cc:20
isc::util::VersionedCSVFile::getVersionedColumn
const VersionedColumnPtr & getVersionedColumn(const size_t index) const
Fetch the column descriptor for a given index.
Definition versioned_csv_file.cc:113
isc::util::VersionedCSVFile::getSchemaVersion
std::string getSchemaVersion() const
text version of current schema supported by the file's metadata
Definition versioned_csv_file.cc:104
isc::util::VersionedCSVFile::InputSchemaState
InputSchemaState
Possible input file schema states.
Definition versioned_csv_file.h:126
isc::util::VersionedCSVFile::NEEDS_UPGRADE
@ NEEDS_UPGRADE
Definition versioned_csv_file.h:128
isc::util::VersionedCSVFile::NEEDS_DOWNGRADE
@ NEEDS_DOWNGRADE
Definition versioned_csv_file.h:129
isc::util::VersionedCSVFile::CURRENT
@ CURRENT
Definition versioned_csv_file.h:127
isc::util::VersionedCSVFile::getInputHeaderCount
size_t getInputHeaderCount() const
Returns the number of columns found in the input header.
Definition versioned_csv_file.cc:56
isc::util::VersionedCSVFile::validateHeader
virtual bool validateHeader(const CSVRow &header)
Validates the header of a VersionedCSVFile.
Definition versioned_csv_file.cc:192
isc::util::VersionedCSVFile::VersionedCSVFile
VersionedCSVFile(const std::string &filename)
Constructor.
Definition versioned_csv_file.cc:14
isc::util::VersionedCSVFile::getInputSchemaVersion
std::string getInputSchemaVersion() const
Returns the schema version of the physical file.
Definition versioned_csv_file.cc:95
isc::util::VersionedCSVFile::recreate
virtual void recreate()
Creates a new CSV file.
Definition versioned_csv_file.cc:72
isc::util::VersionedCSVFile::setMinimumValidColumns
void setMinimumValidColumns(const std::string &column_name)
Sets the minimum number of valid columns based on a given column.
Definition versioned_csv_file.cc:33
isc::util::VersionedCSVFile::next
bool next(CSVRow &row)
Reads next row from the file file.
Definition versioned_csv_file.cc:124
isc::util::VersionedCSVFile::addColumn
void addColumn(const std::string &col_name, const std::string &version, const std::string &default_value="")
Adds metadata for a single column to the schema.
Definition versioned_csv_file.cc:24
isc::util::VersionedCSVFile::getMinimumValidColumns
size_t getMinimumValidColumns() const
Returns the minimum number of columns which must be present for the file to be considered valid.
Definition versioned_csv_file.cc:46
isc::util::VersionedCSVFile::columnCountError
void columnCountError(const CSVRow &row, const std::string &reason)
Convenience method for adding an error message.
Definition versioned_csv_file.cc:182
isc::util::VersionedCSVFile::getValidColumnCount
size_t getValidColumnCount() const
Returns the number of valid columns found in the header For newly created files this will always matc...
Definition versioned_csv_file.cc:51
isc::util::VersionedCSVFile::getInputSchemaState
enum InputSchemaState getInputSchemaState() const
Fetches the state of the input file's schema.
Definition versioned_csv_file.cc:85
isc::util::VersionedColumn
Contains the metadata for a single column in a file.
Definition versioned_csv_file.h:23
version
int version()
returns Kea hooks version.
Definition d2/gss_tsig/version.cc:13
isc_throw
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
Definition exceptions/exceptions.h:210
isc::util
Definition time_utils.cc:43
isc::util::VersionedColumnPtr
boost::shared_ptr< VersionedColumn > VersionedColumnPtr
Defines a smart pointer to VersionedColumn.
Definition versioned_csv_file.h:53
isc
Defines the logger used by the top-level component of kea-lfc.
Definition agent_parser.cc:148
versioned_csv_file.h