Skip to content

Commit 18becf4

Browse files
polycubed: fix list validation
The validation code for the list was not testing all the elements of the list, it instead was testing the list as a container. Due to this complex commands issued with a rest client were failing, for instance: curl -L -X POST --data '{"name":"hw0","ports":[{"name":"pippo"}]}' \ "http://localhost:9000/polycube/v1/helloworld/hw0/" curl -L -X POST --data \ '[{"name":"toveth1", "peer":"veth1"}, {"name":"toveth2", "peer":"veth2"}]' \ "http://localhost:9000/polycube/v1/helloworld/hw0/ports/ This commit implements a new logic that tests all the elements in a list, also a new logic fill the keys in json body of a list request is added as well. This failure was unnoticed because polycubectl does not allow to perform such complex operations in a single command. Fixes: d8d280c ("Added new REST API and validation code") Fixes: 795ce96 ("move help generation from services to daemon") Signed-off-by: Mauricio Vasquez B <[email protected]>
1 parent 7c75e4f commit 18becf4

File tree

4 files changed

+67
-7
lines changed

4 files changed

+67
-7
lines changed

src/polycubed/src/server/Resources/Body/ListResource.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,46 @@ void ListResource::SetDefaultIfMissing(nlohmann::json &body,
105105
}
106106
}
107107

108+
void ListResource::FillKeys(nlohmann::json &body, const ListKeyValues &keys) {
109+
// TODO: is there a more efficient implementation of this?
110+
for (auto &key: keys_) {
111+
for (auto &kv : keys) {
112+
if (key.Name() == kv.name) {
113+
// TODO: check if the key is present in the body and compare the data
114+
body[key.OriginalName()] = kv.value;
115+
break;
116+
}
117+
}
118+
}
119+
}
120+
121+
std::vector<Response> ListResource::BodyValidateMultiple(
122+
const std::string &cube_name, const ListKeyValues &keys,
123+
nlohmann::json &body, bool initialization) const {
124+
std::vector<Response> errors;
125+
126+
nlohmann::json jbody;
127+
if (body.empty()) {
128+
jbody = nlohmann::json::parse("[]");
129+
} else {
130+
jbody = body;
131+
}
132+
133+
if (!body.is_array()) {
134+
errors.push_back({ErrorTag::kInvalidValue, nullptr});
135+
return errors;
136+
}
137+
138+
for (auto &elem : jbody) {
139+
SetDefaultIfMissing(elem, initialization);
140+
auto body = BodyValidate(cube_name, keys, elem, initialization);
141+
errors.reserve(errors.size() + body.size());
142+
std::copy(std::begin(body), std::end(body), std::back_inserter(errors));
143+
}
144+
145+
return errors;
146+
}
147+
108148
bool ListResource::IsMandatory() const {
109149
return false;
110150
}

src/polycubed/src/server/Resources/Body/ListResource.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,16 @@ class ListResource : public virtual ParentResource {
4848
void SetDefaultIfMissing(nlohmann::json &body,
4949
bool initialization) const final;
5050

51+
/*
52+
* This function takes the keys (parsed from the url in "keys") and save
53+
* them in the body of the request
54+
*/
55+
void FillKeys(nlohmann::json &body, const ListKeyValues &keys);
56+
57+
std::vector<Response> BodyValidateMultiple(
58+
const std::string &cube_name, const ListKeyValues &keys,
59+
nlohmann::json &body, bool initialization) const;
60+
5161
const std::vector<ListKey> keys_;
5262

5363
nlohmann::json ToHelpJson() const override;

src/polycubed/src/server/Resources/Body/ParentResource.cpp

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,6 @@ std::vector<Response> ParentResource::BodyValidate(const std::string &cube_name,
6161
for (auto &child : children_) {
6262
const auto &child_name = child->Name();
6363

64-
// TODO: what are the implications of it?
65-
if (child->IsKey()) {
66-
continue;
67-
}
68-
6964
// Choices are a special case
7065
if (std::dynamic_pointer_cast<ChoiceResource>(child) != nullptr) {
7166
choices.push_back(child);
@@ -86,9 +81,18 @@ std::vector<Response> ParentResource::BodyValidate(const std::string &cube_name,
8681
errors.push_back(
8782
{ErrorTag::kInvalidValue, ::strdup(child_name.data())});
8883
} else {
89-
auto child_errors = child->BodyValidate(
90-
cube_name, keys, body_copy[child_name], initialization);
84+
std::vector<Response> child_errors;
85+
// if the child is a list, perform the check over all elements
86+
if (auto list = std::dynamic_pointer_cast<ListResource>(child)) {
87+
child_errors = list->BodyValidateMultiple(
88+
cube_name, keys, body_copy[child_name], initialization);
89+
} else {
90+
child_errors = child->BodyValidate(
91+
cube_name, keys, body_copy[child_name], initialization);
92+
}
93+
9194
errors.reserve(errors.size() + child_errors.size());
95+
9296
// remove current parsed element from the body so that in the
9397
// eventuality of choices, they will operate only on unparsed
9498
// elements. moreover, this is required for detecting unparsed

src/polycubed/src/server/Resources/Endpoint/ParentResource.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,12 @@ void ParentResource::CreateReplaceUpdate(
105105
const auto &cube_name = Service::Cube(request);
106106
ListKeyValues keys{};
107107
Keys(request, keys);
108+
109+
// fill keys if they are missing
110+
if (auto list = dynamic_cast<ListResource*>(this)) {
111+
list->FillKeys(jbody, keys);
112+
}
113+
108114
auto body_errors = BodyValidate(cube_name, keys, jbody, initialization);
109115
errors.reserve(errors.size() + body_errors.size());
110116
std::move(std::begin(body_errors), std::end(body_errors),

0 commit comments

Comments
 (0)