SET(CLI_CODENAME "${PROJECT_NAME}-cli")
ADD_EXECUTABLE(${CLI_CODENAME} ${cli_SRCS})
+## Readline detection ##########################################################
+
+FIND_PATH(READLINE_INCLUDE_DIR readline/readline.h
+ HINTS ${READLINE_ROOT_DIR} PATH_SUFFIXES include)
+FIND_LIBRARY(READLINE_LIBRARY readline
+ HINTS ${READLINE_ROOT_DIR} PATH_SUFFIXES lib)
+FIND_LIBRARY(NCURSES_LIBRARY ncurses) # readline depends on libncurses
+MARK_AS_ADVANCED(READLINE_INCLUDE_DIR READLINE_LIBRARY NCURSES_LIBRARY)
+
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(Readline DEFAULT_MSG
+ READLINE_LIBRARY NCURSES_LIBRARY READLINE_INCLUDE_DIR)
+
+SET(READLINE_INCLUDE_DIRS ${READLINE_INCLUDE_DIR})
+SET(READLINE_LIBRARIES ${READLINE_LIBRARY} ${NCURSES_LIBRARY})
+INCLUDE_DIRECTORIES(${READLINE_INCLUDE_DIRS})
+TARGET_LINK_LIBRARIES(${CLI_CODENAME} ${READLINE_LIBRARIES})
## Link libraries ##############################################################
PKG_CHECK_MODULES(LIB_DEPS REQUIRED vasum)
namespace vasum {
namespace cli {
-namespace {
-
-/**
- * Invoke specific function on VsmClient
- *
- * @param fun Function to be called. It must not throw any exception.
- */
-void one_shot(const function<VsmStatus(VsmClient)>& fun)
-{
- string msg;
- VsmStatus status;
- VsmClient client;
-
- client = vsm_client_create();
- if (NULL == client) {
- msg = "Can't create client";
- goto finish;
- }
-
- status = vsm_connect(client);
- if (VSMCLIENT_SUCCESS != status) {
- msg = vsm_get_status_message(client);
- goto finish;
- }
-
- status = fun(client);
- if (VSMCLIENT_SUCCESS != status) {
- msg = vsm_get_status_message(client);
- goto finish;
- }
+VsmClient CommandLineInterface::client = NULL;
-finish:
- vsm_client_free(client);
- if (! msg.empty()) {
- throw runtime_error(msg);
- }
-}
+namespace {
template<typename T>
string stringAsInStream(const T& value)
} // namespace
+void CommandLineInterface::connect()
+{
+ string msg;
+ VsmStatus status;
+
+ CommandLineInterface::client = vsm_client_create();
+ if (NULL == CommandLineInterface::client) {
+ msg = "Can't create client";
+ goto finish;
+ }
+
+ status = vsm_connect(client);
+ if (VSMCLIENT_SUCCESS != status) {
+ msg = vsm_get_status_message(CommandLineInterface::client);
+ }
+
+finish:
+ if (!msg.empty()) {
+ vsm_client_free(CommandLineInterface::client);
+ CommandLineInterface::client = NULL;
+ throw runtime_error(msg);
+ }
+}
+
+void CommandLineInterface::disconnect()
+{
+ string msg;
+ VsmStatus status;
+
+ status = vsm_disconnect(CommandLineInterface::client);
+ if (VSMCLIENT_SUCCESS != status) {
+ msg = vsm_get_status_message(CommandLineInterface::client);
+ }
+
+ vsm_client_free(CommandLineInterface::client);
+ CommandLineInterface::client = NULL;
+
+ if (!msg.empty()) {
+ throw runtime_error(msg);
+ }
+}
+
+void CommandLineInterface::executeCallback(const function<VsmStatus(VsmClient)>& fun)
+{
+ string msg;
+ VsmStatus status;
+
+ status = fun(CommandLineInterface::client);
+ if (VSMCLIENT_SUCCESS != status) {
+ msg = vsm_get_status_message(CommandLineInterface::client);
+ }
+
+ if (!msg.empty()) {
+ throw runtime_error(msg);
+ }
+}
+const std::string& CommandLineInterface::getName() const
+{
+ return mName;
+}
+
+const std::string& CommandLineInterface::getDescription() const
+{
+ return mDescription;
+}
+
void CommandLineInterface::printUsage(std::ostream& out) const
{
- out << mUsage << "\n\n"
+ out << mName;
+ for (const auto& args : mArgsSpec) {
+ out << " " << args.first;
+ }
+
+ out << "\n\n"
<< "\tDescription\n"
- << "\t\t" << mUsageInfo << "\n";
+ << "\t\t" << mDescription << "\n";
+
if (!mArgsSpec.empty()) {
out << "\n\tOptions\n";
for (const auto& args : mArgsSpec) {
out << "\n";
}
-void CommandLineInterface::execute(int pos, int argc, const char** argv)
+bool CommandLineInterface::isAvailable(unsigned int mode) const
{
- mExecutorCallback(pos, argc, argv);
+ return (mAvailability & mode) == mode;
}
+void CommandLineInterface::execute(const Args& argv)
+{
+ mExecutorCallback(argv);
+}
+
+
+void lock_queue(const Args& /*argv*/)
+{
+ CommandLineInterface::executeCallback(vsm_lock_queue);
+}
-void set_active_zone(int pos, int argc, const char** argv)
+void unlock_queue(const Args& /*argv*/)
+{
+ CommandLineInterface::executeCallback(vsm_unlock_queue);
+}
+
+void set_active_zone(const Args& argv)
{
using namespace std::placeholders;
- if (argc <= pos + 1) {
+ if (argv.size() <= 1) {
throw runtime_error("Not enough parameters");
}
- one_shot(bind(vsm_set_active_zone, _1, argv[pos + 1]));
+ CommandLineInterface::executeCallback(bind(vsm_set_active_zone, _1, argv[1].c_str()));
}
-void create_zone(int pos, int argc, const char** argv)
+void create_zone(const Args& argv)
{
using namespace std::placeholders;
- if (argc <= pos + 1) {
+ if (argv.size() <= 1) {
throw runtime_error("Not enough parameters");
}
- one_shot(bind(vsm_create_zone, _1, argv[pos + 1], argv[pos + 2] ? argv[pos + 2] : nullptr));
+ if (argv.size() >= 3 && !argv[2].empty()) {
+ CommandLineInterface::executeCallback(bind(vsm_create_zone, _1, argv[1].c_str(), argv[2].c_str()));
+ } else {
+ CommandLineInterface::executeCallback(bind(vsm_create_zone, _1, argv[1].c_str(), nullptr));
+ }
}
-void destroy_zone(int pos, int argc, const char** argv)
+void destroy_zone(const Args& argv)
{
using namespace std::placeholders;
- if (argc <= pos + 1) {
+ if (argv.size() <= 1) {
throw runtime_error("Not enough parameters");
}
- one_shot(bind(vsm_destroy_zone, _1, argv[pos + 1], 1));
+ CommandLineInterface::executeCallback(bind(vsm_destroy_zone, _1, argv[1].c_str(), 1));
}
-void shutdown_zone(int pos, int argc, const char** argv)
+void shutdown_zone(const Args& argv)
{
using namespace std::placeholders;
- if (argc <= pos + 1) {
+ if (argv.size() <= 1) {
throw runtime_error("Not enough parameters");
}
- one_shot(bind(vsm_shutdown_zone, _1, argv[pos + 1]));
+ CommandLineInterface::executeCallback(bind(vsm_shutdown_zone, _1, argv[1].c_str()));
}
-void start_zone(int pos, int argc, const char** argv)
+void start_zone(const Args& argv)
{
using namespace std::placeholders;
- if (argc <= pos + 1) {
+ if (argv.size() <= 1) {
throw runtime_error("Not enough parameters");
}
- one_shot(bind(vsm_start_zone, _1, argv[pos + 1]));
+ CommandLineInterface::executeCallback(bind(vsm_start_zone, _1, argv[1].c_str()));
}
-void lock_zone(int pos, int argc, const char** argv)
+void lock_zone(const Args& argv)
{
using namespace std::placeholders;
- if (argc <= pos + 1) {
+ if (argv.size() <= 1) {
throw runtime_error("Not enough parameters");
}
- one_shot(bind(vsm_lock_zone, _1, argv[pos + 1]));
+ CommandLineInterface::executeCallback(bind(vsm_lock_zone, _1, argv[1].c_str()));
}
-void unlock_zone(int pos, int argc, const char** argv)
+void unlock_zone(const Args& argv)
{
using namespace std::placeholders;
- if (argc <= pos + 1) {
+ if (argv.size() <= 1) {
throw runtime_error("Not enough parameters");
}
- one_shot(bind(vsm_unlock_zone, _1, argv[pos + 1]));
+ CommandLineInterface::executeCallback(bind(vsm_unlock_zone, _1, argv[1].c_str()));
}
-void get_zones_status(int /* pos */, int /* argc */, const char** /* argv */)
+void get_zones_status(const Args& /* argv */)
{
using namespace std::placeholders;
VsmString activeId;
Table table;
- one_shot(bind(vsm_get_zone_ids, _1, &ids));
- one_shot(bind(vsm_get_active_zone_id, _1, &activeId));
+ CommandLineInterface::executeCallback(bind(vsm_get_zone_ids, _1, &ids));
+ CommandLineInterface::executeCallback(bind(vsm_get_active_zone_id, _1, &activeId));
table.push_back({"Active", "Id", "State", "Terminal", "Root"});
for (VsmString* id = ids; *id; ++id) {
VsmZone zone;
- one_shot(bind(vsm_lookup_zone_by_id, _1, *id, &zone));
+ CommandLineInterface::executeCallback(bind(vsm_lookup_zone_by_id, _1, *id, &zone));
assert(string(zone->id) == string(*id));
table.push_back({string(zone->id) == string(activeId) ? "*" : "",
zone->id,
cout << table << endl;
}
-void get_zone_ids(int /* pos */, int /* argc */, const char** /* argv */)
+void get_zone_ids(const Args& /*argv*/)
{
using namespace std::placeholders;
VsmArrayString ids;
- one_shot(bind(vsm_get_zone_ids, _1, &ids));
+ CommandLineInterface::executeCallback(bind(vsm_get_zone_ids, _1, &ids));
string delim;
for (VsmString* id = ids; *id; ++id) {
cout << delim << *id;
vsm_array_string_free(ids);
}
-void get_active_zone_id(int /* pos */, int /* argc */, const char** /* argv */)
+void get_active_zone_id(const Args& /*argv*/)
{
using namespace std::placeholders;
VsmString id;
- one_shot(bind(vsm_get_active_zone_id, _1, &id));
+ CommandLineInterface::executeCallback(bind(vsm_get_active_zone_id, _1, &id));
cout << id << endl;
vsm_string_free(id);
}
-void lookup_zone_by_id(int pos, int argc, const char** argv)
+void lookup_zone_by_id(const Args& argv)
{
using namespace std::placeholders;
- if (argc <= pos + 1) {
+ if (argv.size() <= 1) {
throw runtime_error("Not enough parameters");
}
VsmZone zone;
- one_shot(bind(vsm_lookup_zone_by_id, _1, argv[pos + 1], &zone));
+ CommandLineInterface::executeCallback(bind(vsm_lookup_zone_by_id, _1, argv[1].c_str(), &zone));
cout << zone << endl;
vsm_zone_free(zone);
}
-void grant_device(int pos, int argc, const char** argv)
+void grant_device(const Args& argv)
{
using namespace std::placeholders;
- if (argc <= pos + 2) {
+ if (argv.size() <= 2) {
throw runtime_error("Not enough parameters");
}
uint32_t flags = O_RDWR;
- one_shot(bind(vsm_grant_device, _1, argv[pos + 1], argv[pos + 2], flags));
+ CommandLineInterface::executeCallback(bind(vsm_grant_device, _1, argv[1].c_str(), argv[2].c_str(), flags));
}
-void revoke_device(int pos, int argc, const char** argv)
+void revoke_device(const Args& argv)
{
using namespace std::placeholders;
- if (argc <= pos + 2) {
+ if (argv.size() <= 2) {
throw runtime_error("Not enough parameters");
}
- one_shot(bind(vsm_revoke_device, _1, argv[pos + 1], argv[pos + 2]));
+ CommandLineInterface::executeCallback(bind(vsm_revoke_device, _1, argv[1].c_str(), argv[2].c_str()));
}
-void create_netdev_veth(int pos, int argc, const char** argv)
+void create_netdev_veth(const Args& argv)
{
using namespace std::placeholders;
- if (argc <= pos + 3) {
+ if (argv.size() <= 3) {
throw runtime_error("Not enough parameters");
}
- one_shot(bind(vsm_create_netdev_veth,
+ CommandLineInterface::executeCallback(bind(vsm_create_netdev_veth,
_1,
- argv[pos + 1],
- argv[pos + 2],
- argv[pos + 3]));
+ argv[1].c_str(),
+ argv[2].c_str(),
+ argv[3].c_str()));
}
-void create_netdev_macvlan(int pos, int argc, const char** argv)
+void create_netdev_macvlan(const Args& argv)
{
using namespace std::placeholders;
- if (argc <= pos + 4) {
+ if (argv.size() <= 4) {
throw runtime_error("Not enough parameters");
}
- one_shot(bind(vsm_create_netdev_macvlan,
+ CommandLineInterface::executeCallback(bind(vsm_create_netdev_macvlan,
_1,
- argv[pos + 1],
- argv[pos + 2],
- argv[pos + 3],
- macvlanFromString(argv[pos + 4])));
+ argv[1].c_str(),
+ argv[2].c_str(),
+ argv[3].c_str(),
+ macvlanFromString(argv[4].c_str())));
}
-void create_netdev_phys(int pos, int argc, const char** argv)
+void create_netdev_phys(const Args& argv)
{
using namespace std::placeholders;
- if (argc <= pos + 2) {
+ if (argv.size() <= 2) {
throw runtime_error("Not enough parameters");
}
- one_shot(bind(vsm_create_netdev_phys,
+ CommandLineInterface::executeCallback(bind(vsm_create_netdev_phys,
_1,
- argv[pos + 1],
- argv[pos + 2]));
+ argv[1].c_str(),
+ argv[2].c_str()));
}
-void lookup_netdev_by_name(int pos, int argc, const char** argv)
+void lookup_netdev_by_name(const Args& argv)
{
using namespace std::placeholders;
- if (argc <= pos + 2) {
+ if (argv.size() <= 2) {
throw runtime_error("Not enough parameters");
}
VsmNetdev vsmNetdev = NULL;
- one_shot(bind(vsm_lookup_netdev_by_name,
+ CommandLineInterface::executeCallback(bind(vsm_lookup_netdev_by_name,
_1,
- argv[pos + 1],
- argv[pos + 2],
+ argv[1].c_str(),
+ argv[2].c_str(),
&vsmNetdev));
cout << vsmNetdev << endl;
vsm_netdev_free(vsmNetdev);
}
-void destroy_netdev(int pos, int argc, const char** argv)
+void destroy_netdev(const Args& argv)
{
using namespace std::placeholders;
- if (argc <= pos + 2) {
+ if (argv.size() <= 2) {
throw runtime_error("Not enough parameters");
}
- one_shot(bind(vsm_destroy_netdev,
+ CommandLineInterface::executeCallback(bind(vsm_destroy_netdev,
_1,
- argv[pos + 1],
- argv[pos + 2]));
+ argv[1].c_str(),
+ argv[2].c_str()));
}
-void zone_get_netdevs(int pos, int argc, const char** argv)
+void zone_get_netdevs(const Args& argv)
{
using namespace std::placeholders;
- if (argc <= pos + 1) {
+ if (argv.size() <= 1) {
throw runtime_error("Not enough parameters");
}
VsmArrayString ids;
- one_shot(bind(vsm_zone_get_netdevs,
+ CommandLineInterface::executeCallback(bind(vsm_zone_get_netdevs,
_1,
- argv[pos + 1],
+ argv[1].c_str(),
&ids));
string delim;
for (VsmString* id = ids; *id; ++id) {
vsm_array_string_free(ids);
}
-void netdev_get_ipv4_addr(int pos, int argc, const char** argv)
+void netdev_get_ipv4_addr(const Args& argv)
{
using namespace std::placeholders;
- if (argc <= pos + 2) {
+ if (argv.size() <= 2) {
throw runtime_error("Not enough parameters");
}
in_addr addr;
- one_shot(bind(vsm_netdev_get_ipv4_addr,
+ CommandLineInterface::executeCallback(bind(vsm_netdev_get_ipv4_addr,
_1,
- argv[pos + 1],
- argv[pos + 2],
+ argv[1].c_str(),
+ argv[2].c_str(),
&addr));
char buf[INET_ADDRSTRLEN];
if (inet_ntop(AF_INET, &addr, buf, INET_ADDRSTRLEN) == NULL) {
cout << buf << endl;
}
-void netdev_get_ipv6_addr(int pos, int argc, const char** argv)
+void netdev_get_ipv6_addr(const Args& argv)
{
using namespace std::placeholders;
- if (argc <= pos + 2) {
+ if (argv.size() <= 2) {
throw runtime_error("Not enough parameters");
}
in6_addr addr;
- one_shot(bind(vsm_netdev_get_ipv6_addr,
+ CommandLineInterface::executeCallback(bind(vsm_netdev_get_ipv6_addr,
_1,
- argv[pos + 1],
- argv[pos + 2],
+ argv[1].c_str(),
+ argv[2].c_str(),
&addr));
char buf[INET6_ADDRSTRLEN];
if (inet_ntop(AF_INET6, &addr, buf, INET6_ADDRSTRLEN) == NULL) {
cout << buf << endl;
}
-void netdev_set_ipv4_addr(int pos, int argc, const char** argv)
+void netdev_set_ipv4_addr(const Args& argv)
{
using namespace std::placeholders;
- if (argc <= pos + 4) {
+ if (argv.size() <= 4) {
throw runtime_error("Not enough parameters");
}
in_addr addr;
- if (inet_pton(AF_INET, argv[pos + 3], &addr) != 1) {
+ if (inet_pton(AF_INET, argv[3].c_str(), &addr) != 1) {
throw runtime_error("Wrong address format");
};
- one_shot(bind(vsm_netdev_set_ipv4_addr,
+ CommandLineInterface::executeCallback(bind(vsm_netdev_set_ipv4_addr,
_1,
- argv[pos + 1],
- argv[pos + 2],
+ argv[1].c_str(),
+ argv[2].c_str(),
&addr,
- stoi(argv[pos + 4])));
+ stoi(argv[4].c_str())));
}
-void netdev_set_ipv6_addr(int pos, int argc, const char** argv)
+void netdev_set_ipv6_addr(const Args& argv)
{
using namespace std::placeholders;
- if (argc <= pos + 4) {
+ if (argv.size() <= 4) {
throw runtime_error("Not enough parameters");
}
in6_addr addr;
- if (inet_pton(AF_INET6, argv[pos + 3], &addr) != 1) {
+ if (inet_pton(AF_INET6, argv[3].c_str(), &addr) != 1) {
throw runtime_error("Wrong address format");
};
- one_shot(bind(vsm_netdev_set_ipv6_addr,
+ CommandLineInterface::executeCallback(bind(vsm_netdev_set_ipv6_addr,
_1,
- argv[pos + 1],
- argv[pos + 2],
+ argv[1].c_str(),
+ argv[2].c_str(),
&addr,
- stoi(argv[pos + 4])));
+ stoi(argv[4].c_str())));
}
-void netdev_up(int pos, int argc, const char** argv)
+void netdev_up(const Args& argv)
{
using namespace std::placeholders;
- if (argc <= pos + 2) {
+ if (argv.size() <= 2) {
throw runtime_error("Not enough parameters");
}
- one_shot(bind(vsm_netdev_up,
+ CommandLineInterface::executeCallback(bind(vsm_netdev_up,
_1,
- argv[pos + 1],
- argv[pos + 2]));
+ argv[1].c_str(),
+ argv[2].c_str()));
}
-void netdev_down(int pos, int argc, const char** argv)
+void netdev_down(const Args& argv)
{
using namespace std::placeholders;
- if (argc <= pos + 2) {
+ if (argv.size() <= 2) {
throw runtime_error("Not enough parameters");
}
- one_shot(bind(vsm_netdev_down,
+ CommandLineInterface::executeCallback(bind(vsm_netdev_down,
_1,
- argv[pos + 1],
- argv[pos + 2]));
+ argv[1].c_str(),
+ argv[2].c_str()));
}
} // namespace cli
#ifndef CLI_COMMAND_LINE_INTERFACE_HPP
#define CLI_COMMAND_LINE_INTERFACE_HPP
+#include <vasum-client.h>
+
#include <map>
#include <vector>
#include <functional>
namespace vasum {
namespace cli {
+#define MODE_COMMAND_LINE (1 << 0)
+#define MODE_INTERACTIVE (1 << 1)
+
+typedef std::vector<std::string> Args;
+
/**
* Class that implements command pattern.
*/
/**
* @see CommandLineInterface::execute
*/
- typedef std::function<void(int, int, const char**)> ExecutorCallback;
+ typedef std::function<void(const Args& argv)> ExecutorCallback;
/**
* @see CommandLineInterface::CommandLineInterface
/**
* Dummy constructor (for stl usage)
*/
- CommandLineInterface() {}
+ CommandLineInterface()
+ : mAvailability(0) {}
/**
* Construct command
* @param argsSpec Description of arguments
*/
CommandLineInterface(const ExecutorCallback& executorCallback,
- const std::string& usage,
- const std::string& usageInfo,
+ const std::string& name,
+ const std::string& description,
+ const unsigned int& availability,
const ArgsSpec& argsSpec)
: mExecutorCallback(executorCallback),
- mUsage(usage),
- mUsageInfo(usageInfo),
+ mName(name),
+ mDescription(description),
+ mAvailability(availability),
mArgsSpec(argsSpec) {}
/**
+ * Set the class (static) in a connected state.
+ * This persistent connection to the vasum client is required
+ * for calls like lock/unlock queue to work.
+ */
+ static void connect();
+
+ /**
+ * Disconnect the class from a vasum client.
+ */
+ static void disconnect();
+
+ /**
+ * Execute a callback passing the connected VsmClient.
+ *
+ * @param fun A callback to execute
+ */
+ static void executeCallback(const std::function<VsmStatus(VsmClient)>& fun);
+
+ /**
+ * Get the command name
+ */
+ const std::string& getName() const;
+
+ /**
+ * Get the command description
+ *
+ * @param out Output stream
+ */
+ const std::string& getDescription() const;
+
+ /**
* Print usage to stream
*
* @param out Output stream
void printUsage(std::ostream& out) const;
/**
+ * Check if the command is available in specific mode
+ *
+ * @param mode A mode to check the command's availability in
+ */
+ bool isAvailable(unsigned int mode) const;
+
+ /**
* Do the work
*
* It calls the callback passed in constructor
* @param argc Number of elements in argv
* @param argv Command line arguments
*/
- void execute(int pos, int argc, const char** argv);
+ void execute(const Args& argv);
private:
+ static VsmClient client;
+
const ExecutorCallback mExecutorCallback;
- const std::string mUsage;
- const std::string mUsageInfo;
+ const std::string mName;
+ const std::string mDescription;
+ const unsigned int mAvailability;
const ArgsSpec mArgsSpec;
};
*
* @see vsm_set_active_zone
*/
-void set_active_zone(int pos, int argc, const char** argv);
+void lock_queue(const Args& argv);
+
+/**
+ * Parses command line arguments and call vsm_set_active_zone
+ *
+ * @see vsm_set_active_zone
+ */
+void unlock_queue(const Args& argv);
+
+/**
+ * Parses command line arguments and call vsm_set_active_zone
+ *
+ * @see vsm_set_active_zone
+ */
+void set_active_zone(const Args& argv);
/**
* Parses command line arguments and call vsm_create_zone
*
* @see vsm_create_zone
*/
-void create_zone(int pos, int argc, const char** argv);
+void create_zone(const Args& argv);
/**
* Parses command line arguments and call vsm_destroy_zone
*
* @see vsm_destroy_zone
*/
-void destroy_zone(int pos, int argc, const char** argv);
+void destroy_zone(const Args& argv);
/**
* Parses command line arguments and call vsm_shutdown_zone
*
* @see vsm_shutdown_zone
*/
-void shutdown_zone(int pos, int argc, const char** argv);
+void shutdown_zone(const Args& argv);
/**
* Parses command line arguments and call vsm_start_zone
*
* @see vsm_start_zone
*/
-void start_zone(int pos, int argc, const char** argv);
+void start_zone(const Args& argv);
/**
* Parses command line arguments and call vsm_lock_zone
*
* @see vsm_lock_zone
*/
-void lock_zone(int pos, int argc, const char** argv);
+void lock_zone(const Args& argv);
/**
* Parses command line arguments and call vsm_unlock_zone
*
* @see vsm_unlock_zone
*/
-void unlock_zone(int pos, int argc, const char** argv);
+void unlock_zone(const Args& argv);
/**
* Parses command line arguments and prints list of zone with
* some useful informations (id, state, terminal, root path)
*/
-void get_zones_status(int pos, int argc, const char** argv);
+void get_zones_status(const Args& argv);
/**
* Parses command line arguments and call vsm_get_zone_ids
*
* @see vsm_get_zone_ids
*/
-void get_zone_ids(int pos, int argc, const char** argv);
+void get_zone_ids(const Args& argv);
/**
* Parses command line arguments and call vsm_get_active_zone_id
*
* @see vsm_get_active_zone_id
*/
-void get_active_zone_id(int pos, int argc, const char** argv);
+void get_active_zone_id(const Args& argv);
/**
* Parses command line arguments and call vsm_lookup_zone_by_id
*
* @see vsm_lookup_zone_by_id
*/
-void lookup_zone_by_id(int pos, int argc, const char** argv);
+void lookup_zone_by_id(const Args& argv);
/**
* Parses command line arguments and call vsm_grant_device
*
* @see vsm_grant_device
*/
-void grant_device(int pos, int argc, const char** argv);
+void grant_device(const Args& argv);
/**
* Parses command line arguments and call vsm_revoke_device
*
* @see vsm_revoke_device
*/
-void revoke_device(int pos, int argc, const char** argv);
+void revoke_device(const Args& argv);
/**
* Parses command line arguments and call vsm_create_netdev_veth
*
* @see vsm_create_netdev_veth
*/
-void create_netdev_veth(int pos, int argc, const char** argv);
+void create_netdev_veth(const Args& argv);
/**
* Parses command line arguments and call vsm_create_netdev_macvlan
*
* @see vsm_create_netdev_macvlan
*/
-void create_netdev_macvlan(int pos, int argc, const char** argv);
+void create_netdev_macvlan(const Args& argv);
/**
* Parses command line arguments and call vsm_create_netdev_phys
*
* @see vsm_create_netdev_phys
*/
-void create_netdev_phys(int pos, int argc, const char** argv);
+void create_netdev_phys(const Args& argv);
/**
* Parses command line arguments and call vsm_lookup_netdev_by_name
*
* @see vsm_lookup_netdev_by_name
*/
-void lookup_netdev_by_name(int pos, int argc, const char** argv);
+void lookup_netdev_by_name(const Args& argv);
/**
* Parses command line arguments and call vsm_destroy_netdev
*
* @see vsm_destroy_netdev
*/
-void destroy_netdev(int pos, int argc, const char** argv);
+void destroy_netdev(const Args& argv);
/**
* Parses command line arguments and prints result of vsm_zone_get_netdevs
*
* @see vsm_zone_get_netdevs
*/
-void zone_get_netdevs(int pos, int argc, const char** argv);
+void zone_get_netdevs(const Args& argv);
/**
* Parses command line arguments and prints result of vsm_netdev_get_ipv4_addr
*
* @see vsm_netdev_get_ipv4_addr
*/
-void netdev_get_ipv4_addr(int pos, int argc, const char** argv);
+void netdev_get_ipv4_addr(const Args& argv);
/**
* Parses command line arguments and and prints result of vsm_netdev_get_ipv6_addr
*
* @see vsm_netdev_get_ipv6_addr
*/
-void netdev_get_ipv6_addr(int pos, int argc, const char** argv);
+void netdev_get_ipv6_addr(const Args& argv);
/**
* Parses command line arguments and call vsm_netdev_set_ipv4_addr
*
* @see vsm_netdev_set_ipv4_addr
*/
-void netdev_set_ipv4_addr(int pos, int argc, const char** argv);
+void netdev_set_ipv4_addr(const Args& argv);
/**
* Parses command line arguments and call vsm_netdev_set_ipv6_addr
*
* @see vsm_netdev_set_ipv6_addr
*/
-void netdev_set_ipv6_addr(int pos, int argc, const char** argv);
+void netdev_set_ipv6_addr(const Args& argv);
/**
* Parses command line arguments and call vsm_netdev_up
*
* @see vsm_netdev_up
*/
-void netdev_up(int pos, int argc, const char** argv);
+void netdev_up(const Args& argv);
/**
* Parses command line arguments and call vsm_netdev_down
*
* @see vsm_netdev_down
*/
-void netdev_down(int pos, int argc, const char** argv);
+void netdev_down(const Args& argv);
} // namespace cli
} // namespace vasum
#include <string>
#include <iostream>
#include <algorithm>
+#include <sstream>
+#include <iterator>
+#include <iomanip>
+#include <readline/readline.h>
+#include <readline/history.h>
using namespace vasum::cli;
std::map<std::string, CommandLineInterface> commands = {
{
+ "lock_queue", {
+ lock_queue,
+ "lock_queue",
+ "Exclusively lock the command queue",
+ MODE_INTERACTIVE,
+ {}
+ }
+ },
+ {
+ "unlock_queue", {
+ unlock_queue,
+ "unlock_queue",
+ "Unlock the queue",
+ MODE_INTERACTIVE,
+ {}
+ }
+ },
+ {
"set_active_zone", {
set_active_zone,
- "set_active_zone zone_id",
+ "set_active_zone",
"Set active (foreground) zone",
+ MODE_COMMAND_LINE | MODE_INTERACTIVE,
{{"zone_id", "id zone name"}}
}
},
{
"create_zone", {
create_zone,
- "create_zone zone_id [zone_tname]",
+ "create_zone",
"Create and add zone",
+ MODE_COMMAND_LINE | MODE_INTERACTIVE,
{{"zone_id", "id zone name"},
{"[zone_tname]", "optional zone template name"}}
}
{
"destroy_zone", {
destroy_zone,
- "destroy_zone zone_id",
+ "destroy_zone",
"Destroy zone",
+ MODE_COMMAND_LINE | MODE_INTERACTIVE,
{{"zone_id", "id zone name"}}
}
},
{
"shutdown_zone", {
shutdown_zone,
- "shutdown_zone zone_id",
+ "shutdown_zone",
"Shutdown zone",
+ MODE_COMMAND_LINE | MODE_INTERACTIVE,
{{"zone_id", "id zone name"}}
}
},
{
"start_zone", {
start_zone,
- "start_zone zone_id",
+ "start_zone",
"Start zone",
+ MODE_COMMAND_LINE | MODE_INTERACTIVE,
{{"zone_id", "id zone name"}}
}
},
{
"lock_zone", {
lock_zone,
- "lock_zone zone_id",
+ "lock_zone",
"Lock zone",
+ MODE_COMMAND_LINE | MODE_INTERACTIVE,
{{"zone_id", "id zone name"}}
}
},
{
"unlock_zone", {
unlock_zone,
- "unlock_zone zone_id",
+ "unlock_zone",
"Unlock zone",
+ MODE_COMMAND_LINE | MODE_INTERACTIVE,
{{"zone_id", "id zone name"}}
}
},
get_zones_status,
"get_zones_status",
"Get list of zone with some useful informations (id, state, terminal, root path)",
+ MODE_COMMAND_LINE | MODE_INTERACTIVE,
{}
}
},
get_zone_ids,
"get_zone_ids",
"Get all zone ids",
+ MODE_COMMAND_LINE | MODE_INTERACTIVE,
{}
}
},
get_active_zone_id,
"get_active_zone_id",
"Get active (foreground) zone ids",
+ MODE_COMMAND_LINE | MODE_INTERACTIVE,
{}
}
},
{
"lookup_zone_by_id", {
lookup_zone_by_id,
- "lookup_zone_by_id zone_id",
+ "lookup_zone_by_id",
"Prints informations about zone",
+ MODE_COMMAND_LINE | MODE_INTERACTIVE,
{{"zone_id", "id zone name"}}
}
},
{
"grant_device", {
grant_device,
- "grant_device zone_id device_name",
+ "grant_device",
"Grants access to the given device",
+ MODE_COMMAND_LINE | MODE_INTERACTIVE,
{{"zone_id", "id zone name"},
{"device_name", " device name"}}
}
{
"revoke_device", {
revoke_device,
- "revoke_device zone_id device_name",
+ "revoke_device",
"Revokes access to the given device",
+ MODE_COMMAND_LINE | MODE_INTERACTIVE,
{{"zone_id", "id zone name"},
{"device_name", " device name"}}
}
{
"create_netdev_veth", {
create_netdev_veth,
- "create_netdev_veth zone_id zone_netdev_id host_netdev_id",
+ "create_netdev_veth",
"Create netdev in zone",
+ MODE_COMMAND_LINE | MODE_INTERACTIVE,
{{"zone_id", "id zone name"},
{"zone_netdev_id", "network device id"},
{"host_netdev_id", "host bridge id"}}
{
"create_netdev_macvlan", {
create_netdev_macvlan,
- "create_netdev_macvlan zone_id zone_netdev_id host_netdev_id mode",
+ "create_netdev_macvlan",
"Create netdev in zone",
+ MODE_COMMAND_LINE | MODE_INTERACTIVE,
{{"zone_id", "id zone name"},
{"zone_netdev_id", "network device id"},
{"host_netdev_id", "host bridge id"},
{
"create_netdev_phys", {
create_netdev_phys,
- "create_netdev_phys zone_id netdev_id",
+ "create_netdev_phys",
"Create/move netdev to zone",
+ MODE_COMMAND_LINE | MODE_INTERACTIVE,
{{"zone_id", "id zone name"},
{"netdev_id", "network device name"}}
}
{
"lookup_netdev_by_name", {
lookup_netdev_by_name,
- "lookup_netdev_by_name zone_id netdev_id",
+ "lookup_netdev_by_name",
"Get netdev flags",
+ MODE_COMMAND_LINE | MODE_INTERACTIVE,
{{"zone_id", "id zone name"},
{"netdev_id", "network device name"}}
}
{
"destroy_netdev", {
destroy_netdev,
- "destroy_netdev zone_id devId",
+ "destroy_netdev",
"Destroy netdev in zone",
+ MODE_COMMAND_LINE | MODE_INTERACTIVE,
{{"zone_id", "id zone name"},
{"netdev_id", "network device name"}}
}
{
"zone_get_netdevs", {
zone_get_netdevs,
- "zone_get_netdevs zone_id",
+ "zone_get_netdevs",
"List network devices in the zone",
+ MODE_COMMAND_LINE | MODE_INTERACTIVE,
{{"zone_id", "id zone name"}}
}
},
{
"netdev_get_ipv4_addr", {
netdev_get_ipv4_addr,
- "netdev_get_ipv4_addr zone_id netdev_id",
+ "netdev_get_ipv4_addr",
"Get ipv4 address",
+ MODE_COMMAND_LINE | MODE_INTERACTIVE,
{{"zone_id", "id zone name"},
{"netdev_id", "network device name"}}
}
{
"netdev_get_ipv6_addr", {
netdev_get_ipv6_addr,
- "netdev_get_ipv6_addr zone_id netdev_id",
+ "netdev_get_ipv6_addr",
"Get ipv6 address",
+ MODE_COMMAND_LINE | MODE_INTERACTIVE,
{{"zone_id", "id zone name"},
{"netdev_id", "network device name"}}
}
{
"netdev_set_ipv4_addr", {
netdev_set_ipv4_addr,
- "netdev_set_ipv4_addr zone_id netdev_id address prefix_len",
+ "netdev_set_ipv4_addr",
"Set ipv4 address",
+ MODE_COMMAND_LINE | MODE_INTERACTIVE,
{{"zone_id", "id zone name"},
{"netdev_id", "network device name"},
{"address", "ipv4 address"},
{
"netdev_set_ipv6_addr", {
netdev_set_ipv6_addr,
- "netdev_set_ipv6_addr zone_id netdev_id address prefix_len",
+ "netdev_set_ipv6_addr",
"Set ipv6 address",
+ MODE_COMMAND_LINE | MODE_INTERACTIVE,
{{"zone_id", "id zone name"},
{"netdev_id", "network device name"},
{"address", "ipv6 address"},
{
"netdev_up", {
netdev_up,
- "netdev_up zone_id netdev_id",
+ "netdev_up",
"Turn up a network device in the zone",
+ MODE_COMMAND_LINE | MODE_INTERACTIVE,
{{"zone_id", "id zone name"},
{"netdev_id", "network device id"}}
}
{
"netdev_down", {
netdev_down,
- "netdev_down zone_id netdev_id",
+ "netdev_down",
"Turn down a network device in the zone",
+ MODE_COMMAND_LINE | MODE_INTERACTIVE,
{{"zone_id", "id zone name"},
{"netdev_id", "network device id"}}
}
{
"zone_get_netdevs", {
zone_get_netdevs,
- "zone_get_netdevs zone_id",
+ "zone_get_netdevs",
"Turn down a network device in the zone",
+ MODE_COMMAND_LINE | MODE_INTERACTIVE,
{{"zone_id", "id zone name"},
{"netdev_id", "network device id"}}
}
}
};
-void printUsage(std::ostream& out, const std::string& name)
+// wrappers for CommandLineInterface
+
+void printUsage(std::ostream& out, const std::string& name, unsigned int mode)
{
- out << "Usage: " << name << " [command [-h|args]]\n\n"
- << "command can be one of the following:\n";
+ std::string n;
+ if (!name.empty()) {
+ n = name + " ";
+ }
+
+ out << "Usage: " << n << "[<command>] [-h|<args>]\n\n";
+ if (mode == MODE_COMMAND_LINE) {
+ out << "Called without parameters enters interactive mode.\n\n";
+ }
+ out << "command can be one of the following:\n";
for (const auto& command : commands) {
- command.second.printUsage(out);
+ if (command.second.isAvailable(mode)) {
+ out << " " << std::setw(30) << std::left << command.second.getName()
+ << command.second.getDescription() << "\n";
+ }
}
+
+ out << "\nSee " << n << "command -h to read about a specific one.\n";
}
-} // namespace
+int connect()
+{
+ try {
+ CommandLineInterface::connect();
+ } catch (const std::runtime_error& ex) {
+ std::cerr << ex.what() << std::endl;
+ return EXIT_FAILURE;
+ }
-int main(const int argc, const char** argv)
+ return EXIT_SUCCESS;
+}
+
+int disconnect()
{
- if (argc < 2) {
- printUsage(std::cout, argv[0]);
+ try {
+ CommandLineInterface::disconnect();
+ } catch (const std::runtime_error& ex) {
+ std::cerr << ex.what() << std::endl;
return EXIT_FAILURE;
}
- if (commands.count(argv[1]) == 0) {
- printUsage(std::cout, argv[0]);
+
+ return EXIT_SUCCESS;
+}
+
+int executeCommand(const Args& argv, int mode)
+{
+ auto pair = commands.find(argv[0]);
+ if (pair == commands.end()) {
+ return EXIT_FAILURE;
+ }
+
+ CommandLineInterface& command = pair->second;
+ if (!command.isAvailable(mode)) {
return EXIT_FAILURE;
}
- CommandLineInterface& command = commands[argv[1]];
- auto it = std::find(argv, argv+argc, std::string("-h"));
- if (it != argv + argc) {
+ auto it = std::find(argv.begin(), argv.end(), std::string("-h"));
+ if (it != argv.end()) {
command.printUsage(std::cout);
return EXIT_SUCCESS;
}
try {
- command.execute(1, argc, argv);
+ command.execute(argv);
} catch (const std::runtime_error& ex) {
std::cerr << ex.what() << std::endl;
return EXIT_FAILURE;
}
+
+ return EXIT_SUCCESS;
+}
+
+// readline completion support
+
+char* object_generator(const char* text, int state)
+{
+ static std::vector<std::string> objs;
+ static size_t len = 0, index = 0;
+
+ if (state == 0) {
+ objs.clear();
+ len = ::strlen(text);
+ index = 0;
+
+ using namespace std::placeholders;
+ VsmArrayString ids = NULL;
+ try {
+ CommandLineInterface::executeCallback(bind(vsm_get_zone_ids, _1, &ids));
+ } catch (const std::runtime_error& ex) {
+ // Quietly ignore, nothing we can do anyway
+ }
+
+ if (ids != NULL) {
+ for (VsmString* id = ids; *id; ++id) {
+ if (::strncmp(text, *id, len) == 0) {
+ objs.push_back(*id);
+ }
+ }
+
+ vsm_array_string_free(ids);
+ }
+ }
+
+ if (index < objs.size()) {
+ return ::strdup(objs[index++].c_str());
+ }
+
+ return NULL;
+}
+
+char* cmd_generator(const char* text, int state)
+{
+ static std::vector<std::string> cmds;
+ static size_t len = 0, index = 0;
+
+ if (state == 0) {
+ cmds.clear();
+ len = ::strlen(text);
+ index = 0;
+
+ for (const auto& command : commands) {
+ if (command.second.isAvailable(MODE_INTERACTIVE)) {
+ const std::string& cmd = command.second.getName();
+ if (::strncmp(text, cmd.c_str(), len) == 0) {
+ cmds.push_back(cmd);
+ }
+ }
+ }
+ }
+
+ if (index < cmds.size()) {
+ return ::strdup(cmds[index++].c_str());
+ }
+
+ return NULL;
+}
+
+char** completion(const char* text, int start, int /*end*/)
+{
+ char **matches = NULL;
+
+ if (start == 0) {
+ matches = ::rl_completion_matches(text, &cmd_generator);
+ } else {
+ matches = ::rl_completion_matches(text, &object_generator);
+ }
+
+ return matches;
+}
+
+// handlers for the modes
+
+int interactiveMode()
+{
+ if (connect() != EXIT_SUCCESS)
+ return EXIT_FAILURE;
+
+ ::rl_attempted_completion_function = completion;
+
+ for (;;) {
+ char *line = ::readline(">>> ");
+
+ if (line == NULL) {
+ break;
+ }
+ if (line[0] == '\0') {
+ free(line);
+ continue;
+ }
+
+ std::istringstream iss(line);
+ Args argv{std::istream_iterator<std::string>{iss},
+ std::istream_iterator<std::string>{}};
+
+ if (commands.count(argv[0]) == 0) {
+ printUsage(std::cout, "", MODE_INTERACTIVE);
+ free(line);
+ continue;
+ }
+
+ executeCommand(argv, MODE_INTERACTIVE);
+ ::add_history(line);
+ free(line);
+ }
+
+ disconnect();
return EXIT_SUCCESS;
}
+int bashComplMode()
+{
+ for (const auto& command : commands) {
+ if (command.second.isAvailable(MODE_COMMAND_LINE)) {
+ std::cout << command.second.getName() << "\n";
+ }
+ }
+
+ return EXIT_SUCCESS;
+}
+
+int cliMode(const int argc, const char** argv)
+{
+ if (commands.count(argv[1]) == 0) {
+ printUsage(std::cout, argv[0], MODE_COMMAND_LINE);
+ return EXIT_FAILURE;
+ }
+
+ if (connect() != EXIT_SUCCESS) {
+ return EXIT_FAILURE;
+ }
+
+ // pass all the arguments excluding argv[0] - the executable name
+ Args commandArgs(argv+1, argv+argc);
+ int rc = executeCommand(commandArgs, MODE_COMMAND_LINE);
+
+ disconnect();
+ return rc;
+}
+
+} // namespace
+
+
+int main(const int argc, const char** argv)
+{
+ if (argc == 1) {
+ return interactiveMode();
+ }
+
+ if (std::string(argv[1]) == "--bash-completion") {
+ return bashComplMode();
+ }
+
+ return cliMode(argc, argv);
+}
COMPREPLY=()
if [ "$COMP_CWORD" == "1" ]; then
- COMPREPLY=($(compgen -W "$(@CLI_CODENAME@ | grep --color=never -e '^\S' | tail -n +3 | cut -f1 -d' ')" -- $cur))
+ COMPREPLY=($(compgen -W "$(@CLI_CODENAME@ --bash-completion)" -- $cur))
elif [ "$COMP_CWORD" == "2" ]; then
COMPREPLY=($(compgen -W "-h" -- $cur))
fi
BuildRequires: boost-devel
BuildRequires: pkgconfig(glib-2.0)
BuildRequires: lxc-devel
+BuildRequires: readline-devel
Requires: lxc
%if %{platform_type} == "TIZEN"
Requires: iproute2