Skip to content

Commit 739228f

Browse files
committed
Create Blog “open-sourcing-workshops-on-demand-part-5-create-a-workshop”
1 parent d9e5c87 commit 739228f

File tree

3 files changed

+292
-0
lines changed

3 files changed

+292
-0
lines changed
Lines changed: 292 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,292 @@
1+
---
2+
title: "Open sourcing Workshops-on-Demand - Part 5: Create a workshop"
3+
date: 2023-07-24T10:43:53.548Z
4+
author: Frederic Passeron
5+
authorimage: /img/frederic-passeron-hpedev-192.jpg
6+
disable: false
7+
---
8+
In this new article that is part of this series dedicated to the [open sourcing of our Workshops-on-Demand project](https://developer.hpe.com/blog/willing-to-build-up-your-own-workshops-on-demand-infrastructure/), I will focus on the necessary steps to build up a new workshop. I already covered most of the infrastructure part that supports the workshops. It now makes sense to emphasize a bit on the content creation.
9+
10+
In order to exist, a workshop requires serveral things:
11+
12+
From a frontend standpoint:
13+
14+
In the Workshops table:
15+
16+
A new entry will need the following:
17+
18+
![](/img/wod-db-entry1.png "Workshop's fields in the Database.")
19+
20+
**An id:** A workshop id to be used by backend server automation and Replays table to reference the associated replay video of the workshop.
21+
22+
**A name:** The workshop's name as it will will be displayed on the registration portal.
23+
24+
**A name of the folder** containing all the workshop's notebooks
25+
26+
**A description / abstract**
27+
28+
**A capacity:** The number of maximum concurrent students allowed to take on the workshop.
29+
30+
A student range: The range between which students get picked at registration time.
31+
32+
Reset and ldap entries are to be used by backend server automation if dedicated reset scripts and ldap authentication are required by the workshop.
33+
34+
A session type (Workshops-on-Demand by default)
35+
36+
A location: If your setup includes multiple production sites, use this field to allocate workshops according to your needs. In the case of the HPE Developer Community, some workshops can only run on a HPE GreenLake cloud environment. As a consequence, the location is set to greenlake in this case.
37+
38+
Avatar, role and replayLink are superseeded by entries in the replay table. I will explain later.
39+
40+
![](/img/wod-db-entry2.png "Workshop's fields in the Database #2.")
41+
42+
Compile: This entry will be filled with the name of a script to be compiled at deployment time. This feature allows for instance the admin to hide login scripts and credentials in non-editable executable files.
43+
44+
Varpass: This defines whethere a workshop require some password variable to be leveraged or not.
45+
46+
ReplayId: This entry links the dedicated replay video to the workshop. it enables the presence of the replay in the learn more page of the workshop.
47+
48+
WorkshopImg: As part of the lifecycle of the workshop, several emails are sent to the student. A workshop image is embbeded in the first emails.
49+
50+
BadgeImg: As part of the lifecycle of the workshop, several emails are sent to the student. In the final email, a badge is included. It allows the student to share its accomplishment on SoME like linkedin for instance.
51+
52+
Note:
53+
54+
Both WorkshopImg and BadgeImg are located on the same remote web server.
55+
56+
Beta: Not implemented yet :-)
57+
58+
Category: The workshops' registration portal proposes several filters to display the catlog's content. You can view all workshops, the most poular ones, or by category. Use this field to sort workshops accordingly.
59+
60+
AlternateLocation: Not implemented yet. The purpose is allow automation of the relocation of a workshop in case of primary location's failure.
61+
62+
Duration: All workshops are time bombed. You will define here the time alloacted to perform the workshop.
63+
64+
If you feel you need more details about the registration process, please take a look at the **Register Phase** paragraph in [the following introductionary blog](https://developer.hpe.com/blog/willing-to-build-up-your-own-workshops-on-demand-infrastructure/).
65+
66+
A set of notebooks that will be used by the student to follow instructions cells in markdown and run code cells leveraging the relevant kernel. If you are not familiar with Jupyter notebooks, a simple [101 workshop](https://developer.hpe.com/hackshack/workshop/25) is available in our Workshops-on-Demand 's catalog.
67+
68+
Optional:
69+
70+
The `ansible` folder contains all the necessary playbooks and variables files to support the main functions of the backend server. It provides playbooks for a minimal installation of the servers or appliances. It also allows the setup of the
71+
different types of servers (i.e backend, frontend, and/or api-db), appliances (virtual machines or containers), or workshops as well as maintenance tasks.
72+
73+
At the root of this directory can be found:
74+
75+
`Check*.yml playbooks`: These playbooks are used to perform checks on the different systems. These checks ensure that this a compliant WoD system by checking firewall rules and many other things. You will see this a bit later in more details.
76+
77+
`Copy_folder.yml`: Historically, this is one of very first playbook we used and therefore, it is very important to me. It performs the necessary actions to deploy
78+
and personnalize (by substituting Ansible variables) the selected notebook to the appropriate student home folder.
79+
80+
`compile_scripts.yml`: Should you need to hide from the student a simple api call that is made on some private endpoint with non-shareable data (credentials for instance), this playbook will make sure to compile it and create a executable file allowing it to happen.
81+
82+
`distrib.yml`: This playbook retrieves the distribution name and version from the machine it is run on.
83+
84+
`install_*.yml`: These playbooks take care of installing the necessary packages needed by the defined type (frontend, backend, api-db, base-system or even appliance).
85+
86+
`setup_*.ym`: There are several types of setup playbooks in this directory.
87+
88+
* `setup_WKSHP-*.yml`: These playbooks are responsible for preparing a base appliance for a given workshop by adding and configuring the necessary packages or services related to the workshop.
89+
* `setup_appliance.yml`: This playbook is used to perform the base setup for a JupyterHub environment server or appliance. It includes setup_base_appliance.yml playbook.
90+
* `setup_base_appliance`: This takes care of setting the minimal requierements for an appliance. It includes `install_base_system.yml` playbook. On top of it, it creates and configures the necessary users.
91+
* `setup_docker_based_appliance.yml`: Quite self explanatory ? it performs setup tasks to enable docker on a given appliance.
92+
93+
It also hosts the `inventory` file describing the role of JupyterHub servers. Place your JupyterHub machine (FQDN) in a group used as PBKDIR namerole.
94+
95+
```shellsession
96+
#
97+
# Place to your JupyterHub machine (FQDN) in a group used as PBKDIR name.
98+
#
99+
[production]
100+
127.0.0.1 ansible_connection=localhost
101+
```
102+
103+
The `conf` folder hosts configuration files in a Jinja format. Once expanded, the resulting files will be used by relevant workshops. I will explain in a future article all the steps and requirements to create a workshop.
104+
105+
As part of the refactoring work to open source the project, we reaaranged the different scripts' locations. We have created an install folder to handle the different installation scripts either from a JupyterHub's perpective or from an appliance's standpoint, too.
106+
107+
We separated the workshops' related scripts from the system ones. When one creates a workshop, one needs to provide a series of notebooks and in some cases some scripts to manage the creation and setup of a related appliance along with additional scripts to manage its lifecycle in the overall Workshops-on-Demand architecture (Create, Cleanup, Reset scripts at deployment or Cleanup times). These scripts need to be located in the `scripts` folder. On the other hand, the system scripts are located in the `sys` folder.
108+
109+
![](/img/tree-wkshop2.png "Tree view of the sys directory")
110+
111+
This directory hosts important configuration files for both the system and JupyterHub. You can see for instance `fail2ban` configuration files. Some Jinja templates are present here, too. These templates will be expanded through the `deliver` mechanism allowing the creation of files customized with Ansible variables. All the wod related tasks are prefixed with wod for better understanding and ease of use.
112+
113+
These Jinja templates can refer to some Jupyterhub kernel needs like `wod-build-evcxr.sh.j2` that aims at creating a script allowing the rust kernel installation. Some other templates are related to the system and JupyterHub. `wod-kill-processes.pl.j2` has been created after discovering the harsh reality of online mining. In a ideal world, I would not have to explain further as the script would not be needed. Unfortunately, this is not the case. When one offers access to some hardware freely online, sooner or later, he can expect to see his original idea to be hyjacked.
114+
115+
Let's say that you want to provide some AI/ML 101 type of workshops. As part of it,
116+
you may consider providing servers with some GPUs. Any twisted minded cryptominer discovering your resources will definitely think he's hits the jackpot! This little anecdot actually happened to us and not only on GPU based servers, some regular servers got hit as well. We found out that performance on some servers became very poor and when looking into it, we found some scripts that were not supposed to run there. As a result, we implemented monitors to check the load on our servers and made sure that to kill any suspicious processes before kicking out the misbehaving student.
117+
118+
`wod-test-action.sh.j2` is another interesting template that will create a script that can be used for testing workshops. This script mimics the procmail API and actually enables you to test the complete lifecycle of a workshop from deployment to cleanup or reset.
119+
120+
```shellsession
121+
wodadmin@server:/usr/local/bin$ ./wod-test-action.sh
122+
Syntax: wod-test-action.sh <CREATE|CLEANUP|RESET|PURGE|PDF|WORD> WKSHOP [MIN[,MAX]
123+
ACTION is mandatory
124+
wodadmin@server:/usr/local/bin$
125+
```
126+
127+
It requires the verb, the workshop's name and the student id. Using the script, one does not need to provide participant id. The script is run locally on the JupyterHub server.
128+
129+
```shellsession
130+
wodadmin@server:/usr/local/bin$ ./wod-test-action.sh
131+
Syntax: wod-test-action.sh <CREATE|CLEANUP|RESET|PURGE|PDF|WORD> WKSHOP [MIN[,MAX]
132+
ACTION is mandatory
133+
wodadmin@server:/usr/local/bin$ ./wod-test-action.sh CREATE WKSHP-API101 121
134+
Action: CREATE
135+
We are working on WKSHP-API101
136+
Student range: 121
137+
Sending a mail to CREATE student 121 for workshop WKSHP-API101
138+
220 server.xyz.com ESMTP Postfix (Ubuntu)
139+
250 2.1.0 Ok
140+
250 2.1.5 Ok
141+
354 End data with <CR><LF>.<CR><LF>
142+
250 2.0.0 Ok: queued as 9749E15403AB
143+
221 2.0.0 Bye
144+
```
145+
146+
In order to retrieve the result of the script, you simply need to run a `tail` command.
147+
148+
```shellsession
149+
wodadmin@server:~$ tail -100f .mail/from
150+
++ date
151+
....
152+
From [email protected] Fri Mar 3 09:08:35 2023
153+
Subject: CREATE 121 0
154+
Folder: /home/wodadmin/wod-backend/scripts/procmail-action.sh CREATE 11
155+
+ source /home/wodadmin/wod-backend/scripts/wod.sh
156+
....
157+
+ echo 'end of procmail-action for student 121 (passwd werty123) with workshop WKSHP-API101 with action CREATE at Fri Mar 3 09:11:39 UTC 2023'
158+
```
159+
160+
The very last line of the trace will provide you with the credentials necessary to test your workshop.
161+
162+
There are two types of activities that can occur on the backend server: punctual or regular. The punctual activity is one that is performed once every now and then. The regular one is usually set up on the backend server as a cron job. Sometimes however, one of these cron tasks can be forced manually if necessary. One of the most important scheduled task is the `deliver` task. I will explain it later on in this chapter. I will start now by explaining an important possible punctual task, the update of the backend server.
163+
164+
#### Update of the backend server:
165+
166+
The backend server hosts all the necessary content for delivering workshops: it supplies notebooks,scripts and playbooks to deploy and personalize them. It also hosts some services that are needed by the overall architecture solution (JupyterHub, Procmail, Fail2ban among others).
167+
168+
Services are installed once and for all at the installation time. These services may evolve over time. One may need to update the JupyterHub application to fix a bug or get new features. In the same fashion, you may consider bumping from one Python version to a new major one. If you are willing to update these services or add new ones, you will need to update the relevant installation playbooks in `wod-backend/ansible` directory.
169+
170+
Here is a small extract of the `install_backend.yml` playbook: Full version [here](https://github.com/Workshops-on-Demand/wod-backend/blob/main/ansible/install_backend.yml)
171+
172+
```shellsession
173+
vi install_backend
174+
- hosts: all
175+
gather_facts: true
176+
vars:
177+
IJAVAVER: "1.3.0"
178+
KUBECTLVER: "1.21.6"
179+
180+
tasks:
181+
- name: Include variables for the underlying distribution
182+
include_vars: "{{ ANSIBLEDIR }}/group_vars/{{ ansible_distribution }}-{{ ansible_distribution_major_version }}.yml"
183+
184+
- name: Base setup for a JupyterHub environment server or appliance
185+
include_tasks: "{{ ANSIBLEDIR }}/setup_base_appliance.yml"
186+
187+
- name: Add CentOS SC repository into repo list
188+
become: yes
189+
become_user: root
190+
yum:
191+
name: centos-release-scl-rh
192+
state: present
193+
when:
194+
- ansible_distribution == "CentOS"
195+
- ansible_distribution_major_version >= "7"
196+
197+
- name: Add conda GPG Key to APT
198+
become: yes
199+
become_user: root
200+
apt_key:
201+
url: https://repo.anaconda.com/pkgs/misc/gpgkeys/anaconda.asc
202+
state: present
203+
when:
204+
- ansible_distribution == "Ubuntu"
205+
- ansible_distribution_major_version >= "20"
206+
207+
# TODO: Do it for EPEL if really needed
208+
- name: Add conda APT repository
209+
become: yes
210+
become_user: root
211+
apt_repository:
212+
repo: deb [arch=amd64] https://repo.anaconda.com/pkgs/misc/debrepo/conda stable main
213+
state: present
214+
when:
215+
- ansible_distribution == "Ubuntu"
216+
```
217+
218+
Possible Use Cases:
219+
220+
* Upgrade to a newer version of JupyterHub
221+
* Add a new kernel to JupyterHub
222+
* Add a new Ansible Galaxy collection
223+
* Add a new PowerShell library
224+
* Add a new package needed by a workshop.
225+
226+
For e.g:
227+
228+
* Kubectl client
229+
* Terraform client
230+
* PowerShell module
231+
* Python Library
232+
233+
You will start by moving to your public backend forked repository and apply the necessary changes before committing and push locally.
234+
235+
Then you will perform a merge request with the main repository. We plan to integrate here in a proper CICD (continuous integration continous development) pipeline to allow a vagrant based test deployment. Whenever someone performs a merge request on the main repo, the test deployment task kicks in and deploys a virtual backend server on which the new version of the installation process is automatically tested. When successful, the merge request is accepted. Once merged, you will need to move to your backend server and perform git remote update and git rebase on the wod-backend directory. Once done, you will then be able to perform the installation process.
236+
237+
#### Regular maintenance of the backend server:
238+
239+
On a daily basis, some tasks are launched to check the integrity of the backend server. Some tasks are related to the security integrity of the system. The following playbook is at the heart of this verification: **wod-backend/ansible/check_backend.yml**. Full version of the file is available [here](https://github.com/Workshops-on-Demand/wod-backend/blob/main/ansible/check_backend.yml) for review.
240+
241+
It checks a quite long list of items like:
242+
243+
* Wod System compliancy: is this really a wod system? by calling out [check_system.yml](https://github.com/Workshops-on-Demand/wod-backend/blob/main/ansible/check_system.yml) playbook.
244+
245+
This first check includes:
246+
247+
* nproc hard and soft limits
248+
* nofile hard and soft limits
249+
* Setup sysctl params
250+
251+
* net.ipv4.tcp_keepalive_time, value: "1800"
252+
* kernel.threads-max, value: "4096000"
253+
* kernel.pid_max, value: "200000"
254+
* vm.max_map_count, value: "600000"
255+
* Setup UDP and TCP firewall rules
256+
* Enable services:
257+
258+
* Firewalld
259+
* Ntp
260+
* Student Management:
261+
262+
* Ensure limits are correct for students accounts
263+
* Copy the skeleton content under /etc/skel
264+
* Test `.profile` file
265+
* Ensure vim is the default EDITOR
266+
* Setup `logind.conf`
267+
* Manage `/etc/hosts` file
268+
* Install the pkg update script
269+
* Setup `crontab` for daily pkg security update
270+
* Deliver create/reset/setup scripts as ansible template for variable expansion
271+
* Install utility scripts
272+
* Deliver the system scripts (`cleanup-processes.sh.j2`)
273+
* Installation of the cleanup-processes script
274+
* Setup weekly cleanup processes task
275+
* Enable WoD service
276+
* Test private tasks YAML file
277+
* Call private tasks if available. It performs the private part before users management to allow interruption of the deliver script during normal operations - waiting till end of users management can take hours for 2000 users. Potential impact: private scripts are run before users creation, so may miss some part of setup.
278+
* User Management:
279+
280+
* Remove existing JupyterHub users
281+
* Remove Linux users and their home directory
282+
* Ensure dedicated students groups exist
283+
* Ensure Linux students users exists with their home directory
284+
* Ensure JupyterHub students users exist
285+
* Setup ACL for students with JupyterHub account
286+
* Setup default ACL for students with JupyterHub account
287+
288+
A similar set of scripts exist for the different parts of the solution ([check_api-db.yml](https://github.com/Workshops-on-Demand/wod-backend/blob/main/ansible/check_api-db.yml) for api-db server, [check_frontend.yml ](https://github.com/Workshops-on-Demand/wod-backend/blob/main/ansible/check_frontend.yml)for frontend server for instance).
289+
290+
You should now have a better understanding of the maintenance tasks associated to the backend server. Similar actions are available for the other components of the project. Checking tasks have been created for the frontend and api-db server. Having now mostly covered all the subjects related to the backend server from an infrastructure standpoint, it is high time to discuss the content part. In my next blog, I plan to describe the workshop creation process. Time to understand how to build up some content for the JupyterHub server!
291+
292+
If we can be of any help in clarifying any of this, please reach out to us on [Slack](https://slack.hpedev.io/). Please be sure to check back at [HPE DEV](https://developer.hpe.com/blog) for a follow up on this. Also, don't forget to check out also the Hack Shack for new [workshops](https://developer.hpe.com/hackshack/workshops)! Willing to collaborate with us? Contact us so we can build more workshops!

static/img/wod-db-entry1.png

164 KB
Loading

static/img/wod-db-entry2.png

104 KB
Loading

0 commit comments

Comments
 (0)