2 * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
4 * Contact: Mateusz Malicki <m.malicki2@samsung.com>
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License
21 * @author Mateusz Malicki (m.malicki2@samsung.com)
22 * @brief Definition of CommandLineInterface class
26 #include "command-line-interface.hpp"
27 #include "vasum-client.h"
28 #include "utils/c-array.hpp"
41 #include <linux/if_link.h>
42 #include <arpa/inet.h>
51 VsmClient CommandLineInterface::client = NULL;
55 std::string zoneStateToString(const VsmZoneState& state)
59 case STOPPED: name = "STOPPED"; break;
60 case STARTING: name = "STARTING"; break;
61 case RUNNING: name = "RUNNING"; break;
62 case STOPPING: name = "STOPPING"; break;
63 case ABORTING: name = "ABORTING"; break;
64 case FREEZING: name = "FREEZING"; break;
65 case FROZEN: name = "FROZEN"; break;
66 case THAWED: name = "THAWED"; break;
67 case LOCKED: name = "LOCKED"; break;
68 case MAX_STATE: name = "MAX_STATE"; break;
69 case ACTIVATING: name = "ACTIVATING"; break;
70 default: name = "MAX_STATE (ERROR)";
76 std::string netdevTypeToString(const VsmNetdevType& netdevType)
80 case VSMNETDEV_VETH: type = "VETH"; break;
81 case VSMNETDEV_PHYS: type = "PHYS"; break;
82 case VSMNETDEV_MACVLAN: type = "MACVLAN"; break;
87 std::string netdevToString(const VsmNetdev& netdev)
89 std::string out = std::string("Name: ") + vsm_netdev_get_name(netdev)
90 + std::string("\nType: ") + netdevTypeToString(vsm_netdev_get_type(netdev));
94 typedef vector<vector<string>> Table;
96 ostream& operator<<(ostream& out, const Table& table)
99 for (const auto& row : table) {
100 if (sizes.size() < row.size()) {
101 sizes.resize(row.size());
103 for (size_t i = 0; i < row.size(); ++i) {
104 sizes[i] = max(sizes[i], row[i].length());
108 for (const auto& row : table) {
109 for (size_t i = 0; i < row.size(); ++i) {
110 out << left << setw(sizes[i]+2) << row[i];
118 enum macvlan_mode macvlanFromString(const std::string& mode) {
119 if (mode == "private") {
120 return MACVLAN_MODE_PRIVATE;
122 if (mode == "vepa") {
123 return MACVLAN_MODE_VEPA;
125 if (mode == "bridge") {
126 return MACVLAN_MODE_BRIDGE;
128 if (mode == "passthru") {
129 return MACVLAN_MODE_PASSTHRU;
131 throw runtime_error("Unsupported macvlan mode");
134 void buildZoneList(std::vector<std::string>& list)
136 using namespace std::placeholders;
139 CommandLineInterface::executeCallback(bind(vsm_get_zone_ids, _1, &ids));
140 for (VsmString* id = ids; *id; ++id) {
143 vsm_array_string_free(ids);
148 const std::vector<std::string> CommandLineInterface::buildCompletionList(const Args& a) const
150 std::vector<std::string> v;
152 if (a.size() > mArgsSpec.size() + 1) {
156 ArgSpec as = mArgsSpec[a.size() - 2];
157 string::size_type s = 0U;
158 string::size_type e = s;
159 while (e != string::npos) {
160 e = as.format.find('|', s);
161 std::string ss = as.format.substr(s, e - s);
164 if (ss == "{ZONE}") {
167 else if (ss == "{NETDEV}") {
168 //TODO: get list of available interfaces
172 else if (ss.length() > 0) {
180 void CommandLineInterface::connect()
183 if (CommandLineInterface::client != nullptr) {
187 CommandLineInterface::client = vsm_client_create();
188 if (CommandLineInterface::client == nullptr) {
189 throw runtime_error("Can't create client");
192 status = vsm_connect(client);
193 if (VSMCLIENT_SUCCESS != status) {
194 string msg = vsm_get_status_message(CommandLineInterface::client);
195 vsm_client_free(CommandLineInterface::client);
196 CommandLineInterface::client = nullptr;
197 throw runtime_error(msg);
201 void CommandLineInterface::disconnect()
206 if (CommandLineInterface::client == nullptr) {
210 status = vsm_disconnect(CommandLineInterface::client);
211 if (VSMCLIENT_SUCCESS != status) {
212 msg = vsm_get_status_message(CommandLineInterface::client);
215 vsm_client_free(CommandLineInterface::client);
216 CommandLineInterface::client = nullptr;
218 if (VSMCLIENT_SUCCESS != status) {
219 throw runtime_error(msg);
223 void CommandLineInterface::executeCallback(const function<VsmStatus(VsmClient)>& fun)
225 CommandLineInterface::connect();
227 VsmStatus status = fun(CommandLineInterface::client);
228 if (VSMCLIENT_SUCCESS != status) {
229 throw runtime_error(vsm_get_status_message(CommandLineInterface::client));
233 const std::string& CommandLineInterface::getName() const
238 const std::string& CommandLineInterface::getDescription() const
243 void CommandLineInterface::printUsage(std::ostream& out) const
246 for (const auto& args : mArgsSpec) {
247 out << " " << args.name;
252 << "\t\t" << mDescription << "\n";
254 if (!mArgsSpec.empty()) {
255 out << "\n\tOptions\n";
256 for (const auto& args : mArgsSpec) {
257 out << "\t\t" << args.name << " -- " << args.description << "\n";
263 bool CommandLineInterface::isAvailable(unsigned int mode) const
265 return (mAvailability & mode) == mode;
268 void CommandLineInterface::execute(const Args& argv) const
270 mExecutorCallback(argv);
274 void lock_queue(const Args& /*argv*/)
276 CommandLineInterface::executeCallback(vsm_lock_queue);
279 void unlock_queue(const Args& /*argv*/)
281 CommandLineInterface::executeCallback(vsm_unlock_queue);
284 void set_active_zone(const Args& argv)
286 using namespace std::placeholders;
288 if (argv.size() < 2) {
289 throw runtime_error("Not enough parameters");
292 CommandLineInterface::executeCallback(bind(vsm_set_active_zone, _1, argv[1].c_str()));
295 void create_zone(const Args& argv)
297 using namespace std::placeholders;
299 if (argv.size() < 2) {
300 throw runtime_error("Not enough parameters");
303 if (argv.size() >= 3 && !argv[2].empty()) {
304 CommandLineInterface::executeCallback(bind(vsm_create_zone, _1, argv[1].c_str(), argv[2].c_str()));
306 CommandLineInterface::executeCallback(bind(vsm_create_zone, _1, argv[1].c_str(), nullptr));
310 void destroy_zone(const Args& argv)
312 using namespace std::placeholders;
314 if (argv.size() < 2) {
315 throw runtime_error("Not enough parameters");
318 CommandLineInterface::executeCallback(bind(vsm_destroy_zone, _1, argv[1].c_str(), 1));
321 void shutdown_zone(const Args& argv)
323 using namespace std::placeholders;
325 if (argv.size() < 2) {
326 throw runtime_error("Not enough parameters");
329 CommandLineInterface::executeCallback(bind(vsm_shutdown_zone, _1, argv[1].c_str()));
332 void start_zone(const Args& argv)
334 using namespace std::placeholders;
336 if (argv.size() < 2) {
337 throw runtime_error("Not enough parameters");
340 CommandLineInterface::executeCallback(bind(vsm_start_zone, _1, argv[1].c_str()));
343 void console_zone(const Args& argv)
345 using namespace std::placeholders;
347 if (argv.size() < 2) {
348 throw runtime_error("Not enough parameters");
352 CommandLineInterface::executeCallback(bind(vsm_lookup_zone_by_id, _1, argv[1].c_str(), &zone));
354 if (zoneStateToString(vsm_zone_get_state(zone)) != "RUNNING") {
356 throw runtime_error("Zone '" + argv[1] + "' is not running");
359 std::string zonesPath = vsm_zone_get_rootfs(zone);
360 std::string zoneRootFs = argv[1] + "/rootfs";
361 zonesPath.erase(zonesPath.length()- zoneRootFs.length(), zoneRootFs.length());
365 utils::CStringArrayBuilder args;
366 args.add("lxc-console")
368 .add("-n").add(argv[1].c_str())
369 .add("-P").add(zonesPath.c_str());
371 if (!execv("/usr/bin/lxc-console", const_cast<char* const*>(args.c_array()))) {
372 throw runtime_error("Could not log into zone");
376 void lock_zone(const Args& argv)
378 using namespace std::placeholders;
380 if (argv.size() < 2) {
381 throw runtime_error("Not enough parameters");
384 CommandLineInterface::executeCallback(bind(vsm_lock_zone, _1, argv[1].c_str()));
387 void unlock_zone(const Args& argv)
389 using namespace std::placeholders;
391 if (argv.size() < 2) {
392 throw runtime_error("Not enough parameters");
395 CommandLineInterface::executeCallback(bind(vsm_unlock_zone, _1, argv[1].c_str()));
398 void get_zones_status(const Args& argv)
400 using namespace std::placeholders;
406 if (argv.size() < 2) {
407 CommandLineInterface::executeCallback(bind(vsm_get_zone_ids, _1, &ids));
410 ids = reinterpret_cast<char**>(calloc(argv.size(), sizeof(char*)));
411 for (unsigned i = 1; i<argv.size(); ++i) {
412 ids[i - 1] = ::strdup(argv[i].c_str());
417 CommandLineInterface::executeCallback(bind(vsm_get_active_zone_id, _1, &activeId));
418 table.push_back({"Active", "Id", "State", "Terminal", "Root"});
419 for (VsmString* id = ids; *id; ++id) {
421 CommandLineInterface::executeCallback(bind(vsm_lookup_zone_by_id, _1, *id, &zone));
422 assert(string(vsm_zone_get_id(zone)) == string(*id));
423 table.push_back({string(vsm_zone_get_id(zone)) == string(activeId) ? "YES" : "NO",
424 vsm_zone_get_id(zone),
425 zoneStateToString(vsm_zone_get_state(zone)),
426 to_string(vsm_zone_get_terminal(zone)),
427 vsm_zone_get_rootfs(zone)});
430 vsm_string_free(activeId);
431 vsm_array_string_free(ids);
432 cout << table << endl;
435 void get_zone_ids(const Args& /*argv*/)
437 using namespace std::placeholders;
440 CommandLineInterface::executeCallback(bind(vsm_get_zone_ids, _1, &ids));
442 for (VsmString* id = ids; *id; ++id) {
443 cout << delim << *id;
447 vsm_array_string_free(ids);
450 void get_active_zone(const Args& /*argv*/)
452 using namespace std::placeholders;
455 CommandLineInterface::executeCallback(bind(vsm_get_active_zone_id, _1, &id));
460 void grant_device(const Args& argv)
462 using namespace std::placeholders;
464 if (argv.size() < 3) {
465 throw runtime_error("Not enough parameters");
468 uint32_t flags = O_RDWR;
469 CommandLineInterface::executeCallback(bind(vsm_grant_device, _1, argv[1].c_str(), argv[2].c_str(), flags));
472 void revoke_device(const Args& argv)
474 using namespace std::placeholders;
476 if (argv.size() < 3) {
477 throw runtime_error("Not enough parameters");
480 CommandLineInterface::executeCallback(bind(vsm_revoke_device, _1, argv[1].c_str(), argv[2].c_str()));
483 void create_netdev(const Args& argv)
485 using namespace std::placeholders;
487 if (argv.size() < 2) {
488 throw runtime_error("Not enough parameters");
491 std::string nettype = argv[2];
492 if (nettype == "phys") {
493 if (argv.size() < 4) {
494 throw runtime_error("Not enough parameters");
496 CommandLineInterface::executeCallback(bind(vsm_create_netdev_phys,
501 else if (nettype == "veth") {
502 if (argv.size() < 5) {
503 throw runtime_error("Not enough parameters");
505 CommandLineInterface::executeCallback(bind(vsm_create_netdev_veth,
511 else if (nettype == "macvlan") {
512 if (argv.size() < 6) {
513 throw runtime_error("Not enough parameters");
515 CommandLineInterface::executeCallback(bind(vsm_create_netdev_macvlan,
520 macvlanFromString(argv[5].c_str())));
523 throw runtime_error("Wrong nettype option " + nettype);
526 void destroy_netdev(const Args& argv)
528 using namespace std::placeholders;
530 if (argv.size() < 3) {
531 throw runtime_error("Not enough parameters");
533 CommandLineInterface::executeCallback(bind(vsm_destroy_netdev,
539 void netdev_list(const Args& argv)
541 using namespace std::placeholders;
543 if (argv.size() < 2) {
544 throw runtime_error("Not enough parameters");
546 if (argv.size() < 3) {
548 CommandLineInterface::executeCallback(bind(vsm_zone_get_netdevs,
553 for (VsmString* id = ids; *id; ++id) {
554 cout << delim << *id;
558 cout << "There is no network device in zone";
561 vsm_array_string_free(ids);
564 VsmNetdev netdev = NULL;
567 char buf[INET_ADDRSTRLEN|INET6_ADDRSTRLEN];
568 CommandLineInterface::executeCallback(bind(vsm_lookup_netdev_by_name,
573 cout << netdevToString(netdev) << endl;
574 vsm_netdev_free(netdev);
576 CommandLineInterface::executeCallback(bind(vsm_netdev_get_ipv4_addr,
581 if (inet_ntop(AF_INET, &ipv4, buf, INET_ADDRSTRLEN) == NULL) {
582 throw runtime_error("Wrong address received");
586 CommandLineInterface::executeCallback(bind(vsm_netdev_get_ipv6_addr,
591 if (inet_ntop(AF_INET6, &ipv6, buf, INET6_ADDRSTRLEN) == NULL) {
592 throw runtime_error("Wrong address received");
598 void netdev_add_ip_addr(const Args& argv)
600 using namespace std::placeholders;
601 if (argv.size() < 5) {
602 throw runtime_error("Not enough parameters");
604 if (argv[3].find(':') == std::string::npos) {
606 if (inet_pton(AF_INET, argv[3].c_str(), &addr) != 1) {
607 throw runtime_error("Wrong address format");
609 CommandLineInterface::executeCallback(bind(vsm_netdev_set_ipv4_addr,
614 stoi(argv[4].c_str())));
618 if (inet_pton(AF_INET6, argv[3].c_str(), &addr) != 1) {
619 throw runtime_error("Wrong address format");
621 CommandLineInterface::executeCallback(bind(vsm_netdev_set_ipv6_addr,
626 stoi(argv[4].c_str())));
630 void netdev_del_ip_addr(const Args& argv)
632 using namespace std::placeholders;
633 if (argv.size() < 5) {
634 throw runtime_error("Not enough parameters");
636 if (argv[3].find(':') == std::string::npos) {
638 if (inet_pton(AF_INET, argv[3].c_str(), &addr) != 1) {
639 throw runtime_error("Wrong address format");
641 CommandLineInterface::executeCallback(bind(vsm_netdev_del_ipv4_addr,
646 stoi(argv[4].c_str())));
650 if (inet_pton(AF_INET6, argv[3].c_str(), &addr) != 1) {
651 throw runtime_error("Wrong address format");
653 CommandLineInterface::executeCallback(bind(vsm_netdev_del_ipv6_addr,
658 stoi(argv[4].c_str())));
662 void netdev_up(const Args& argv)
664 using namespace std::placeholders;
666 if (argv.size() < 3) {
667 throw runtime_error("Not enough parameters");
669 CommandLineInterface::executeCallback(bind(vsm_netdev_up,
675 void netdev_down(const Args& argv)
677 using namespace std::placeholders;
679 if (argv.size() < 3) {
680 throw runtime_error("Not enough parameters");
682 CommandLineInterface::executeCallback(bind(vsm_netdev_down,
688 void clean_up_zones_root(const Args& /* argv */)
690 using namespace std::placeholders;
692 CommandLineInterface::executeCallback(bind(vsm_clean_up_zones_root, _1));