Skip to content

Commit

Permalink
Merge pull request #126 from richiMarchi/add_feature_loadtopology
Browse files Browse the repository at this point in the history
Add feature loadtopology
  • Loading branch information
frisso committed May 23, 2019
2 parents 8659149 + ee9e8c5 commit cc4cf71
Show file tree
Hide file tree
Showing 7 changed files with 136 additions and 31 deletions.
70 changes: 63 additions & 7 deletions Documentation/polycubectl/polycubectl.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,15 @@ How to use
----------

**NOTE**: ``polycubed`` must be running, in order to use ``polycubectl``.
You can start the daemon typing ``sudo polycubed`` in another terminal. Refer to :doc:`Quick Start <../quickstart>`.
You can start the daemon typing ``sudo polycubed`` in another terminal.
Refer to :doc:`Quick Start <../quickstart>`.

``polycubectl`` is a generic CLI, that enables the user to interact with ``Cubes`` (``bridge``, ``router``, ...) and with some framework primitives to ``connect``, ``show`` and build complex ``topologies``.

::

# Show help
polycubectl --help

::

Keyword Type Description
simpleforwarder service Simple Forwarder Base Service
simplebridge service Simple L2 Bridge Service
Expand All @@ -45,14 +43,71 @@ You can start the daemon typing ``sudo polycubed`` in another terminal. Refer to
connect command Connect ports
disconnect command Disconnect ports

attach command Attach transparent cubes
detach command Detach transparent cubes
attach command Attach transparent cubes
detach command Detach transparent cubes

services command Show/Add/Del services (e.g. Bridge, Router, ..)
cubes command Show running service instances (e.g. br1, nat2, ..)
topology command Show topology of service instances
netdevs command Show net devices available

``polycubectl`` is service agnostic, hence the syntax is service dependent.
However we can generalize the syntax as:

::

polycubectl [parent] [command] [child] [argument0=value0] [argument1=value1]


- ``parent``: path of the parent resource where the command has to be applied.
- ``command``: ``add``, ``del``, ``show``, ``set`` or a yang action.
- ``child``: specific resource where the command is applied.
- ``argument``: some commands accept additional commands that are sent in the body request.

Some examples:

::

polycubectl router r0 add loglevel=debug
polycubectl r0 ports add port1 ip=10.1.0.1 netmask=255.255.0.0
polycubectl r0 show routing table
polycubectl r0 ports port1 set peer=veth1
polycubectl r0 ports del port1

# yang action
polycubectl firewall1 chain ingress append src=10.0.0.1 action=DROP


The best way to know what is the syntax for each service is to use the `Help`_ or the bash completion by pressing ``<TAB>`` at any point.


``polycubectl`` is also able to read the contents of the request from the standard input, it can be used in two ways:

Passing complex configuration from the command line
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
::

# create a helloworld instance with loglevel debug and action forward
polycubectl helloworld add hw0 << EOF
{
"loglevel": "debug",
"action": "forward"
}
EOF


Reading configuration from a file
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
::

# create helloworld from a yaml file
polycubectl helloworld add hw0 < hw0.yaml

# create a router from a json file
polycubectl router add r0 < r0.json

# add a list of cubes
polycubectl cubes add < mycubes.yaml

Help
^^^^
Expand Down Expand Up @@ -124,7 +179,8 @@ More complete examples are available in :doc:`tutorials <../tutorials/index>`.
Configuration
-------------

By default, the CLI contacts ``polycubed`` daemon at ``http://localhost:9000/polycube/v1/``. The user can override this configuration with following instructions.
By default, ``polycubectl`` contacts ``polycubed`` at ``http://localhost:9000/polycube/v1/``.
The user can override this configuration with following instructions.

Parameters
^^^^^^^^^^
Expand Down
1 change: 0 additions & 1 deletion src/polycubectl/aliases.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ package main

import (
"fmt"
//"reflect"
"github.com/polycube-network/polycube/src/polycubectl/cliargs"
)

Expand Down
25 changes: 24 additions & 1 deletion src/polycubectl/cliargs/cliargs.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ import (
"strconv"
"strings"

"os"
"bufio"
"bytes"
"github.com/ghodss/yaml"

"github.com/polycube-network/polycube/src/polycubectl/config"
"github.com/polycube-network/polycube/src/polycubectl/httprequest"

Expand Down Expand Up @@ -441,7 +446,25 @@ func (cli *CLIArgs) GetHTTPRequest() (*httprequest.HTTPRequest, error) {
url += url0
body = body0
} else {
body = cli.buildBody()
// if there is text on the standard input that'll used as the body
var buffer bytes.Buffer
reader := bufio.NewReader(os.Stdin)
text, _ := reader.ReadString('\n')
for text != "" {
buffer.WriteString(text)
text, _ = reader.ReadString('\n')
}

if buffer.Len() > 0 {
jsonBuff, err := yaml.YAMLToJSON(buffer.Bytes())
if err != nil {
return nil, err
} else {
body = jsonBuff
}
} else {
body = cli.buildBody()
}
}
}

Expand Down
28 changes: 28 additions & 0 deletions src/polycubed/src/rest_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,9 @@ void RestServer::setup_routes() {
router_->get(base + std::string("/cubes/:cubeName"),
bind(&RestServer::get_cube, this));

router_->post(base + std::string("/cubes"),
bind(&RestServer::post_cubes, this));

router_->options(base + std::string("/cubes"),
bind(&RestServer::cubes_help, this));

Expand Down Expand Up @@ -428,6 +431,31 @@ void RestServer::get_cube(const Pistache::Rest::Request &request,
}
}

void RestServer::post_cubes(const Pistache::Rest::Request &request,
Pistache::Http::ResponseWriter response) {
logRequest(request);
try {
json j = json::parse(request.body());
logJson(j);
std::vector<Response> resp = {{ErrorTag::kNoContent, nullptr}};
bool error = false;
for (auto &it : j) {
resp = core.get_service_controller(it["service-name"]).get_management_interface()->get_service()
->CreateReplaceUpdate(it["name"], it, false, true);
if (!error && resp[0].error_tag != kCreated) {
Rest::Server::ResponseGenerator::Generate(std::move(resp), std::move(response));
error = true;
}
}
if (!error) {
Rest::Server::ResponseGenerator::Generate(std::move(resp), std::move(response));
}
} catch (const std::runtime_error &e) {
logger->error("{0}", e.what());
response.send(Pistache::Http::Code::Bad_Request, e.what());
}
}

void RestServer::cubes_help(const Pistache::Rest::Request &request,
Pistache::Http::ResponseWriter response) {
json j = json::object();
Expand Down
3 changes: 3 additions & 0 deletions src/polycubed/src/rest_server.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ class RestServer {
void get_cube(const Pistache::Rest::Request &request,
Pistache::Http::ResponseWriter response);

void post_cubes(const Pistache::Rest::Request &request,
Pistache::Http::ResponseWriter response);

void cubes_help(const Pistache::Rest::Request &request,
Pistache::Http::ResponseWriter response);

Expand Down
33 changes: 15 additions & 18 deletions src/polycubed/src/server/Resources/Endpoint/Service.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,8 @@ void Service::ClearCubes() {
}
}

void Service::CreateReplaceUpdate(const std::string &name, nlohmann::json &body,
ResponseWriter response, bool update,
bool initialization) {
std::vector<Response>
Service::CreateReplaceUpdate(const std::string &name, nlohmann::json &body, bool update, bool initialization) {
if (update || !ServiceController::exists_cube(name)) {
auto op = OperationType(update, initialization);
auto k = ListKeyValues{};
Expand All @@ -82,9 +81,7 @@ void Service::CreateReplaceUpdate(const std::string &name, nlohmann::json &body,

auto body_errors = BodyValidate(name, k, jbody, initialization);
if (!body_errors.empty()) {
Server::ResponseGenerator::Generate(std::move(body_errors),
std::move(response));
return;
return std::move(body_errors);
}

auto resp = WriteValue(name, body, k, op);
Expand All @@ -93,12 +90,9 @@ void Service::CreateReplaceUpdate(const std::string &name, nlohmann::json &body,
resp.error_tag == ErrorTag::kNoContent)) {
cube_names_.AddValue(name);
}
Server::ResponseGenerator::Generate(std::vector<Response>{resp},
std::move(response));
return std::vector<Response>{resp};
} else {
Server::ResponseGenerator::Generate(
std::vector<Response>{{ErrorTag::kDataExists, nullptr}},
std::move(response));
return std::vector<Response>{{ErrorTag::kDataExists, nullptr}};
}
}

Expand Down Expand Up @@ -129,8 +123,8 @@ void Service::post_body(const Request &request, ResponseWriter response) {
return;
}

CreateReplaceUpdate(body["name"].get<std::string>(), body,
std::move(response), false, true);
auto resp = CreateReplaceUpdate(body["name"].get<std::string>(), body, false, true);
Server:: ResponseGenerator::Generate(std::move(resp), std::move(response));
}

void Service::post(const Request &request, ResponseWriter response) {
Expand All @@ -151,7 +145,8 @@ void Service::post(const Request &request, ResponseWriter response) {
}
}

CreateReplaceUpdate(name, body, std::move(response), false, true);
auto resp = CreateReplaceUpdate(name, body, false, true);
Server:: ResponseGenerator::Generate(std::move(resp), std::move(response));
}

void Service::put(const Request &request, ResponseWriter response) {
Expand All @@ -163,7 +158,8 @@ void Service::put(const Request &request, ResponseWriter response) {
body = nlohmann::json::parse(request.body());
}
body["name"] = name;
CreateReplaceUpdate(name, body, std::move(response), false, true);
auto resp = CreateReplaceUpdate(name, body, false, true);
Server:: ResponseGenerator::Generate(std::move(resp), std::move(response));
}

void Service::patch(const Request &request, ResponseWriter response) {
Expand All @@ -175,7 +171,8 @@ void Service::patch(const Request &request, ResponseWriter response) {
body = nlohmann::json::parse(request.body());
}
body["name"] = name;
CreateReplaceUpdate(name, body, std::move(response), true, false);
auto resp = CreateReplaceUpdate(name, body, true, false);
Server:: ResponseGenerator::Generate(std::move(resp), std::move(response));
}

void Service::del(const Pistache::Rest::Request &request,
Expand Down Expand Up @@ -203,8 +200,8 @@ void Service::patch_body(const Request &request, ResponseWriter response) {
std::move(response));
return;
}
CreateReplaceUpdate(body["name"].get<std::string>(), body,
std::move(response), true, false);
auto resp = CreateReplaceUpdate(body["name"].get<std::string>(), body, true, false);
Server:: ResponseGenerator::Generate(std::move(resp), std::move(response));
}

void Service::options_body(const Request &request, ResponseWriter response) {
Expand Down
7 changes: 3 additions & 4 deletions src/polycubed/src/server/Resources/Endpoint/Service.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,13 @@ class Service : public ParentResource, public Body::Service {

virtual Response ReadHelp() = 0;

std::vector<Response> CreateReplaceUpdate(const std::string &name, nlohmann::json &body,
bool update, bool initialization);

private:
const std::string body_rest_endpoint_;
Validators::InSetValidator cube_names_;

void CreateReplaceUpdate(const std::string &name, nlohmann::json &body,
ResponseWriter response, bool replace,
bool initialization);

nlohmann::json getServiceKeys() const;

void post(const Request &request, ResponseWriter response) final;
Expand Down

0 comments on commit cc4cf71

Please sign in to comment.