blob: 43e600467c5a20c91a32fcca82953a3c64cde222 [file] [log] [blame]
Nathan Skrzypczak9ad39c02021-08-19 11:38:06 +02001Web applications with VPP
2=========================
3
4Vpp includes a versatile http/https static server plugin. We quote the
5word static in the previous sentence because the server is easily
6extended. This note describes how to build a Hugo site which includes
7both monitoring and control functions.
8
9Lets assume that we have a vpp data-plane plugin which needs a
10monitoring and control web application. Heres how to build one.
11
12Step 1: Add URL handlers
13------------------------
14
15Individual URL handlers are pretty straightforward. You can return just
16about anything you like, but as we work through the example youll see
17why returning data in .json format tends to work out pretty well.
18
19::
20
21 static int
Matus Fabiana67da252024-08-01 16:36:44 +020022 handle_get_status (hss_url_handler_args_t *args)
Nathan Skrzypczak9ad39c02021-08-19 11:38:06 +020023 {
24 my_main_t *mm = &my_main;
25 u8 *s = 0;
26
27 /* Construct a .json reply */
28 s = format (s, "{\"status\": {");
29 s = format (s, " \"thing1\": \"%s\",", mm->thing1_value_string);
30 s = format (s, " \"thing2\": \"%s\",", mm->thing2_value_string);
31 /* ... etc ... */
32 s = format (s, " \"lastthing\": \"%s\"", mm->last_value_string);
33 s = format (s, "}}");
34
35 /* And tell the static server plugin how to send the results */
Matus Fabiana67da252024-08-01 16:36:44 +020036 args->data = s;
37 args->data_len = vec_len (s);
38 args->ct = HTTP_CONTENT_APP_JSON;
39 args->free_vec_data = 1; /* free s when done with it, in the framework */
40 return HSS_URL_HANDLER_OK;
Nathan Skrzypczak9ad39c02021-08-19 11:38:06 +020041 }
42
43Words to the Wise: Chrome has a very nice set of debugging tools. Select
44More Tools -> Developer Tools”. Right-hand sidebar appears with html
45source code, a javascript debugger, network results including .json
46objects, and so on.
47
48Note: .json object format is **intolerant** of both missing and extra
49commas, missing and extra curly-braces. Its easy to waste a
50considerable amount of time debugging .json bugs.
51
52Step 2: Register URL handlers with the server
53---------------------------------------------
54
Matus Fabiana67da252024-08-01 16:36:44 +020055Call ``hss_register_url_handler`` as shown. Its likely
Nathan Skrzypczak9ad39c02021-08-19 11:38:06 +020056but not guaranteed that the static server plugin will be available.
57
58::
59
60 int
61 plugin_url_init (vlib_main_t * vm)
62 {
63 void (*fp) (void *, char *, int);
64
65 /* Look up the builtin URL registration handler */
66 fp = vlib_get_plugin_symbol ("http_static_plugin.so",
Matus Fabiana67da252024-08-01 16:36:44 +020067 "hss_register_url_handler");
Nathan Skrzypczak9ad39c02021-08-19 11:38:06 +020068
69 if (fp == 0)
70 {
71 clib_warning ("http_static_plugin.so not loaded...");
72 return -1;
73 }
74
75 (*fp) (handle_get_status, "status.json", HTTP_BUILTIN_METHOD_GET);
76 (*fp) (handle_get_run, "run.json", HTTP_BUILTIN_METHOD_GET);
77 (*fp) (handle_get_reset, "reset.json", HTTP_BUILTIN_METHOD_GET);
78 (*fp) (handle_get_stop, "stop.json", HTTP_BUILTIN_METHOD_GET);
79 return 0;
80 }
81
82Make sure to start the http static server **before** calling
83plugin_url_init(…), or the registrations will disappear.
84
85Step 3: Install Hugo, pick a theme, and create a site
86-----------------------------------------------------
87
88Please refer to the Hugo documentation.
89
90See `the Hugo Quick Start
91Page <https://gohugo.io/getting-started/quick-start>`__. Prebuilt binary
92artifacts for many different environments are available on `the Hugo
93release page <https://github.com/gohugoio/hugo/releases>`__.
94
95To pick a theme, visit `the Hugo Theme
96site <https://themes.gohugo.io>`__. Decide what you need your site to
97look like. Stay away from complex themes unless youre prepared to spend
98considerable time tweaking and tuning.
99
100The Introduction theme is a good choice for a simple site, YMMV.
101
102Step 4: Create a rawhtml shortcode
103------------------------------------
104
105Once youve initialized your new site, create the directory
106/layouts/shortcodes. Create the file rawhtml.html in that directory,
107with the following contents:
108
109::
110
111 <!-- raw html -->
112 {{.Inner}}
113
114This is a key trick which allows a static Hugo site to include
115javascript code.
116
117Step 5: create Hugo content which interacts with vpp
118----------------------------------------------------
119
120Now its time to do some web front-end coding in javascript. Of course,
121you can create static text, images, etc. as described in the Hugo
122documentation. Nothing changes in that respect.
123
124To include dynamically-generated data in your Hugo pages, splat down
125some
126
127.. raw:: html
128
129 <div>
130
131HTML tags, and define a few buttons:
132
133::
134
135 {{< rawhtml >}}
136 <div id="Thing1"></div>
137 <div id="Thing2"></div>
138 <div id="Lastthing"></div>
139 <input type="button" value="Run" onclick="runButtonClick()">
140 <input type="button" value="Reset" onclick="resetButtonClick()">
141 <input type="button" value="Stop" onclick="stopButtonClick()">
142 <div id="Message"></div>
143 {{< /rawhtml >}}
144
145Time for some javascript code to interact with vpp:
146
147::
148
149 {{< rawhtml >}}
150 <script>
151 async function getStatusJson() {
152 pump_url = location.href + "status.json";
153 const json = await fetch(pump_url, {
154 method: 'GET',
155 mode: 'no-cors',
156 cache: 'no-cache',
157 headers: {
158 'Content-Type': 'application/json',
159 },
160 })
161 .then((response) => response.json())
162 .catch(function(error) {
163 console.log(error);
164 });
165
166 return json.status;
167 };
168
169 async function sendButton(which) {
170 my_url = location.href + which + ".json";
171 const json = await fetch(my_url, {
172 method: 'GET',
173 mode: 'no-cors',
174 cache: 'no-cache',
175 headers: {
176 'Content-Type': 'application/json',
177 },
178 })
179 .then((response) => response.json())
180 .catch(function(error) {
181 console.log(error);
182 });
183 return json.message;
184 };
185
186 async function getStatus() {
187 const status = await getStatusJson();
188
189 document.getElementById("Thing1").innerHTML = status.thing1;
190 document.getElementById("Thing2").innerHTML = status.thing2;
191 document.getElementById("Lastthing").innerHTML = status.lastthing;
192 };
193
194 async function runButtonClick() {
195 const json = await sendButton("run");
196 document.getElementById("Message").innerHTML = json.Message;
197 }
198
199 async function resetButtonClick() {
200 const json = await sendButton("reset");
201 document.getElementById("Message").innerHTML = json.Message;
202 }
203 async function stopButtonClick() {
204 const json = await sendButton("stop");
205 document.getElementById("Message").innerHTML = json.Message;
206 }
207
208 getStatus();
209
210 </script>
211 {{< /rawhtml >}}
212
213At this level, javascript coding is pretty simple. Unless you know
214exactly what youre doing, please follow the async function / await
215pattern shown above.
216
217Step 6: compile the website
218---------------------------
219
220At the top of the website workspace, simply type hugo”. The compiled
221website lands in the public subdirectory.
222
223You can use the Hugo static server - with suitable stub javascript code
224- to see what your site will eventually look like. To start the hugo
225static server, type hugo server”. Browse to http://localhost:1313”.
226
227Step 7: configure vpp
228---------------------
229
230In terms of command-line args: you may wish to use poll-sleep-usec 100
231to keep the load average low. Totally appropriate if vpp wont be
232processing a lot of packets or handling high-rate http/https traffic.
233
234::
235
236 unix {
237 ...
238 poll-sleep-usec 100
239 startup-config ... see below ...
240 ...
241 }
242
243If you wish to provide an https site, configure tls. The simplest tls
244configuration uses a built-in test certificate - which will annoy Chrome
245/ Firefox - but its sufficient for testing:
246
247::
248
249 tls {
250 use-test-cert-in-ca
251 }
252
253vpp startup configuration
254~~~~~~~~~~~~~~~~~~~~~~~~~
255
256Enable the vpp static server by way of the startup config mentioned
257above:
258
259::
260
Matus Fabiana67da252024-08-01 16:36:44 +0200261 http static server url-handlers www-root /myhugosite/public uri tcp://0.0.0.0/2345 cache-size 5m fifo-size 8192
Nathan Skrzypczak9ad39c02021-08-19 11:38:06 +0200262
263The www-root must be specified, and must correctly name the compiled
264hugo site root. If your Hugo site is located at /myhugosite, specify
265www-root /myhugosite/public in the http static server stanza. The
266uri shown above binds to TCP port 2345.
267
268If youre using https, use a uri like tls://0.0.0.0/443” instead of the
269uri shown above.
270
271You may want to add a Linux host interface to view the full-up site
272locally:
273
274::
275
276 create tap host-if-name lstack host-ip4-addr 192.168.10.2/24
277 set int ip address tap0 192.168.10.1/24
278 set int state tap0 up