summaryrefslogtreecommitdiffstats
path: root/docs/usecases/webapp.md
blob: 3b1a3b7b5b71e6bdbce19c5087342727d623c3e8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
Building VPP web applications
====
ain; u8 *s = 0; /* Construct a .json reply */ s = format (s, "{\"status\": {"); s = format (s, " \"thing1\": \"%s\",", mm->thing1_value_string); s = format (s, " \"thing2\": \"%s\",", mm->thing2_value_string); /* ... etc ... */ s = format (s, " \"lastthing\": \"%s\"", mm->last_value_string); s = format (s, "}}"); /* And tell the static server plugin how to send the results */ hs->data = s; hs->data_offset = 0; hs->cache_pool_index = ~0; hs->free_data = 1; /* free s when done with it, in the framework */ return 0; } ``` Words to the Wise: Chrome has a very nice set of debugging tools. Select "More Tools -> Developer Tools". Right-hand sidebar appears with html source code, a javascript debugger, network results including .json objects, and so on. Note: .json object format is **intolerant** of both missing and extra commas, missing and extra curly-braces. It's easy to waste a considerable amount of time debugging .json bugs. Step 2: Register URL handlers with the server --------------------------------------------- Call http_static_server_register_builtin_handler() as shown. It's likely but not guaranteed that the static server plugin will be available. ``` int plugin_url_init (vlib_main_t * vm) { void (*fp) (void *, char *, int); /* Look up the builtin URL registration handler */ fp = vlib_get_plugin_symbol ("http_static_plugin.so", "http_static_server_register_builtin_handler"); if (fp == 0) { clib_warning ("http_static_plugin.so not loaded..."); return -1; } (*fp) (handle_get_status, "status.json", HTTP_BUILTIN_METHOD_GET); (*fp) (handle_get_run, "run.json", HTTP_BUILTIN_METHOD_GET); (*fp) (handle_get_reset, "reset.json", HTTP_BUILTIN_METHOD_GET); (*fp) (handle_get_stop, "stop.json", HTTP_BUILTIN_METHOD_GET); return 0; } ``` Make sure to start the http static server **before** calling plugin_url_init(...), or the registrations will disappear. Step 3: Install Hugo, pick a theme, and create a site ----------------------------------------------------- Please refer to the Hugo documentation. See [the Hugo Quick Start Page](https://gohugo.io/getting-started/quick-start). Prebuilt binary artifacts for many different environments are available on [the Hugo release page](https://github.com/gohugoio/hugo/releases). To pick a theme, visit [the Hugo Theme site](https://themes.gohugo.io). Decide what you need your site to look like. Stay away from complex themes unless you're prepared to spend considerable time tweaking and tuning. The "Introduction" theme is a good choice for a simple site, YMMV. Step 4: Create a "rawhtml" shortcode ------------------------------------ Once you've initialized your new site, create the directory <site-root>/layouts/shortcodes. Create the file "rawhtml.html" in that directory, with the following contents: ``` <!-- raw html --> {{.Inner}} ``` This is a key trick which allows a static Hugo site to include javascript code. Step 5: create Hugo content which interacts with vpp ---------------------------------------------------- Now it's time to do some web front-end coding in javascript. Of course, you can create static text, images, etc. as described in the Hugo documentation. Nothing changes in that respect. To include dynamically-generated data in your Hugo pages, splat down some <div> HTML tags, and define a few buttons: ``` {{< rawhtml >}} <div id="Thing1"></div> <div id="Thing2"></div> <div id="Lastthing"></div> <input type="button" value="Run" onclick="runButtonClick()"> <input type="button" value="Reset" onclick="resetButtonClick()"> <input type="button" value="Stop" onclick="stopButtonClick()"> <div id="Message"></div> {{< /rawhtml >}} ``` Time for some javascript code to interact with vpp: {{< rawhtml >}} <script> async function getStatusJson() { pump_url = location.href + "status.json"; const json = await fetch(pump_url, { method: 'GET', mode: 'no-cors', cache: 'no-cache', headers: { 'Content-Type': 'application/json', }, }) .then((response) => response.json()) .catch(function(error) { console.log(error); }); return json.status; }; async function sendButton(which) { my_url = location.href + which + ".json"; const json = await fetch(my_url, { method: 'GET', mode: 'no-cors', cache: 'no-cache', headers: { 'Content-Type': 'application/json', }, }) .then((response) => response.json()) .catch(function(error) { console.log(error); }); return json.message; }; async function getStatus() { const status = await getStatusJson(); document.getElementById("Thing1").innerHTML = status.thing1; document.getElementById("Thing2").innerHTML = status.thing2; document.getElementById("Lastthing").innerHTML = status.lastthing; }; async function runButtonClick() { const json = await sendButton("run"); document.getElementById("Message").innerHTML = json.Message; } async function resetButtonClick() { const json = await sendButton("reset"); document.getElementById("Message").innerHTML = json.Message; } async function stopButtonClick() { const json = await sendButton("stop"); document.getElementById("Message").innerHTML = json.Message; } getStatus(); </script> {{< /rawhtml >}} At this level, javascript coding is pretty simple. Unless you know exactly what you're doing, please follow the async function / await pattern shown above. Step 6: compile the website --------------------------- At the top of the website workspace, simply type "hugo". The compiled website lands in the "public" subdirectory. You can use the Hugo static server - with suitable stub javascript code - to see what your site will eventually look like. To start the hugo static server, type "hugo server". Browse to "http://localhost:1313". Step 7: configure vpp --------------------- In terms of command-line args: you may wish to use poll-sleep-usec 100 to keep the load average low. Totally appropriate if vpp won't be processing a lot of packets or handling high-rate http/https traffic. ``` unix { ... poll-sleep-usec 100 startup-config ... see below ... ... } ``` If you wish to provide an https site, configure tls. The simplest tls configuration uses a built-in test certificate - which will annoy Chrome / Firefox - but it's sufficient for testing: ``` tls { use-test-cert-in-ca } ``` ### vpp startup configuration Enable the vpp static server by way of the startup config mentioned above: ``` http static server www-root /myhugosite/public uri tcp://0.0.0.0/2345 cache-size 5m fifo-size 8192 ``` The www-root must be specified, and must correctly name the compiled hugo site root. If your Hugo site is located at /myhugosite, specify "www-root /myhugosite/public" in the "http static server" stanza. The uri shown above binds to TCP port 2345. If you're using https, use a uri like "tls://0.0.0.0/443" instead of the uri shown above. You may want to add a Linux host interface to view the full-up site locally: ``` create tap host-if-name lstack host-ip4-addr 192.168.10.2/24 set int ip address tap0 192.168.10.1/24 set int state tap0 up ```