softwarecontainer  0.18.0-739e8d7 2017-05-04
cgroupsparser.cpp
1 /*
2  * Copyright (C) 2016-2017 Pelagicore AB
3  *
4  * Permission to use, copy, modify, and/or distribute this software for
5  * any purpose with or without fee is hereby granted, provided that the
6  * above copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
9  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
10  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR
11  * BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
12  * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
13  * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
14  * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
15  * SOFTWARE.
16  *
17  * For further information see LICENSE
18  */
19 
20 #include "cgroupsparser.h"
21 #include "cgroupsgateway.h"
22 #include "jsonparser.h"
23 
24 #include <math.h>
25 
26 namespace softwarecontainer {
27 
28 CGroupsParser::CGroupsParser()
29  : m_settings()
30 {
31 }
32 
33 std::string CGroupsParser::convertToBytes(const std::string settingValue, const int multiply)
34 {
35  long long limit_in_bytes = std::strtoll(settingValue.c_str(), NULL, 10);
36  if (limit_in_bytes == std::numeric_limits<long long>::max() ||
37  limit_in_bytes == std::numeric_limits<long long>::min()) {
38  if (errno == ERANGE) {
39  std::string errMessage = settingValue + " is out of range";
40  log_error() << errMessage;
41  throw LimitRangeError(errMessage);
42  }
43  }
44 
45  if (limit_in_bytes > llrint(std::numeric_limits<long long>::max() / multiply)) {
46  std::string errMessage = settingValue + " * " + std::to_string(multiply) + " is out of range";
47  log_error() << errMessage;
48  throw LimitRangeError(errMessage);
49  }
50 
51  limit_in_bytes *= multiply;
52  return std::to_string(limit_in_bytes);
53 }
54 
55 std::string CGroupsParser::suffixCorrection(const std::string settingValue)
56 {
57  auto suffix = settingValue.back();
58  std::string removeUnit = settingValue;
59  removeUnit.pop_back();
60 
61  if (std::isdigit(suffix)) {
62  //the value is digit already no need to do anything
63  return settingValue;
64  } else if ('K' == suffix || 'k' == suffix) {
65  //the value is Kilobyte unit convert it to byte
66  int KB = 1024;
67  return convertToBytes(removeUnit, KB);
68  } else if ('M' == suffix || 'm' == suffix) {
69  //the value is Megabyte unit convert it to byte
70  int MB = 1024 * 1024;
71  return convertToBytes(removeUnit, MB);
72  } else if ('G' == suffix || 'g' == suffix) {
73  //the value is Gigabyte unit convert it to byte
74  int GB = 1024 * 1024 * 1024;
75  return convertToBytes(removeUnit, GB);
76  }
77  std::string errMessage = "Bad suffix on setting value " + settingValue;
78  log_error() << errMessage;
79  throw BadSuffixError(errMessage);
80 }
81 
82 void CGroupsParser::parseCGroupsGatewayConfiguration(const json_t *element)
83 {
84  std::string settingKey;
85  std::string settingValue;
86 
87  if (!JSONParser::read(element, "setting", settingKey)) {
88  std::string errMessage = "Key \"setting\" either not a string or not in json configuration";
89  log_error() << errMessage;
90  throw JSonError(errMessage);
91  }
92 
93  if (!JSONParser::read(element, "value", settingValue)) {
94  std::string errMessage = "Key \"value\" either not a string or not in json configuration";
95  log_error() << errMessage;
96  throw JSonError(errMessage);
97  }
98 
99  if (("memory.limit_in_bytes" == settingKey) || ("memory.memsw.limit_in_bytes" == settingKey)) {
100  settingValue = suffixCorrection(settingValue);
101 
102  // if the new value is smaller/equal than the old value, then we don't save the new value.
103  if (m_settings.count(settingKey) != 0) {
104  if (std::stoll(m_settings[settingKey]) >= std::stoll(settingValue)) {
105  return;
106  }
107  }
108 
109  } else if (("cpu.shares" == settingKey)) {
110  int newValue;
111  try {
112  newValue = std::stoi(settingValue);
113  } catch (std::out_of_range &err) {
114  std::string errorMessage = "The value for cpu.shares is too high";
115  log_error() << errorMessage;
116  throw InvalidInputError(errorMessage);
117  } catch (std::invalid_argument &err) {
118  std::string errorMessage = "The value for cpu.shares is not an integer";
119  log_error() << errorMessage;
120  throw InvalidInputError(errorMessage);
121  }
122 
123  if (newValue < 2) {
124  std::string errorMessage = "Value of cpu.shares must be at least 2";
125  log_error() << errorMessage;
126  throw InvalidInputError(errorMessage);
127  }
128  // if the new value is smaller/equal to the old value, then we don't save the new value.
129  if (m_settings.count(settingKey) != 0) {
130  if (std::stoi(m_settings[settingKey]) >= newValue) {
131  return;
132  }
133  }
134  settingValue = std::to_string(newValue);
135  log_debug() << "Value for cpu.shares: " << settingValue;
136 
137  } else if ("net_cls.classid" == settingKey) {
138  // Should be of format 0xAAAABBBB
139  if (settingValue.find("0x") != 0 // Has to begin with 0x
140  || settingValue.length() > 10 // Can not be longer than 0x + 8
141  || settingValue.length() < 7) // Has to be at least 0xAAAAB to cover major/minor handle
142  {
143  std::string errorMessage = "net_cls.classid should be of form 0xAAAABBBB";
144  log_error() << errorMessage;
145  throw InvalidInputError(errorMessage);
146  }
147 
148  char *endPtr = NULL;
149  unsigned long int hexedValue = strtoul(settingValue.c_str(), &endPtr, 16);
150  if (0 == hexedValue || ULONG_MAX == hexedValue || ((endPtr != NULL) && *endPtr != '\0')) {
151  std::string errorMessage = "Could not parse all of net_cls.classid value as hex string";
152  log_error() << errorMessage;
153  throw InvalidInputError(errorMessage);
154  }
155 
156  } else {
157  log_warning() << settingKey << " is not supported by CGroups Gateway" ;
158  }
159 
160  // If we got this far we save the key/value pair
161  m_settings[settingKey] = settingValue;
162 }
163 
164 const std::map<std::string, std::string> &CGroupsParser::getSettings()
165 {
166  return m_settings;
167 }
168 } // namespace softwarecontainer
Developers guide to adding a config item:
static bool read(const json_t *element, const char *key, std::string &result)
Reads a string from a JSON Object.
Definition: jsonparser.cpp:51