├── automatedtest ├── finish.md ├── intro.md ├── step2.md ├── foreground.sh ├── step1.md ├── index.json └── .cypress │ └── example_spec.js ├── embed-videos ├── finish.md ├── index.json ├── step1.md └── intro.md ├── placeholders ├── finish.md ├── intro.md ├── step3.md ├── foreground1.sh ├── foreground2.sh ├── step1.md ├── step2.md └── index.json ├── displaying-web-ui ├── finish.md ├── intro.md ├── step1.md └── index.json ├── quiz ├── finish.md ├── intro.md ├── index.json └── step1.md ├── credit-where-credit-due ├── intro.md ├── step1.md ├── finish.md └── index.json ├── custom-events ├── site │ ├── myapp.scss │ ├── index.html │ ├── site.tar.gz │ ├── build-zip.sh │ ├── server │ │ └── template.html │ ├── package.json │ └── gulpfile.js ├── intro.md ├── env-init.sh ├── index.json └── step1.md ├── environment-usages ├── bash │ ├── finish.md │ ├── step1.md │ └── index.json ├── go │ ├── finish.md │ ├── step1.md │ └── index.json ├── java │ ├── finish.md │ ├── step1.md │ └── index.json ├── r │ ├── finish.md │ ├── step1.md │ └── index.json ├── ruby │ ├── finish.md │ ├── step1.md │ └── index.json ├── rust │ ├── finish.md │ ├── step1.md │ └── index.json ├── dotnet │ ├── finish.md │ ├── step1.md │ └── index.json ├── kotlin │ ├── finish.md │ ├── step1.md │ └── index.json ├── nodejs │ ├── finish.md │ ├── step1.md │ └── index.json ├── python │ ├── finish.md │ ├── step1.md │ └── index.json ├── python-3-7 │ ├── finish.md │ ├── foreground.sh │ ├── step1.md │ └── index.json ├── python-3-8 │ ├── finish.md │ ├── foreground.sh │ ├── step1.md │ └── index.json ├── README.md ├── kubernetes-cluster-running │ ├── step1.md │ ├── finish.md │ └── index.json ├── minikube │ ├── step1.md │ ├── finish.md │ └── index.json ├── kubernetes-cluster │ ├── step2.md │ ├── finish.md │ ├── step1.md │ └── index.json ├── ubuntu-2004 │ ├── finish.md │ ├── step1.md │ └── index.json └── ubuntu-1804 │ ├── finish.md │ ├── step1.md │ └── index.json ├── instruction-guided-template ├── finish.md ├── .cypress │ └── instruction_guided_spec.js ├── step2.md ├── intro.md ├── foreground.sh ├── step1.md └── index.json ├── opening-multiple-terminals ├── finish.md ├── intro.md ├── step1.md └── index.json ├── use-ip-or-dns-for-environment ├── intro.md ├── finish.md ├── foreground.sh ├── step1.md └── index.json ├── environments ├── kubernetes-cluster-1-16 │ ├── node │ │ ├── build │ │ │ └── 1_init.sh │ │ └── katacoda.yaml │ ├── katacoda.yaml │ └── master │ │ ├── katacoda.yaml │ │ └── build │ │ └── 1_init.sh ├── exampleenv1 │ ├── katacoda.yaml │ └── build │ │ ├── 2_pulldockerimages.sh │ │ ├── 3_pulldemos.sh │ │ ├── 1_installpackages.sh │ │ └── 4_configure_environment.sh ├── kc-custom-env-vscode-extensions │ ├── katacoda.yaml │ └── build │ │ └── 1_init.sh ├── multinodeexampleenv-cluster │ ├── node │ │ ├── katacoda.yaml │ │ └── build │ │ │ ├── 2_pulldockerimages.sh │ │ │ ├── 3_pulldemos.sh │ │ │ └── 1_installpackages.sh │ └── master │ │ ├── katacoda.yaml │ │ └── build │ │ ├── 2_pulldockerimages.sh │ │ ├── 3_pulldemos.sh │ │ └── 1_installpackages.sh └── README.md ├── notebooks-py ├── requirements.txt ├── index.json └── Index.ipynb ├── delivering-training └── creating-training-pathway-json │ ├── finish.md │ ├── intro.md │ ├── index.json │ └── step1.md ├── challenges ├── challenge-linux-solver │ ├── install-solver.sh │ ├── assets │ │ ├── my-xargs.sh │ │ ├── streetcar.pdf │ │ ├── solutions.sh.enc │ │ ├── cow-311266_640.png │ │ ├── learning-modern-linux-book.jpg │ │ ├── solutions.sh.md │ │ ├── solutions.sh │ │ ├── verifications.sh │ │ └── hints.md │ ├── task_1.md │ ├── verify.sh │ ├── hint.sh │ ├── task_2.md │ ├── task_4.md │ ├── finish.md │ ├── readme.md │ ├── task_3.md │ ├── intro.md │ ├── index.json │ ├── .cypress │ │ └── solver_spec.js.disabled │ ├── init-background.sh │ └── init-foreground.sh ├── kubernetes-challenge-1 │ ├── foreground.sh │ ├── 1_verify.sh │ ├── 2_verify.sh │ ├── 2_task.md │ ├── intro.md │ ├── assets │ │ ├── cheat │ │ ├── cheat2 │ │ ├── tux.png │ │ └── .DS_Store │ ├── .DS_Store │ ├── finish.md │ ├── configure.sh │ ├── 1_task.md │ ├── 1_hint.sh │ ├── .cypress │ │ └── k8s_spec.js │ └── index.json ├── node-challenge-1 │ ├── 1_task.md │ ├── intro.md │ ├── 1_verify.sh │ ├── finish.md │ ├── assets │ │ └── cheat │ ├── background.sh │ ├── .cypress │ │ └── node_spec.js │ └── index.json └── challenge-hello-world │ ├── 1_task.md │ ├── 1_verify.sh │ ├── 2_verify.sh │ ├── 2_task.md │ ├── finish.md │ ├── intro.md │ ├── 2_hint.sh │ ├── SOLUTIONS.md │ ├── assets │ └── example-asset.txt │ ├── 1_hint.sh │ ├── index.json │ └── README.md ├── uilayouts ├── uilayout-editor-terminal │ ├── setup.sh │ ├── intro.md │ ├── index.json │ └── step1.md ├── uilayout-vscode-terminal │ ├── intro.md │ ├── index.json │ └── step1.md ├── uilayout-iframe │ ├── step1.md │ └── index.json ├── uilayout-terminal │ ├── step1.md │ └── index.json ├── uilayout-terminal-terminal │ ├── step1.md │ └── index.json ├── uilayout-terminal-iframe-split │ ├── index.json │ └── step1.md ├── uilayout-terminal-iframe │ ├── index.json │ └── step1.md └── uilayout-terminal-with-vscode │ ├── index.json │ └── step1.md ├── displaying-progress-spinner ├── foreground.sh ├── background.sh ├── intro.md ├── step1.md ├── index.json └── assets │ └── wait.sh ├── assets ├── avatar.png └── test.css ├── upload-assets ├── assets │ ├── deploy.sh │ └── wait.sh ├── foreground.sh ├── background.sh ├── index.json └── step1.md ├── run-commands-automatically ├── background.sh ├── step2-background.sh ├── step2-foreground.sh ├── foreground.sh ├── intro.md ├── step3-foreground.sh ├── step3-background.sh ├── step2.md ├── step1.md ├── step3.md └── index.json ├── verified-steps ├── step1-verify.sh ├── step2-answer.md ├── step2.md ├── index.json └── step1.md ├── README.md ├── course-data-host01-reference ├── intro.md ├── init-env.sh ├── set-env.sh ├── step1.md ├── assets │ ├── nginx.yaml │ └── wait-script.sh └── index.json ├── create-course ├── finish.md ├── intro.md ├── step2.md ├── index.json ├── step4.md ├── step1.md └── step3.md ├── notebooks-py-slim ├── index.json └── Index.ipynb ├── .dev ├── docker-compose.yml ├── Dockerfile ├── README.md └── Makefile ├── displaying-images ├── assets │ └── logo-text-with-head.png ├── step1.md └── index.json ├── create-scenario-101 ├── intro.md ├── finish.md ├── step4.md ├── step5.md ├── step2.md ├── index.json ├── step1.md └── step3.md ├── strings.yaml ├── vscode-extensions ├── foreground.sh ├── setup.sh ├── index.json └── step1.md ├── delivering-training-pathway.json ├── writing-files ├── index.json └── step1.md ├── clipboard ├── index.json └── step1.md ├── markdown-extensions ├── index.json └── step1.md ├── visualise-docker ├── index.json └── step1.md ├── exclusion-patterns ├── index.json └── step1.md ├── training └── training-example-pathway.json ├── dashboard-tabs-iframe ├── index.json └── step1.md ├── challenges-pathway.json ├── dashboard-tabs ├── index.json ├── step1.md └── step2.md ├── uilayouts-pathway.json ├── environment-usages-pathway.json └── profile-pathway.json /automatedtest/finish.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /embed-videos/finish.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /placeholders/finish.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /placeholders/intro.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /placeholders/step3.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /displaying-web-ui/finish.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /displaying-web-ui/intro.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /quiz/finish.md: -------------------------------------------------------------------------------- 1 | Great work! -------------------------------------------------------------------------------- /credit-where-credit-due/intro.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /credit-where-credit-due/step1.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /custom-events/site/myapp.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /environment-usages/bash/finish.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /environment-usages/bash/step1.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /environment-usages/go/finish.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /environment-usages/go/step1.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /environment-usages/java/finish.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /environment-usages/java/step1.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /environment-usages/r/finish.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /environment-usages/r/step1.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /environment-usages/ruby/finish.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /environment-usages/ruby/step1.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /environment-usages/rust/finish.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /environment-usages/rust/step1.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /environment-usages/dotnet/finish.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /environment-usages/dotnet/step1.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /environment-usages/kotlin/finish.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /environment-usages/kotlin/step1.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /environment-usages/nodejs/finish.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /environment-usages/nodejs/step1.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /environment-usages/python/finish.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /environment-usages/python/step1.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /instruction-guided-template/finish.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /opening-multiple-terminals/finish.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /opening-multiple-terminals/intro.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /use-ip-or-dns-for-environment/intro.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /environment-usages/python-3-7/finish.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /environment-usages/python-3-8/finish.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /use-ip-or-dns-for-environment/finish.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /environments/kubernetes-cluster-1-16/node/build/1_init.sh: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /notebooks-py/requirements.txt: -------------------------------------------------------------------------------- 1 | requests 2 | voluptuous 3 | -------------------------------------------------------------------------------- /custom-events/site/index.html: -------------------------------------------------------------------------------- 1 |
Custom events
2 | -------------------------------------------------------------------------------- /delivering-training/creating-training-pathway-json/finish.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /environments/exampleenv1/katacoda.yaml: -------------------------------------------------------------------------------- 1 | base: 'ubuntu1604' 2 | -------------------------------------------------------------------------------- /challenges/challenge-linux-solver/install-solver.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | -------------------------------------------------------------------------------- /uilayouts/uilayout-editor-terminal/setup.sh: -------------------------------------------------------------------------------- 1 | mkdir -p example; cd example/ -------------------------------------------------------------------------------- /challenges/kubernetes-challenge-1/foreground.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | launch.sh -------------------------------------------------------------------------------- /challenges/node-challenge-1/1_task.md: -------------------------------------------------------------------------------- 1 | Fix multiply.js to execute properly. 2 | -------------------------------------------------------------------------------- /displaying-progress-spinner/foreground.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | sleep 1; wait.sh -------------------------------------------------------------------------------- /environments/exampleenv1/build/2_pulldockerimages.sh: -------------------------------------------------------------------------------- 1 | docker pull nginx 2 | -------------------------------------------------------------------------------- /environments/kc-custom-env-vscode-extensions/katacoda.yaml: -------------------------------------------------------------------------------- 1 | base: "ubuntu2004" -------------------------------------------------------------------------------- /environments/multinodeexampleenv-cluster/node/katacoda.yaml: -------------------------------------------------------------------------------- 1 | base: 'ubuntu1604' 2 | -------------------------------------------------------------------------------- /challenges/challenge-hello-world/1_task.md: -------------------------------------------------------------------------------- 1 | Create a new file called `bananas.txt`. 2 | -------------------------------------------------------------------------------- /environments/kubernetes-cluster-1-16/katacoda.yaml: -------------------------------------------------------------------------------- 1 | base: 'kubernetes-cluster:1.16' 2 | -------------------------------------------------------------------------------- /environments/multinodeexampleenv-cluster/master/katacoda.yaml: -------------------------------------------------------------------------------- 1 | base: 'ubuntu1604' 2 | -------------------------------------------------------------------------------- /environments/exampleenv1/build/3_pulldemos.sh: -------------------------------------------------------------------------------- 1 | docker pull katacoda/docker-http-server 2 | -------------------------------------------------------------------------------- /assets/avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/katacoda/scenario-examples/HEAD/assets/avatar.png -------------------------------------------------------------------------------- /challenges/challenge-hello-world/1_verify.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | test -f /root/bananas.txt 4 | -------------------------------------------------------------------------------- /challenges/challenge-hello-world/2_verify.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | test -f /root/apples.txt 4 | -------------------------------------------------------------------------------- /challenges/kubernetes-challenge-1/1_verify.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | grep app-env -ie 'kubernetes' -------------------------------------------------------------------------------- /challenges/kubernetes-challenge-1/2_verify.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | grep /root/app.js -ie 'katacoda' -------------------------------------------------------------------------------- /environment-usages/python-3-7/foreground.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | python --version 4 | python 5 | -------------------------------------------------------------------------------- /environment-usages/python-3-8/foreground.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | python --version 4 | python 5 | -------------------------------------------------------------------------------- /environments/exampleenv1/build/1_installpackages.sh: -------------------------------------------------------------------------------- 1 | apt-get update 2 | apt-get install -y vim 3 | -------------------------------------------------------------------------------- /environments/multinodeexampleenv-cluster/master/build/2_pulldockerimages.sh: -------------------------------------------------------------------------------- 1 | docker pull nginx 2 | -------------------------------------------------------------------------------- /environments/multinodeexampleenv-cluster/node/build/2_pulldockerimages.sh: -------------------------------------------------------------------------------- 1 | docker pull nginx 2 | -------------------------------------------------------------------------------- /upload-assets/assets/deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | cd /root/ 3 | sleep 5 4 | touch hello-world 5 | -------------------------------------------------------------------------------- /assets/test.css: -------------------------------------------------------------------------------- 1 | #tutorial { 2 | width: 50%; 3 | } 4 | 5 | #split-host { 6 | width: 50%; 7 | } 8 | -------------------------------------------------------------------------------- /environments/kubernetes-cluster-1-16/master/katacoda.yaml: -------------------------------------------------------------------------------- 1 | base: 'kubernetes-master-ubuntu1604-1-16' 2 | -------------------------------------------------------------------------------- /environments/kubernetes-cluster-1-16/node/katacoda.yaml: -------------------------------------------------------------------------------- 1 | base: 'kubernetes-node-ubuntu1604-1-16' 2 | -------------------------------------------------------------------------------- /run-commands-automatically/background.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | touch /root/createdFromBackgroundScript -------------------------------------------------------------------------------- /verified-steps/step1-verify.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | [ -d /home/scrapbook/tutorial/.git ] && echo "done" -------------------------------------------------------------------------------- /automatedtest/intro.md: -------------------------------------------------------------------------------- 1 | This is an example scenario that will be tested using the Cypress integration. 2 | -------------------------------------------------------------------------------- /challenges/challenge-hello-world/2_task.md: -------------------------------------------------------------------------------- 1 | Now create another file, but this time called `apples.txt`. 2 | -------------------------------------------------------------------------------- /challenges/node-challenge-1/intro.md: -------------------------------------------------------------------------------- 1 | To complete this challenge you will need to {state challenge goal}. 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Katacoda Scenario Examples 2 | 3 | View the examples at https://katacoda.com/scenario-examples 4 | -------------------------------------------------------------------------------- /challenges/challenge-linux-solver/assets/my-xargs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Add your one line magic here 4 | 5 | -------------------------------------------------------------------------------- /environments/multinodeexampleenv-cluster/master/build/3_pulldemos.sh: -------------------------------------------------------------------------------- 1 | docker pull katacoda/docker-http-server 2 | -------------------------------------------------------------------------------- /environments/multinodeexampleenv-cluster/node/build/3_pulldemos.sh: -------------------------------------------------------------------------------- 1 | docker pull katacoda/docker-http-server 2 | -------------------------------------------------------------------------------- /placeholders/foreground1.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "The IP address for this environment is [[HOST_IP]]" 4 | -------------------------------------------------------------------------------- /run-commands-automatically/step2-background.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | touch /root/createdFromStep2BackgroundScript -------------------------------------------------------------------------------- /challenges/kubernetes-challenge-1/2_task.md: -------------------------------------------------------------------------------- 1 | Save the source code of the application's `app.js` to `/root/app.js`. 2 | -------------------------------------------------------------------------------- /challenges/kubernetes-challenge-1/intro.md: -------------------------------------------------------------------------------- 1 | To complete this challenge you will need to {state challenge goal}. 2 | -------------------------------------------------------------------------------- /environments/multinodeexampleenv-cluster/node/build/1_installpackages.sh: -------------------------------------------------------------------------------- 1 | apt-get update 2 | apt-get install -y vim 3 | -------------------------------------------------------------------------------- /uilayouts/uilayout-vscode-terminal/intro.md: -------------------------------------------------------------------------------- 1 | Example using the VS Code / Terminal Split screen terminal layout. 2 | -------------------------------------------------------------------------------- /custom-events/site/site.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/katacoda/scenario-examples/HEAD/custom-events/site/site.tar.gz -------------------------------------------------------------------------------- /environment-usages/README.md: -------------------------------------------------------------------------------- 1 | # Katacoda Environments 2 | 3 | Learn more at https://www.katacoda.community/environments.html -------------------------------------------------------------------------------- /environments/multinodeexampleenv-cluster/master/build/1_installpackages.sh: -------------------------------------------------------------------------------- 1 | apt-get update 2 | apt-get install -y vim 3 | -------------------------------------------------------------------------------- /notebooks-py/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "jupyter@0.1", 3 | "backend": { 4 | "imageid": "python:3.8" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /challenges/node-challenge-1/1_verify.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cat /root/multiply.js /opt/test.js > /opt/.run.js; node /opt/.run.js -------------------------------------------------------------------------------- /course-data-host01-reference/intro.md: -------------------------------------------------------------------------------- 1 | This an example scenario to use background scripts including explicit references to host01 -------------------------------------------------------------------------------- /create-course/finish.md: -------------------------------------------------------------------------------- 1 | Congratulations, you have learned how to make a course based on a collection of Katacoda scenarios. 2 | -------------------------------------------------------------------------------- /delivering-training/creating-training-pathway-json/intro.md: -------------------------------------------------------------------------------- 1 | This scenario will explain how to create a training pathway. 2 | -------------------------------------------------------------------------------- /notebooks-py-slim/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "jupyter@0.1", 3 | "backend": { 4 | "imageid": "python:3.8" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /run-commands-automatically/step2-foreground.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "This is automatically run when the step starts" 4 | -------------------------------------------------------------------------------- /upload-assets/foreground.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | while [ ! -f /usr/local/bin/wait.sh ]; do sleep 1; done; /usr/local/bin/wait.sh -------------------------------------------------------------------------------- /challenges/kubernetes-challenge-1/assets/cheat: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | type_and_run 'curl "node01:30080?cmd=env" > /root/app-env' 4 | -------------------------------------------------------------------------------- /run-commands-automatically/foreground.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "This is automatically run when the scenario" 4 | 5 | pwd 6 | ls -lha -------------------------------------------------------------------------------- /run-commands-automatically/intro.md: -------------------------------------------------------------------------------- 1 | When the scenario starts, additional commands can be executed in the foreground or background. 2 | -------------------------------------------------------------------------------- /challenges/kubernetes-challenge-1/assets/cheat2: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | type_and_run 'curl "node01:30080?cmd=cat%20app.js" > /root/app.js' 4 | -------------------------------------------------------------------------------- /course-data-host01-reference/init-env.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | sleep 30 4 | ssh root@host01 "touch /tmp/kc-scenario-done > /tmp/load-quiz.out" -------------------------------------------------------------------------------- /uilayouts/uilayout-editor-terminal/intro.md: -------------------------------------------------------------------------------- 1 | When the scenario starts, additional commands can be executed in the foreground or background. 2 | -------------------------------------------------------------------------------- /.dev/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.4' 2 | 3 | services: 4 | dev: 5 | build: 6 | context: . 7 | volumes: 8 | - ..:/app/ 9 | -------------------------------------------------------------------------------- /challenges/kubernetes-challenge-1/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/katacoda/scenario-examples/HEAD/challenges/kubernetes-challenge-1/.DS_Store -------------------------------------------------------------------------------- /environment-usages/python-3-8/step1.md: -------------------------------------------------------------------------------- 1 | # Python 3.8 walrus operator example 2 | 3 | ```python 4 | print(walrus := True) 5 | ```{{execute T1}} 6 | -------------------------------------------------------------------------------- /instruction-guided-template/.cypress/instruction_guided_spec.js: -------------------------------------------------------------------------------- 1 | it("performs all lab actions", () => { 2 | cy.performAllLabActions(); 3 | }); 4 | -------------------------------------------------------------------------------- /placeholders/foreground2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "The URL to access Port 80 is [[HOST_SUBDOMAIN]]-80-[[KATACODA_HOST]].[[KATACODA_DOMAIN]]" 4 | -------------------------------------------------------------------------------- /.dev/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:12.6-alpine 2 | 3 | RUN apk add --update --no-cache bash make 4 | RUN npm install katacoda-cli -g 5 | 6 | WORKDIR /app 7 | -------------------------------------------------------------------------------- /placeholders/step1.md: -------------------------------------------------------------------------------- 1 |
[[HOST_IP]]
2 | 3 | `[[HOST_IP]]`{{execute}} 4 | 5 |
[[HOST2_IP]]
6 | 7 | `[[HOST2_IP]]`{{execute}} 8 | -------------------------------------------------------------------------------- /challenges/kubernetes-challenge-1/assets/tux.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/katacoda/scenario-examples/HEAD/challenges/kubernetes-challenge-1/assets/tux.png -------------------------------------------------------------------------------- /displaying-images/assets/logo-text-with-head.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/katacoda/scenario-examples/HEAD/displaying-images/assets/logo-text-with-head.png -------------------------------------------------------------------------------- /environment-usages/kubernetes-cluster-running/step1.md: -------------------------------------------------------------------------------- 1 | This environment has a `launch.sh`{{execute}} 2 | 3 | You can get with `kubectl get nodes`{{execute}} -------------------------------------------------------------------------------- /challenges/kubernetes-challenge-1/assets/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/katacoda/scenario-examples/HEAD/challenges/kubernetes-challenge-1/assets/.DS_Store -------------------------------------------------------------------------------- /environment-usages/python-3-7/step1.md: -------------------------------------------------------------------------------- 1 | # Python 3.7 time features example 2 | 3 | ```python 4 | import time 5 | 6 | print(time.time_ns()) 7 | ```{{execute T1}} 8 | -------------------------------------------------------------------------------- /run-commands-automatically/step3-foreground.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "Waiting to complete"; while [ ! -f /opt/.backgroundfinished ] ; do sleep 2; done; echo "Done" -------------------------------------------------------------------------------- /challenges/challenge-linux-solver/assets/streetcar.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/katacoda/scenario-examples/HEAD/challenges/challenge-linux-solver/assets/streetcar.pdf -------------------------------------------------------------------------------- /challenges/challenge-linux-solver/assets/solutions.sh.enc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/katacoda/scenario-examples/HEAD/challenges/challenge-linux-solver/assets/solutions.sh.enc -------------------------------------------------------------------------------- /displaying-progress-spinner/background.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | sleep 15 3 | echo "done" >> /root/katacoda-finished 4 | sleep 15 5 | echo "done" >> /root/katacoda-background-finished -------------------------------------------------------------------------------- /challenges/challenge-linux-solver/assets/cow-311266_640.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/katacoda/scenario-examples/HEAD/challenges/challenge-linux-solver/assets/cow-311266_640.png -------------------------------------------------------------------------------- /challenges/node-challenge-1/finish.md: -------------------------------------------------------------------------------- 1 | This is the finish page for the challenge. 2 | 3 | See the documentation on the style guide for the recommended content of the finish pages. 4 | -------------------------------------------------------------------------------- /challenges/challenge-hello-world/finish.md: -------------------------------------------------------------------------------- 1 | This is the finish page for the challenge. 2 | 3 | See the documentation on the style guide for the recommended content of the finish pages. 4 | -------------------------------------------------------------------------------- /challenges/kubernetes-challenge-1/finish.md: -------------------------------------------------------------------------------- 1 | This is the finish page for the challenge. 2 | 3 | See the documentation on the style guide for the recommended content of the finish pages. 4 | -------------------------------------------------------------------------------- /instruction-guided-template/step2.md: -------------------------------------------------------------------------------- 1 | This will be the second step, and the test should catch the error in 2 | this command when the command fails: 3 | 4 | `ehco [[HOST_IP]]`{{execute}} 5 | -------------------------------------------------------------------------------- /run-commands-automatically/step3-background.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "This is a background script with a long running process" 4 | 5 | sleep 10 6 | 7 | echo "done" >> /opt/.backgroundfinished -------------------------------------------------------------------------------- /create-scenario-101/intro.md: -------------------------------------------------------------------------------- 1 | In this scenario, you will learn how to create your first Katacoda scenario. It will explain the essential aspects and the design decisions that you need to be aware of. 2 | -------------------------------------------------------------------------------- /automatedtest/step2.md: -------------------------------------------------------------------------------- 1 | This will be the second step. 2 | 3 | ## Run Commands 4 | 5 | Commands can have tags to save duplicating the command within the test. 6 | 7 | `uname -a`{{execute test-uname}} 8 | -------------------------------------------------------------------------------- /challenges/challenge-linux-solver/assets/learning-modern-linux-book.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/katacoda/scenario-examples/HEAD/challenges/challenge-linux-solver/assets/learning-modern-linux-book.jpg -------------------------------------------------------------------------------- /challenges/node-challenge-1/assets/cheat: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | type_out "Updating code to include return" 4 | 5 | cat << EOF > /root/multiply.js 6 | function multiply(a, b){ 7 | return a * b 8 | } 9 | EOF -------------------------------------------------------------------------------- /automatedtest/foreground.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "The IP address for this environment is [[HOST_IP]]" 4 | echo "The URL to access Port 80 is [[HOST_SUBDOMAIN]]-80-[[KATACODA_HOST]].[[KATACODA_DOMAIN]]" 5 | -------------------------------------------------------------------------------- /custom-events/site/build-zip.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | tar --exclude=dist/ --exclude=.git/ --exclude=.idea/ --exclude=build-zip.sh --exclude=.DS_Store --exclude=node_modules/ --exclude=css/ -zcvf site.tar.gz . 4 | -------------------------------------------------------------------------------- /instruction-guided-template/intro.md: -------------------------------------------------------------------------------- 1 | This is an example lab that will be tested using [instruction-guided testing](https://interactive-docs.oreilly.com/overview/automated-tests.html#instruction-guided-tests). 2 | -------------------------------------------------------------------------------- /verified-steps/step2-answer.md: -------------------------------------------------------------------------------- 1 | This allows you to display additional information to help the user with the scenario. 2 | 3 | Such as, the correct command the user needs to run: 4 | 5 | `git init`{{execute}} 6 | -------------------------------------------------------------------------------- /challenges/kubernetes-challenge-1/configure.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | launch.sh 4 | kubectl apply -f /opt/deploy.yaml 5 | rm /opt/deploy.yaml 6 | 7 | echo "Started" 8 | echo 'done' > /opt/katacoda-background-finished -------------------------------------------------------------------------------- /course-data-host01-reference/set-env.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | clear 4 | while [ ! -f /tmp/wait-script.sh ] 5 | do 6 | clear 7 | sleep .2 8 | done 9 | 10 | chmod 755 /tmp/wait-script.sh; /tmp/wait-script.sh -------------------------------------------------------------------------------- /environments/exampleenv1/build/4_configure_environment.sh: -------------------------------------------------------------------------------- 1 | cat << EOF > /opt/configure-environment.sh 2 | #!/bin/bash 3 | 4 | docker run -it -d --name=http -p 80:80 nginx 5 | EOF 6 | chmod +x /opt/configure-environment.sh -------------------------------------------------------------------------------- /custom-events/intro.md: -------------------------------------------------------------------------------- 1 | Katacoda provides a service that listens to events defined in the scenario and allows to override the default behavior of the platform. 2 | 3 | This scenario will show you how to use custom events. 4 | -------------------------------------------------------------------------------- /environment-usages/minikube/step1.md: -------------------------------------------------------------------------------- 1 | The Minikube environment is designed for teaching users how to deploy Kubernetes using the Minikube project. 2 | 3 | The cluster can be started with the command `minikube start`{{execute}}. -------------------------------------------------------------------------------- /instruction-guided-template/foreground.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "The IP address for this environment is [[HOST_IP]]" 4 | echo "The URL to access Port 80 is [[HOST_SUBDOMAIN]]-80-[[KATACODA_HOST]].[[KATACODA_DOMAIN]]" 5 | -------------------------------------------------------------------------------- /use-ip-or-dns-for-environment/foreground.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "The IP address for this environment is [[HOST_IP]]" 4 | echo "The URL to access Port 80 is [[HOST_SxeUBDOMAIN]]-80-[[KATACODA_HOST]].[[KATACODA_DOMAIN]]" 5 | -------------------------------------------------------------------------------- /credit-where-credit-due/finish.md: -------------------------------------------------------------------------------- 1 | You have learned about credits. You can also consider adding to the bottom of the finish page a way for the learners to context you. 2 | 3 | --- 4 | 5 | [Contact the author](https://www.github.com) -------------------------------------------------------------------------------- /create-scenario-101/finish.md: -------------------------------------------------------------------------------- 1 | Congratulations. You have completed the scenario on the foundations of creating Katacoda content. Continue looking at examples on [katacoda.com/scenario-examples](https://katacoda.com/scenario-examples) 2 | -------------------------------------------------------------------------------- /environment-usages/kubernetes-cluster/step2.md: -------------------------------------------------------------------------------- 1 | Copy the command from the `kubeadm init` output starting with `kubeadm join` 2 | 3 | Run this on the second node, this will automatically add the node. Verify with `kubectl get nodes`{{execute}} -------------------------------------------------------------------------------- /displaying-progress-spinner/intro.md: -------------------------------------------------------------------------------- 1 | To indicate action happening in the background, a progress spinner can help provide uses with helpful feedback. 2 | 3 | This example is waiting for two background scripts to finish, each taking 15 seconds. 4 | -------------------------------------------------------------------------------- /custom-events/site/server/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | @@include('./index.html') 8 | 9 | 10 | -------------------------------------------------------------------------------- /course-data-host01-reference/step1.md: -------------------------------------------------------------------------------- 1 | This scenario contains an explicit reference to host01 in the background script (init-env.sh) 2 | 3 | ```sh 4 | sleep 2 5 | ssh root@host01 "chmod 755 /tmp/load-quiz.sh; /tmp/load-quiz.sh > /tmp/load-quiz.out" 6 | ``` 7 | -------------------------------------------------------------------------------- /environment-usages/ubuntu-2004/finish.md: -------------------------------------------------------------------------------- 1 | Start using the Ubuntu environment for your content by setting the `imageid` to `ubuntu:2004`. 2 | 3 | For example: 4 | 5 |
 6 | "backend": {
 7 |   "imageid": "ubuntu:2004"
 8 | }
 9 | 
10 | -------------------------------------------------------------------------------- /challenges/challenge-linux-solver/task_1.md: -------------------------------------------------------------------------------- 1 | 2 | Use `cowsay` with the quote: 3 | 4 | `O'Reilly, inspiring the future for more than 40 years` 5 | 6 | Steer this bovonic output to a file named `cowsay.txt`. 7 | -------------------------------------------------------------------------------- /upload-assets/background.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | sleep 5 4 | 5 | echo "done" | sudo tee /root/katacoda-finished 6 | 7 | echo "Everything ready... Finalise the deployment" 8 | 9 | /usr/local/bin/deploy.sh 10 | 11 | echo "done" | sudo tee /root/katacoda-background-finished -------------------------------------------------------------------------------- /automatedtest/step1.md: -------------------------------------------------------------------------------- 1 | This is an example scenario that will be tested using the Cypress integration. 2 | 3 | ## IP Address 4 | 5 | `echo [[HOST_IP]]`{{execute test-echoIP}} 6 | 7 | ## URL 8 | 9 | `echo [[HOST_SUBDOMAIN]]-80-[[KATACODA_HOST]].[[KATACODA_DOMAIN]]`{{execute}} 10 | -------------------------------------------------------------------------------- /challenges/challenge-linux-solver/verify.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | task=$(solver status -q) 4 | solver verify -q "$task" >> "/tmp/solver.out" 5 | 6 | verify_error=$? 7 | if [[ $verify_error -eq 0 ]] 8 | then 9 | solver request_advance_task "$task" 10 | fi 11 | exit $verify_error 12 | -------------------------------------------------------------------------------- /create-course/intro.md: -------------------------------------------------------------------------------- 1 | In this scenario, you will learn how to create a course, a series of Katacoda scenarios collected together. 2 | 3 | The advantage of creating a course is the ability to group related scenarios to provide users with a clear explanation and order to complete the content. -------------------------------------------------------------------------------- /instruction-guided-template/step1.md: -------------------------------------------------------------------------------- 1 | The instruction-guided tests are located in 2 | `.cypress/instruction_guided_spec.js`. 3 | 4 | ## IP Address 5 | 6 | `echo [[HOST_IP]]`{{execute}} 7 | 8 | ## URL 9 | 10 | `echo [[HOST_SUBDOMAIN]]-80-[[KATACODA_HOST]].[[KATACODA_DOMAIN]]`{{execute}} 11 | -------------------------------------------------------------------------------- /environment-usages/minikube/finish.md: -------------------------------------------------------------------------------- 1 | Start using the Minikube environment for your content by setting the `imageid` to `minikube`. 2 | 3 | For example: 4 | 5 |
 6 | "environment": {
 7 |   "uilayout": "terminal"
 8 | },
 9 | "backend": {
10 |   "imageid": "minikube"
11 | }
12 | 
-------------------------------------------------------------------------------- /challenges/kubernetes-challenge-1/1_task.md: -------------------------------------------------------------------------------- 1 | Write the environment variables from the application environment to a file called `/root/app-env` 2 | 3 | --- 4 | 5 | 6 | Here is an example of placing an image in the markdown of the task. 7 | -------------------------------------------------------------------------------- /environment-usages/ubuntu-1804/finish.md: -------------------------------------------------------------------------------- 1 | Start using the Ubuntu environment for your content by setting the `imageid` to `ubuntu:1804`. 2 | 3 | For example: 4 | 5 |
 6 | "backend": {
 7 |   "imageid": "ubuntu:1804"
 8 | }
 9 | 
10 | 11 | Looking for Ubuntu 20.04? Use the imageid `ubuntu:2004` -------------------------------------------------------------------------------- /strings.yaml: -------------------------------------------------------------------------------- 1 | # Override the strings in the UI 2 | continue: "Continue" 3 | start_scenario: "Start Scenario" 4 | welcome: "Welcome" 5 | difficulty: "Difficuly" 6 | time: "Time" 7 | steps: "Steps" 8 | step: "Step" 9 | of: "of" 10 | answer: "Answer" 11 | solution: "Solution" 12 | show: "Show" 13 | terminal: "Terminal" 14 | -------------------------------------------------------------------------------- /opening-multiple-terminals/step1.md: -------------------------------------------------------------------------------- 1 | `echo "Run in T1"`{{execute T1}} 2 | 3 |
`echo "Run in T1"`{{execute T1}}
4 | 5 | `echo "Run in T2"`{{execute T2}} 6 | 7 |
`echo "Run in T2"`{{execute T2}}
8 | 9 | `echo "No Terminal Defined"`{{execute}} 10 | 11 |
`echo "No Terminal Defined"`{{execute}}
12 | -------------------------------------------------------------------------------- /challenges/challenge-hello-world/intro.md: -------------------------------------------------------------------------------- 1 | This is a simplified "Hello, world" example for a challenge. It uses the challenge format v0.8, and illustrates how to define: 2 | 3 | - tasks 4 | - verification tests 5 | - hints 6 | 7 | Please reference the [detailed challenge documentation here](https://www.katacoda.community/challenges/challenges.html). 8 | -------------------------------------------------------------------------------- /challenges/kubernetes-challenge-1/1_hint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | seconds_sofar=$1 4 | 5 | if [[ $seconds_sofar -ge 5 && $seconds_sofar -lt 10 ]]; then 6 | echo "Keep going, a hint will be shown soon..." 7 | fi 8 | 9 | 10 | if [ $seconds_sofar -ge 10 ]; then 11 | echo "Hint: try running the command:" 12 | echo "curl node01:30080" 13 | fi -------------------------------------------------------------------------------- /vscode-extensions/foreground.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | EXTENSION_DIR=/opt/.katacodacode/extensions/humao.rest-client-0.24.3 3 | while ! [ -d "$EXTENSION_DIR" ]; 4 | do 5 | clear; 6 | echo 'Installing VS Code extensions, please wait before opening the IDE'. 7 | sleep 1 8 | done 9 | clear 10 | : VS Code extensions installed, now you can open the IDE -------------------------------------------------------------------------------- /environment-usages/kubernetes-cluster/finish.md: -------------------------------------------------------------------------------- 1 | Start using the Multi-node Kubernetes environment for your content by setting the `imageid` to `kubernetes-cluster:1.18`. 2 | 3 | For example: 4 | 5 |
 6 | "environment": {
 7 |   "uilayout": "terminal"
 8 | },
 9 | "backend": {
10 |   "imageid": "kubernetes-cluster:1.18"
11 | }
12 | 
-------------------------------------------------------------------------------- /custom-events/env-init.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | curl -L https://github.com/katacoda/scenario-examples/blob/master/custom-events/site/site.tar.gz?raw=true > ~/site.tar.gz 4 | tar -xvzf ~/site.tar.gz -C /home/scrapbook/tutorial 5 | cd /home/scrapbook/tutorial 6 | npm install 7 | echo "Starting... this will block the rest of the commands from running..." 8 | npm start 9 | -------------------------------------------------------------------------------- /environment-usages/kubernetes-cluster-running/finish.md: -------------------------------------------------------------------------------- 1 | Start using the Multi-node Kubernetes environment for your content by setting the `imageid` to `kubernetes-cluster-running:1.18`. 2 | 3 | For example: 4 | 5 |
 6 | "environment": {
 7 |   "uilayout": "terminal"
 8 | },
 9 | "backend": {
10 |   "imageid": "kubernetes-cluster-running:1.18"
11 | }
12 | 
-------------------------------------------------------------------------------- /challenges/challenge-linux-solver/hint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # First parameter, $1, is time in seconds since task instructions were presented 4 | 5 | task=$(solver status -q) 6 | solver verify "$task" -q > /dev/null 2>&1 7 | 8 | # Error code returned from challenge_verify is the hint content id to present 9 | verify_error=$? 10 | solver request_hint "$1" "$task" "$verify_error" 11 | -------------------------------------------------------------------------------- /environment-usages/kubernetes-cluster/step1.md: -------------------------------------------------------------------------------- 1 | With this environment the Kubernetes nodes are not configured. If you want to configure the nodes then you'd need to run `kubeadm` which has been set and configured. For example, for following command will initialise the master with the latest version installed. 2 | 3 | `kubeadm init --kubernetes-version $(kubeadm version -o short)`{{execute HOST1}} -------------------------------------------------------------------------------- /displaying-images/step1.md: -------------------------------------------------------------------------------- 1 | Within the Assets directory, images can be embedded into the scenarios. 2 | 3 | In this scenario, within the Assets directory, a `logo-text-with-head.png` file exists. Only images within the Assets directory are available. 4 | 5 |
 6 | ![Katacoda Logo](./assets/logo-text-with-head.png)
 7 | 
8 | 9 | ![Katacoda Logo](./assets/logo-text-with-head.png) 10 | -------------------------------------------------------------------------------- /uilayouts/uilayout-iframe/step1.md: -------------------------------------------------------------------------------- 1 | The Katacoda `iframe` UI Layout provides a full webpage experience. 2 | 3 | # Index.json 4 | 5 | Example: 6 | 7 |
 8 | "environment": {
 9 |     "uilayout": "iframe"
10 | },
11 | "backend": {
12 |     "url": "https://httpbin.org"
13 | }
14 | 
15 | 16 | ## Important 17 | 18 | The URL must be HTTPS and not block being embedded via an iframe. 19 | -------------------------------------------------------------------------------- /challenges/challenge-linux-solver/task_2.md: -------------------------------------------------------------------------------- 1 | Sometimes text output can be messy and hard to decipher. Take a look at the standard Linux `passwd` file: 2 | 3 | `cat /etc/passwd`{{execute}}. 4 | 5 | It's would be kinder to the eyes to format all the data in the rows into a table with columns. 6 | 7 | Find the right Linux command to tabularize the contents of the `passwd` file into the file `kinder-passwd.txt`. 8 | -------------------------------------------------------------------------------- /.dev/README.md: -------------------------------------------------------------------------------- 1 | # Development 2 | 3 | ## Available Make targets 4 | 5 | List all available Make targets with information. 6 | 7 | ```bash 8 | make help 9 | ``` 10 | 11 | ## Development environment 12 | 13 | Start docker container with development enviroment. 14 | 15 | ```bash 16 | make bash 17 | ``` 18 | 19 | ## Validate 20 | 21 | Validate the code. 22 | 23 | ```bash 24 | make validate 25 | ``` 26 | -------------------------------------------------------------------------------- /environment-usages/ubuntu-1804/step1.md: -------------------------------------------------------------------------------- 1 | The Katacoda Ubuntu Environment is a flexible single node environment. Users are connected to the environment as `root`. This provides them with full flexibility to install additional packages, explore the internals of Linux and experiment with new ideas. 2 | 3 | The environment also comes with Docker, meaning additional containers can be pulled and access as and when required. 4 | -------------------------------------------------------------------------------- /verified-steps/step2.md: -------------------------------------------------------------------------------- 1 | To provide users with more information or context, a Answer section can be provided. 2 | 3 | Here is the snippet from Step 2 within the `index.json`. 4 |
 5 | "details": {
 6 |     "steps": [
 7 |         {
 8 |             "title": "Show Answers",
 9 |             "text": "step2.md",
10 |             "answer": "step2-answer.md"
11 |         }
12 |     ]
13 | }
14 | 
15 | -------------------------------------------------------------------------------- /environment-usages/ubuntu-2004/step1.md: -------------------------------------------------------------------------------- 1 | The Katacoda Ubuntu Environment is a flexible single node environment. Users are connected to the environment as `root`. This provides them with full flexibility to install additional packages, explore the internals of Linux and experiment with new ideas. 2 | 3 | The environment also comes with Docker, meaning additional containers can be pulled and access as and when required. 4 | 5 | -------------------------------------------------------------------------------- /challenges/node-challenge-1/background.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "Started" 4 | 5 | cat << 'EOF' > /root/multiply.js 6 | function multiply(a, b){ 7 | a * b 8 | } 9 | EOF 10 | 11 | cat << 'EOF' > /opt/test.js 12 | var x = multiply(2, 2); 13 | if(x === 4) { 14 | process.exit(0); 15 | } else { 16 | console.log("Error", x); 17 | process.exit(1); 18 | } 19 | EOF 20 | 21 | echo 'done' > /opt/katacoda-background-finished -------------------------------------------------------------------------------- /create-scenario-101/step4.md: -------------------------------------------------------------------------------- 1 | For those who prefer an IDE based extension, Katacoda has extended Visual Studio Code for scenario management. 2 | 3 | This can be installed from the [Katacoda page on the Visual Studio Marketplace](https://marketplace.visualstudio.com/items/Katacoda.vscode/). 4 | 5 | After installation, you can create new scenarios, add steps and have quick access to the Katacoda markdown features via snippets. 6 | -------------------------------------------------------------------------------- /vscode-extensions/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo 'debconf debconf/frontend select Noninteractive' | sudo debconf-set-selections 3 | cd /tmp && apt-get update -y && apt install libarchive-tools -y # install bsdtar 4 | curl -L https://marketplace.visualstudio.com/_apis/public/gallery/publishers/humao/vsextensions/rest-client/0.24.3/vspackage | bsdtar -xvf - extension 5 | mv extension /opt/.katacodacode/extensions/humao.rest-client-0.24.3 -------------------------------------------------------------------------------- /delivering-training-pathway.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Delivering Training with Katacoda", 3 | "description": "", 4 | "icon": "fa-katacoda", 5 | "courses": [ 6 | { 7 | "course_id": "creating-training-pathway-json", 8 | "title": "Creating Training Pathway.json File", 9 | "description": "Learn how to define the scenarios to deliver for training" 10 | } 11 | ] 12 | } 13 | 14 | -------------------------------------------------------------------------------- /quiz/intro.md: -------------------------------------------------------------------------------- 1 | The purpose of the **Interactive Quiz** is to help retain knowledge discussed within the scenario and highlight the key topics you want users to remember. 2 | 3 | Within the quiz, users have complete access to the terminal environment. This allows them to explore the environment to identify the correct answer in order to proceed. 4 | 5 | Users need to answer all the questions correctly to get proceed to the next step. -------------------------------------------------------------------------------- /use-ip-or-dns-for-environment/step1.md: -------------------------------------------------------------------------------- 1 | ## IP Address 2 | 3 | `echo [[HOST_IP]]`{{execute}} 4 | 5 |
[[HOST_IP]]
6 | 7 | ## URL 8 | 9 | `echo [[HOST_SUBDOMAIN]]-80-[[KATACODA_HOST]].[[KATACODA_DOMAIN]]`{{execute}} 10 | 11 |
[[HOST_SUBDOMAIN]]-80-[[KATACODA_HOST]].[[KATACODA_DOMAIN]]
12 | 13 |
[[HOST_SUBDOMAIN]]
14 | 15 |
[[KATACODA_HOST]]
16 | 17 |
[[KATACODA_DOMAIN]]
18 | -------------------------------------------------------------------------------- /custom-events/site/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "new-app", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "start": "gulp default" 7 | }, 8 | "dependencies": { 9 | "fs": "0.0.1-security", 10 | "request": "^2.88.0" 11 | }, 12 | "devDependencies": { 13 | "browser-sync": "^2.26.7", 14 | "gulp": "^4.0.2", 15 | "gulp-file-include": "^2.1.0", 16 | "gulp-sass": "^4.0.2" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /uilayouts/uilayout-terminal/step1.md: -------------------------------------------------------------------------------- 1 | The Katacoda `terminal` UI Layout provides a full Terminal experience. 2 | 3 | # Index.json 4 | 5 | Example: 6 | 7 |
 8 | "environment": {
 9 |     "uilayout": "terminal"
10 | },
11 | 
12 | 13 | # Helper Functionality 14 | 15 | `echo "Running a command"`{{execute}} 16 | 17 | Other Terminal and Markdown functionality is available at https://katacoda.com/scenario-examples/scenarios/markdown-extensions -------------------------------------------------------------------------------- /environment-usages/go/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Go Environment", 3 | "description": "", 4 | "details": { 5 | "steps": [ 6 | { 7 | "title": "Go", 8 | "text": "step1.md" 9 | } 10 | ], 11 | "finish": { 12 | "text": "finish.md" 13 | } 14 | }, 15 | "environment": { 16 | "hideintro": true, 17 | "uilayout": "terminal" 18 | }, 19 | "backend": { 20 | "imageid": "golang:1.14" 21 | } 22 | } -------------------------------------------------------------------------------- /environment-usages/ruby/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Ruby Environment", 3 | "description": "", 4 | "details": { 5 | "steps": [ 6 | { 7 | "title": "Ruby", 8 | "text": "step1.md" 9 | } 10 | ], 11 | "finish": { 12 | "text": "finish.md" 13 | } 14 | }, 15 | "environment": { 16 | "hideintro": true, 17 | "uilayout": "terminal" 18 | }, 19 | "backend": { 20 | "imageid": "ruby:2.5" 21 | } 22 | } -------------------------------------------------------------------------------- /environment-usages/bash/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Bash Environment", 3 | "description": "", 4 | "details": { 5 | "steps": [ 6 | { 7 | "title": "Bash", 8 | "text": "step1.md" 9 | } 10 | ], 11 | "finish": { 12 | "text": "finish.md" 13 | } 14 | }, 15 | "environment": { 16 | "hideintro": true, 17 | "uilayout": "terminal" 18 | }, 19 | "backend": { 20 | "imageid": "bash1804" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /environment-usages/java/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Java Environment", 3 | "description": "", 4 | "details": { 5 | "steps": [ 6 | { 7 | "title": "Java", 8 | "text": "step1.md" 9 | } 10 | ], 11 | "finish": { 12 | "text": "finish.md" 13 | } 14 | }, 15 | "environment": { 16 | "hideintro": true, 17 | "uilayout": "terminal" 18 | }, 19 | "backend": { 20 | "imageid": "openjdk:15" 21 | } 22 | } -------------------------------------------------------------------------------- /environment-usages/r/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "R Environment", 3 | "description": "", 4 | "details": { 5 | "steps": [ 6 | { 7 | "title": "R Language", 8 | "text": "step1.md" 9 | } 10 | ], 11 | "finish": { 12 | "text": "finish.md" 13 | } 14 | }, 15 | "environment": { 16 | "hideintro": true, 17 | "uilayout": "terminal" 18 | }, 19 | "backend": { 20 | "imageid": "rlang:3.6.3" 21 | } 22 | } -------------------------------------------------------------------------------- /environment-usages/rust/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Rust Environment", 3 | "description": "", 4 | "details": { 5 | "steps": [ 6 | { 7 | "title": "Rust", 8 | "text": "step1.md" 9 | } 10 | ], 11 | "finish": { 12 | "text": "finish.md" 13 | } 14 | }, 15 | "environment": { 16 | "hideintro": true, 17 | "uilayout": "terminal" 18 | }, 19 | "backend": { 20 | "imageid": "rust:1.44.1" 21 | } 22 | } -------------------------------------------------------------------------------- /environment-usages/dotnet/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": ".NET Environment", 3 | "description": "", 4 | "details": { 5 | "steps": [ 6 | { 7 | "title": ".NET", 8 | "text": "step1.md" 9 | } 10 | ], 11 | "finish": { 12 | "text": "finish.md" 13 | } 14 | }, 15 | "environment": { 16 | "hideintro": true, 17 | "uilayout": "terminal" 18 | }, 19 | "backend": { 20 | "imageid": "dotnet:6.0" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /environment-usages/kotlin/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Kotlin Environment", 3 | "description": "", 4 | "details": { 5 | "steps": [ 6 | { 7 | "title": "Kotlin", 8 | "text": "step1.md" 9 | } 10 | ], 11 | "finish": { 12 | "text": "finish.md" 13 | } 14 | }, 15 | "environment": { 16 | "hideintro": true, 17 | "uilayout": "terminal" 18 | }, 19 | "backend": { 20 | "imageid": "kotlin:1.3.61" 21 | } 22 | } -------------------------------------------------------------------------------- /environment-usages/nodejs/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Node.js Environment", 3 | "description": "", 4 | "details": { 5 | "steps": [ 6 | { 7 | "title": "Node.js", 8 | "text": "step1.md" 9 | } 10 | ], 11 | "finish": { 12 | "text": "finish.md" 13 | } 14 | }, 15 | "environment": { 16 | "hideintro": true, 17 | "uilayout": "terminal" 18 | }, 19 | "backend": { 20 | "imageid": "nodejs:12" 21 | } 22 | } -------------------------------------------------------------------------------- /environment-usages/python/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Python 3 Environment", 3 | "description": "", 4 | "details": { 5 | "steps": [ 6 | { 7 | "title": "Python", 8 | "text": "step1.md" 9 | } 10 | ], 11 | "finish": { 12 | "text": "finish.md" 13 | } 14 | }, 15 | "environment": { 16 | "hideintro": true, 17 | "uilayout": "terminal" 18 | }, 19 | "backend": { 20 | "imageid": "python:3.6" 21 | } 22 | } -------------------------------------------------------------------------------- /create-scenario-101/step5.md: -------------------------------------------------------------------------------- 1 | As changes are being made to the content, when they are pushed into the master branch of a Git repository, the content on Katacoda can automatically be updated via a webhook. 2 | 3 | To configure the Webhook, follow the guide at [Create Author Profile](https://www.katacoda.community/essentials/author-profile.html). 4 | 5 | Once the webhook is installed, everytime you make a push to update to your content, Katacoda will be automatically updated. 6 | -------------------------------------------------------------------------------- /placeholders/step2.md: -------------------------------------------------------------------------------- 1 | Render port 8500: https://[[HOST_SUBDOMAIN]]-8500-[[KATACODA_HOST]].environments.katacoda.com/ 2 | 3 | Render port 8500:
https://[[HOST_SUBDOMAIN]]-8500-[[KATACODA_HOST]].environments.katacoda.com/
4 | 5 | Render port 80:
https://[[HOST_SUBDOMAIN]]-80-[[KATACODA_HOST]].environments.katacoda.com/
6 | 7 | Display page allowing user to select port: 8 |
https://[[HOST_SUBDOMAIN]]-[[KATACODA_HOST]].environments.katacoda.com/
9 | -------------------------------------------------------------------------------- /challenges/challenge-linux-solver/task_4.md: -------------------------------------------------------------------------------- 1 | The [xargs](https://man7.org/linux/man-pages/man1/xargs.1.html) command is powerful in Linux. Given the set of "1 2 3 4 5", with just one line add the string "I am [n]" to each file [n].txt. For instance file `2.txt` should contain a single line with "I am 2", file `5.txt` will contain "I am 5". This challenge needs to see your command, so place it in the provided script file `my-xargs.sh`. 2 | 3 | 💡 Tip: do not use a `for` or `while` loop, just xargs. 4 | -------------------------------------------------------------------------------- /environment-usages/minikube/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Minikube", 3 | "description": "Use Minikube to help explain Kubernetes", 4 | "details": { 5 | "steps": [ 6 | { 7 | "title": "Start Minikube", 8 | "text": "step1.md" 9 | } 10 | ], 11 | "finish": { 12 | "text": "finish.md" 13 | } 14 | }, 15 | "environment": { 16 | "hideintro": true, 17 | "uilayout": "terminal" 18 | }, 19 | "backend": { 20 | "imageid": "minikube" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /environment-usages/ubuntu-1804/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Ubuntu 18.04 Instance", 3 | "description": "General purpose environment", 4 | "details": { 5 | "steps": [ 6 | { 7 | "title": "Ubuntu 18.04", 8 | "text": "step1.md" 9 | } 10 | ], 11 | "finish": { 12 | "text": "finish.md" 13 | } 14 | }, 15 | "environment": { 16 | "hideintro": true, 17 | "uilayout": "terminal" 18 | }, 19 | "backend": { 20 | "imageid": "ubuntu:1804" 21 | } 22 | } -------------------------------------------------------------------------------- /environment-usages/ubuntu-2004/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Ubuntu 20.04 Instance", 3 | "description": "General purpose environment", 4 | "details": { 5 | "steps": [ 6 | { 7 | "title": "Ubuntu 20.04", 8 | "text": "step1.md" 9 | } 10 | ], 11 | "finish": { 12 | "text": "finish.md" 13 | } 14 | }, 15 | "environment": { 16 | "hideintro": true, 17 | "uilayout": "terminal" 18 | }, 19 | "backend": { 20 | "imageid": "ubuntu:2004" 21 | } 22 | } -------------------------------------------------------------------------------- /environment-usages/python-3-7/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Python 3.7 Environment", 3 | "description": "", 4 | "details": { 5 | "steps": [ 6 | { 7 | "title": "Python", 8 | "text": "step1.md", 9 | "foreground": "foreground.sh" 10 | } 11 | ], 12 | "finish": { 13 | "text": "finish.md" 14 | } 15 | }, 16 | "environment": { 17 | "hideintro": true, 18 | "uilayout": "terminal" 19 | }, 20 | "backend": { 21 | "imageid": "python:3.7" 22 | } 23 | } -------------------------------------------------------------------------------- /environment-usages/python-3-8/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Python 3.8 Environment", 3 | "description": "", 4 | "details": { 5 | "steps": [ 6 | { 7 | "title": "Python", 8 | "text": "step1.md", 9 | "foreground": "foreground.sh" 10 | } 11 | ], 12 | "finish": { 13 | "text": "finish.md" 14 | } 15 | }, 16 | "environment": { 17 | "hideintro": true, 18 | "uilayout": "terminal" 19 | }, 20 | "backend": { 21 | "imageid": "python:3.8" 22 | } 23 | } -------------------------------------------------------------------------------- /environments/kc-custom-env-vscode-extensions/build/1_init.sh: -------------------------------------------------------------------------------- 1 | cd /tmp && apt-get update -y && apt install libarchive-tools -y # install bsdtar 2 | curl -L https://marketplace.visualstudio.com/_apis/public/gallery/publishers/ms-python/vsextensions/python/2020.5.86806/vspackage | bsdtar -xvf - extension 3 | # The name of the directory for the extension should use the same pattern that when the extension is installed manually .-. 4 | mv extension /opt/.katacodacode/extensions/ms-python.python-2020.5.86806 -------------------------------------------------------------------------------- /displaying-images/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "noindex": true, 3 | "title": "Displaying Images", 4 | "description": "Display images as part of the scenario", 5 | "details": { 6 | "steps": [ 7 | { 8 | "title": "Asset Images", 9 | "text": "step1.md" 10 | } 11 | ] 12 | }, 13 | "environment": { 14 | "hideintro": true, 15 | "uilayout": "terminal" 16 | }, 17 | "backend": { 18 | "imageid": "ubuntu" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /course-data-host01-reference/assets/nginx.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2 2 | kind: Deployment 3 | metadata: 4 | name: nginx-deployment 5 | spec: 6 | selector: 7 | matchLabels: 8 | app: nginx 9 | replicas: 2 # tells deployment to run 2 pods matching the template 10 | template: 11 | metadata: 12 | labels: 13 | app: nginx 14 | spec: 15 | containers: 16 | - name: nginx 17 | image: nginx:1.14.2 18 | ports: 19 | - containerPort: 80 -------------------------------------------------------------------------------- /create-course/step2.md: -------------------------------------------------------------------------------- 1 | A course can include scenarios in different directories. This allows scenarios to be re-used and re-purposed in different situations. 2 | 3 | An example of this would be including the following: 4 | 5 |
 6 | {
 7 |     "pathway_id" "environment-usages",
 8 |     "course_id": "ubuntu",
 9 |     "title": "Ubuntu 16.04 Instance",
10 |     "description": "General purpose environment"
11 | },
12 | 
13 | 14 | This would reference the scenario Ubuntu from the environment-usages course. 15 | -------------------------------------------------------------------------------- /create-scenario-101/step2.md: -------------------------------------------------------------------------------- 1 | Within each step, a series of Markdown extensions have been created that can provide various details for the users' experience. 2 | 3 | For example, commands such as `echo "Run in Terminal"`{{execute}} can be executed by clicking the command. 4 | 5 | This is done by adding `execute` to the markdown code block, for example: 6 |
`echo "Run in Terminal"`{{execute}}
7 | 8 | More can be found at the scenario [on Markdown extensions](https://katacoda.com/scenario-examples/scenarios/markdown-extensions). 9 | -------------------------------------------------------------------------------- /writing-files/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "noindex": true, 3 | "title": "Writing files", 4 | "description": "How to write a file in your scenario", 5 | "details": { 6 | "steps": [ 7 | { 8 | "title": "How to write a file in your scenario", 9 | "text": "step1.md" 10 | } 11 | ] 12 | }, 13 | "environment": { 14 | "hideintro": true, 15 | "uilayout": "terminal" 16 | }, 17 | "backend": { 18 | "imageid": "ubuntu" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /clipboard/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "noindex": true, 3 | "title": "Clipboard Integration", 4 | "description": "Understand how the Katacoda Clipboard integration", 5 | "details": { 6 | "steps": [ 7 | { 8 | "title": "Clipboard Examples", 9 | "text": "step1.md" 10 | } 11 | ] 12 | }, 13 | "environment": { 14 | "hideintro": true, 15 | "uilayout": "editor-terminal" 16 | }, 17 | "backend": { 18 | "imageid": "ubuntu" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /uilayouts/uilayout-terminal/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "noindex": true, 3 | "title": "Scenario with Terminal UI", 4 | "description": "Katacoda Scenario Example", 5 | "details": { 6 | "steps": [ 7 | { 8 | "title": "", 9 | "text": "step1.md" 10 | } 11 | ] 12 | }, 13 | "environment": { 14 | "hideintro": true, 15 | "hidefinish": true, 16 | "uilayout": "terminal" 17 | }, 18 | "backend": { 19 | "imageid": "nodejs:12" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /environments/README.md: -------------------------------------------------------------------------------- 1 | ## Creating Custom Environments on Katacoda 2 | 3 | NOTE: This is only available with a Katacoda Subscription. 4 | 5 | ## Creating a new Environment 6 | 7 | 1) Create a directory. This will be the name of the environment. 8 | 9 | 2) Within the directory, create a new directory called build 10 | 11 | 3) Within the build directory, create a series of bash scripts, prefixed with a number to indicate order. For example: 12 | 13 | 1_installpackages.sh 14 | 15 | 2_pulldockerimages.sh 16 | 17 | 3_pulldemos.sh 18 | -------------------------------------------------------------------------------- /markdown-extensions/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "noindex": true, 3 | "title": "Markdown Extensions", 4 | "description": "Examples of how the Katacoda Markdown Extensions", 5 | "details": { 6 | "steps": [ 7 | { 8 | "title": "Extension Examples", 9 | "text": "step1.md" 10 | } 11 | ] 12 | }, 13 | "environment": { 14 | "hideintro": true, 15 | "uilayout": "terminal-terminal" 16 | }, 17 | "backend": { 18 | "imageid": "docker-swarm" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /uilayouts/uilayout-terminal-terminal/step1.md: -------------------------------------------------------------------------------- 1 | The Katacoda `terminal-terminal` UI Layout provides a full Terminal experience. 2 | 3 | # Index.json 4 | 5 | Example: 6 | 7 |
 8 | "environment": {
 9 |     "uilayout": "terminal-terminal"
10 | },
11 | 
12 | 13 | # Helper Functionality 14 | 15 | `echo "Running a command on Host 1"`{{execute HOST1}} 16 | 17 | `echo "Running a command on Host 2"`{{execute HOST2}} 18 | 19 | Other Terminal and Markdown functionality is available at https://katacoda.com/scenario-examples/scenarios/markdown-extensions 20 | -------------------------------------------------------------------------------- /environment-usages/kubernetes-cluster-running/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Kubernetes", 3 | "description": "Multi node Kubernetes cluster configured using Kubeadm", 4 | "details": { 5 | "steps": [ 6 | { 7 | "title": "Running Kubernetes", 8 | "text": "step1.md" 9 | } 10 | ], 11 | "finish": { 12 | "text": "finish.md" 13 | } 14 | }, 15 | "environment": { 16 | "hideintro": true, 17 | "uilayout": "terminal-terminal" 18 | }, 19 | "backend": { 20 | "imageid": "kubernetes-cluster-running:1.18" 21 | } 22 | } -------------------------------------------------------------------------------- /run-commands-automatically/step2.md: -------------------------------------------------------------------------------- 1 | By having scripts run for each step it's possible to simulate activities and actions under the covers. Such as modifying settings or causing additional situations for the user to complete. 2 | 3 | The syntax is the same as when defining scripts for intro. 4 | 5 |
 6 | {
 7 |     "title": "Scripts Example",
 8 |     "courseData": "step2-background.sh",
 9 |     "code": "step2-foreground.sh",
10 |     "text": "step2.md"
11 | }
12 | 
13 | 14 | The next step will explain how to handle the user having to wait for a task to complete. 15 | -------------------------------------------------------------------------------- /uilayouts/uilayout-terminal-terminal/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "noindex": true, 3 | "title": "Scenario with Terminal Terminal UI", 4 | "description": "Katacoda Scenario Example", 5 | "details": { 6 | "steps": [ 7 | { 8 | "title": "", 9 | "text": "step1.md" 10 | } 11 | ] 12 | }, 13 | "environment": { 14 | "hideintro": true, 15 | "hidefinish": true, 16 | "uilayout": "terminal-terminal" 17 | }, 18 | "backend": { 19 | "imageid": "docker-swarm" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /uilayouts/uilayout-iframe/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "noindex": true, 3 | "title": "Scenario with Terminal iFrame UI", 4 | "description": "Katacoda Scenario Example", 5 | "details": { 6 | "steps": [ 7 | { 8 | "title": "", 9 | "text": "step1.md" 10 | } 11 | ] 12 | }, 13 | "environment": { 14 | "hideintro": true, 15 | "hidefinish": true, 16 | "uilayout": "iframe" 17 | }, 18 | "backend": { 19 | "imageid": "bash", 20 | "url": "https://httpbin.org" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /embed-videos/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Embed Videos into Scenarios", 3 | "description": "Learn how to embed YouTube videos into a scenario", 4 | "difficulty": "Beginner", 5 | "time": "10", 6 | "details": { 7 | "steps": [ 8 | { 9 | "title": "Embedding Video", 10 | "text": "step1.md" 11 | } 12 | ], 13 | "intro": { 14 | "text": "intro.md" 15 | }, 16 | "finish": { 17 | "text": "finish.md" 18 | } 19 | }, 20 | "environment": { 21 | "uilayout": "terminal" 22 | }, 23 | "backend": { 24 | "imageid": "bash" 25 | } 26 | } -------------------------------------------------------------------------------- /automatedtest/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Automated Test Example", 3 | "description": "Example of using Cypress to test a Katacoda scenario", 4 | "details": { 5 | "steps": [ 6 | { 7 | "text": "step1.md", 8 | "code": "foreground.sh" 9 | }, 10 | { 11 | "text": "step2.md" 12 | } 13 | ], 14 | "intro": { 15 | "text": "intro.md" 16 | }, 17 | "finish": { 18 | "text": "finish.md" 19 | } 20 | }, 21 | "environment": { 22 | "uilayout": "terminal" 23 | }, 24 | "backend": { 25 | "imageid": "ubuntu" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /delivering-training/creating-training-pathway-json/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Creating Training Pathway.json File", 3 | "description": "Learn how to define the scenarios to deliver for training", 4 | "details": { 5 | "steps": [ 6 | { 7 | "title": "training-pathway.json", 8 | "text": "step1.md" 9 | } 10 | ], 11 | "intro": { 12 | "text": "intro.md" 13 | }, 14 | "finish": { 15 | "text": "finish.md" 16 | } 17 | }, 18 | "environment": { 19 | "uilayout": "editor-terminal" 20 | }, 21 | "backend": { 22 | "imageid": "ubuntu" 23 | } 24 | } -------------------------------------------------------------------------------- /instruction-guided-template/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Instruction-Guided Test Template", 3 | "description": "Example of using Cypress to test a lab", 4 | "details": { 5 | "steps": [ 6 | { 7 | "text": "step1.md", 8 | "code": "foreground.sh" 9 | }, 10 | { 11 | "text": "step2.md" 12 | } 13 | ], 14 | "intro": { 15 | "text": "intro.md" 16 | }, 17 | "finish": { 18 | "text": "finish.md" 19 | } 20 | }, 21 | "environment": { 22 | "uilayout": "terminal" 23 | }, 24 | "backend": { 25 | "imageid": "ubuntu" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /uilayouts/uilayout-terminal-iframe-split/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "noindex": true, 3 | "title": "Scenario with Terminal iFrame Split UI", 4 | "description": "Katacoda Scenario Example", 5 | "details": { 6 | "steps": [ 7 | { 8 | "title": "", 9 | "text": "step1.md" 10 | } 11 | ] 12 | }, 13 | "environment": { 14 | "hideintro": true, 15 | "hidefinish": true, 16 | "uilayout": "terminal-iframe-split" 17 | }, 18 | "backend": { 19 | "imageid": "ubuntu:2004", 20 | "port": 80 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /visualise-docker/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "noindex": true, 3 | "title": "Visualise Environment Tab", 4 | "description": "Learn how to add the Visualise Tab", 5 | "details": { 6 | "steps": [ 7 | { 8 | "title": "", 9 | "text": "step1.md" 10 | } 11 | ] 12 | }, 13 | "files": [], 14 | "environment": { 15 | "hideintro": true, "hidefinish": true, 16 | 17 | "showvisualise": true, 18 | 19 | "uilayout": "terminal" 20 | }, 21 | "backend": { 22 | "imageid": "ubuntu" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /displaying-web-ui/step1.md: -------------------------------------------------------------------------------- 1 | ## Start HTTP Server 2 | 3 | `docker container run -p 80:80 -d katacoda/docker-http-server`{{execute}} 4 | 5 | ## Test 6 | 7 | `curl localhost`{{execute}} 8 | 9 | ## Generated Web Link 10 | 11 | https://[[HOST_SUBDOMAIN]]-80-[[KATACODA_HOST]].environments.katacoda.com 12 | 13 | ## Markdown 14 | 15 |
https://[[HOST_SUBDOMAIN]]-80-[[KATACODA_HOST]].environments.katacoda.com
16 | 17 | ## Learn More 18 | 19 | [Displaying Tabs](https://katacoda.com/scenario-examples/scenarios/dashboard-tabs) and [embedding iFrames](https://katacoda.com/scenario-examples/scenarios/dashboard-tabs-iframe) 20 | -------------------------------------------------------------------------------- /writing-files/step1.md: -------------------------------------------------------------------------------- 1 | You can write files in your scenario using a bash command: 2 | 3 | ```sh 4 | cat << EOF > /tmp/storageos-secret.yaml 5 | apiVersion: v1 6 | kind: Secret 7 | metadata: 8 | name: "storageos-api" 9 | namespace: "storageos-operator" 10 | labels: 11 | app: "storageos" 12 | type: "kubernetes.io/storageos" 13 | EOF 14 | ```{{execute}} 15 | 16 | Check the content of your file 17 | `cat /tmp/storageos-secret.yaml`{{execute}} 18 | 19 | If you need to have those files created at the start of the scenario, you can define them as [assets](https://katacoda.com/scenario-examples/scenarios/upload-assets). 20 | -------------------------------------------------------------------------------- /opening-multiple-terminals/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Opening Multiple Terminals", 3 | "description": "Show how to create multiple terminals when running commands", 4 | "difficulty": "Beginner", 5 | "time": "10 minutes", 6 | "details": { 7 | "steps": [ 8 | { 9 | "title": "Multiple Terminals", 10 | "text": "step1.md" 11 | } 12 | ], 13 | "intro": { 14 | "text": "intro.md" 15 | }, 16 | "finish": { 17 | "text": "finish.md" 18 | } 19 | }, 20 | "environment": { 21 | "uilayout": "terminal" 22 | }, 23 | "backend": { 24 | "imageid": "bash" 25 | } 26 | } -------------------------------------------------------------------------------- /uilayouts/uilayout-terminal-iframe-split/step1.md: -------------------------------------------------------------------------------- 1 | The Katacoda `terminal-iframe-split` UI Layout provides a full Terminal experience with the ability to include webpages as iframes alongside the content. 2 | 3 | # Index.json 4 | 5 | Example: 6 | 7 |
 8 | "environment": {
 9 |     "uilayout": "terminal-iframe-split"
10 | },
11 | "backend": {
12 |     "imageid": "ubuntu",
13 |     "port": 80
14 | }
15 | 
16 | 17 | More information can be found at https://katacoda.com/scenario-examples/scenarios/dashboard-tabs-iframe 18 | 19 | # Example 20 | 21 | `docker container run -p 80:80 -d katacoda/docker-http-server`{{execute}} 22 | -------------------------------------------------------------------------------- /uilayouts/uilayout-terminal-iframe/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "noindex": true, 3 | "title": "Scenario with Terminal iFrame UI", 4 | "description": "Katacoda Scenario Example", 5 | "details": { 6 | "steps": [ 7 | { 8 | "title": "", 9 | "text": "step1.md" 10 | } 11 | ] 12 | }, 13 | "environment": { 14 | "hideintro": true, 15 | "hidefinish": true, 16 | "showdashboards": true, 17 | "uilayout": "terminal-iframe" 18 | }, 19 | "backend": { 20 | "imageid": "nodejs:12", 21 | "port": 3000 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /uilayouts/uilayout-vscode-terminal/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "noindex": true, 3 | "title": "Scenario with VS Code / Terminal UI Split Screen", 4 | "description": "Katacoda Scenario Example", 5 | "details": { 6 | "steps": [ 7 | { 8 | "text": "step1.md" 9 | } 10 | ], 11 | "intro": { 12 | "text": "intro.md", 13 | "credits": "" 14 | } 15 | }, 16 | "environment": { 17 | "hidefinish": true, 18 | "uilayout": "vscode-terminal-split" 19 | }, 20 | "backend": { 21 | "imageid": "nodejs:12" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /environment-usages/kubernetes-cluster/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Kubernetes", 3 | "description": "Multi node Kubernetes cluster configured using Kubeadm", 4 | "details": { 5 | "steps": [ 6 | { 7 | "title": "Control Plane Node", 8 | "text": "step1.md" 9 | }, 10 | { 11 | "title": "Worker Node", 12 | "text": "step2.md" 13 | } 14 | ], 15 | "finish": { 16 | "text": "finish.md" 17 | } 18 | }, 19 | "environment": { 20 | "hideintro": true, 21 | "uilayout": "terminal-terminal" 22 | }, 23 | "backend": { 24 | "imageid": "kubernetes-cluster:1.18" 25 | } 26 | } -------------------------------------------------------------------------------- /challenges/challenge-hello-world/2_hint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # See hint documentation: https://www.katacoda.community/challenges.html#hints 4 | 5 | seconds_sofar=$1 6 | 7 | # echo "Debug Hint Task 2: $seconds_sofar" 8 | 9 | # This hint message will appear between 10-20 seconds elapsed after the task began. 10 | if [[ $seconds_sofar -ge 10 && $seconds_sofar -lt 20 ]]; then 11 | echo "Still working on it? I'll show a hint very soon..." 12 | fi 13 | 14 | # This hint message will appear 20+ seconds elapsed after the task began. 15 | if [ $seconds_sofar -ge 20 ]; then 16 | echo "**Hint:** This hint could nudge you toward the solution." 17 | fi 18 | -------------------------------------------------------------------------------- /course-data-host01-reference/assets/wait-script.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | clear 3 | 4 | echo -e "Preparing the environment ..." 5 | 6 | show_progress() 7 | { 8 | echo -n "Starting" 9 | local -r pid="${1}" 10 | local -r delay='0.75' 11 | local spinstr='\|/-' 12 | local temp 13 | printf " \b\b\b\b" 14 | until [ -f /tmp/kc-scenario-done ]; do 15 | temp="${spinstr#?}" 16 | printf " [%c] " "${spinstr}" 17 | spinstr=${temp}${spinstr%"${temp}"} 18 | sleep "${delay}" 19 | printf "\b\b\b\b\b\b" 20 | done 21 | printf " \b\b\b\b" 22 | echo "" 23 | echo "Configured" 24 | } 25 | 26 | show_progress 27 | 28 | 29 | -------------------------------------------------------------------------------- /.dev/Makefile: -------------------------------------------------------------------------------- 1 | SHELL := /bin/bash 2 | .DEFAULT_GOAL := help 3 | 4 | .PHONY: help 5 | help: ## help target to show available commands with information 6 | @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' 7 | 8 | .PHONY: validate 9 | validate: docker-build ## Validate the katacoda scenarios 10 | docker-compose run dev katacoda validate:all --repo=/app/ 11 | 12 | .PHONY: docker-build 13 | docker-build: ## Build Container 14 | docker-compose build 15 | 16 | .PHONY: bash 17 | bash: docker-build ## Open bash with dev dependencies installed 18 | docker-compose run dev bash 19 | -------------------------------------------------------------------------------- /challenges/challenge-hello-world/SOLUTIONS.md: -------------------------------------------------------------------------------- 1 | # SOLUTIONS 2 | 3 | For each task, please provide instructions for the solution. This is NOT shared with the learner, but is for our internal reference, to help test the scenario. 4 | 5 | ## Task 1 Solution 6 | 7 | - Poke the widget 8 | - Change the value 9 | - Paste in the code 10 | - Run the thing 11 | - [etc...] 12 | 13 | ## Task 2 Solution 14 | 15 | - xxxxx 16 | - xxxxx 17 | - xxxxx 18 | 19 | ## Task 3 Solution 20 | 21 | - xxxxx 22 | - xxxxx 23 | - xxxxx 24 | 25 | ## Task 4 Solution 26 | 27 | - xxxxx 28 | - xxxxx 29 | - xxxxx 30 | 31 | ## Task 5 Solution 32 | 33 | - xxxxx 34 | - xxxxx 35 | - xxxxx 36 | -------------------------------------------------------------------------------- /vscode-extensions/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Visual Studio Code - Install extensions", 3 | "description": "Install extensions", 4 | "details": { 5 | "steps": [ 6 | { 7 | "title": "😺", 8 | "courseData": "setup.sh", 9 | "code": "foreground.sh", 10 | "text": "step1.md" 11 | } 12 | ] 13 | }, 14 | "environment": { 15 | "hideintro": true, 16 | "uilayout": "terminal", 17 | "uieditorpath": "/root/example", 18 | "showide": true, 19 | "ide": "ssh host01 '/opt/start-vscode.sh /root/example'" 20 | }, 21 | "backend": { 22 | "imageid": "kubernetes-cluster-running:1.18" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /challenges/node-challenge-1/.cypress/node_spec.js: -------------------------------------------------------------------------------- 1 | describe('Node.js Challenge', () => { 2 | before(() => { 3 | cy.startScenario() 4 | }); 5 | 6 | it('starts on Task 1', () => { 7 | cy.terminalShouldContain('Task 1'); 8 | cy.terminalNotShouldContain('Task 2'); 9 | }); 10 | 11 | it('completing Task 1 completes the challenge', () => { 12 | cy.viewport(2560, 1600) 13 | 14 | cy.terminalShouldContain('Task 1'); 15 | 16 | cy.terminalNotShouldContain('Completed Challenge'); 17 | 18 | cy.terminalType("cheat"); 19 | 20 | cy.terminalShouldContain('✅'); 21 | 22 | cy.terminalShouldContain('Completed Challenge'); 23 | }); 24 | }) -------------------------------------------------------------------------------- /challenges/challenge-hello-world/assets/example-asset.txt: -------------------------------------------------------------------------------- 1 | Hi! I'm just an example asset. Don't mind me. 2 | 3 | I'm only here because the index.json specified to copy over 4 | the contents of the scenario's source /assets/ folder into 5 | the environment's /root/ folder, like so: 6 | 7 | "assets": { 8 | "client": [ 9 | { "file": "*", "target": "~/" } 10 | ] 11 | } 12 | 13 | The ~/ just refers to the environment user's home folder. 14 | That user is named "root". Once the environment loads, try 15 | confirming that this example got copied over with: 16 | 17 | $ pwd 18 | /root 19 | 20 | $ ls 21 | example-asset.txt -------------------------------------------------------------------------------- /displaying-web-ui/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Displaying Web UI ", 3 | "description": "Learn how to access a Web UI running on the environment", 4 | "difficulty": "easy", 5 | "time": "10 minutes", 6 | "details": { 7 | "steps": [ 8 | { 9 | "text": "step1.md" 10 | } 11 | ], 12 | "intro": { 13 | "text": "intro.md" 14 | }, 15 | "finish": { 16 | "text": "finish.md" 17 | } 18 | }, 19 | "environment": { 20 | "hideintro": true, 21 | "uilayout": "terminal" 22 | }, 23 | "backend": { 24 | "imageid": "ubuntu" 25 | } 26 | } -------------------------------------------------------------------------------- /use-ip-or-dns-for-environment/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "title": "Get the IP or DNS name for the environment", 4 | "description": "Learn how to get the IP address or DNS name for configuration scripts", 5 | "difficulty": "Beginner", 6 | "time": "60 minutes", 7 | "details": { 8 | "steps": [ 9 | { 10 | "text": "step1.md", 11 | "code": "foreground.sh" 12 | } 13 | ], 14 | "intro": { 15 | "text": "intro.md" 16 | }, 17 | "finish": { 18 | "text": "finish.md" 19 | } 20 | }, 21 | "environment": { 22 | "uilayout": "terminal" 23 | }, 24 | "backend": { 25 | "imageid": "ubuntu" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /uilayouts/uilayout-terminal-with-vscode/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "noindex": true, 3 | "title": "Scenario with Terminal and VS Code UI as Tab", 4 | "description": "Katacoda Scenario Example", 5 | "details": { 6 | "steps": [ 7 | { 8 | "title": "", 9 | "text": "step1.md" 10 | } 11 | ] 12 | }, 13 | "files": [ 14 | "app.js", "index.js" 15 | ], 16 | "environment": { 17 | "uieditorpath": "/root/example", 18 | "showide": true, 19 | "idePort": 23000, 20 | "uilayout": "terminal" 21 | }, 22 | "backend": { 23 | "imageid": "ubuntu:2004" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /quiz/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "noindex": true, 3 | "title": "Interactive Quiz", 4 | "description": "Verify understanding and key points by using an interactive quiz", 5 | "details": { 6 | "steps": [ 7 | { 8 | "title": "Quiz", 9 | "text": "step1.md" 10 | } 11 | ], 12 | "intro": { 13 | "text": "intro.md", 14 | "credits": "" 15 | }, 16 | "finish": { 17 | "text": "finish.md" 18 | } 19 | }, 20 | "files": [], 21 | "environment": { 22 | "uilayout": "terminal" 23 | }, 24 | "backend": { 25 | "imageid": "ubuntu" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /run-commands-automatically/step1.md: -------------------------------------------------------------------------------- 1 | Commands can be run automatically in the foreground and background when a scenario starts and when a step loads. 2 | 3 | The `index.json` file contains the scenario structure. 4 | 5 | Within the `intro` block and for each step, two files can be defined under `courseData` and `code`. 6 | 7 | `courseData` defines a script which runs in the background. 8 | 9 | `code` defines the commands to run in the foreground. 10 | 11 |
12 | "intro": {
13 |     "text": "intro.md",
14 |     "courseData": "background.sh",
15 |     "code": "foreground.sh",
16 |     "credits": ""
17 | }
18 | 
19 | 20 | When the user proceeds to the next step, additional scripts can be run. 21 | -------------------------------------------------------------------------------- /embed-videos/step1.md: -------------------------------------------------------------------------------- 1 | Within the Markdown content for Katacoda you can embed any HTML element, this means you would have the ability to embed YouTube videos, such as the example below. 2 | 3 | 4 | 5 | The HTML included is: 6 | 7 |
 8 | <iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/KeJJ34BvA7Q" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
 9 | 
10 | -------------------------------------------------------------------------------- /embed-videos/intro.md: -------------------------------------------------------------------------------- 1 | Example of embedding a video on the intro screen. 2 | 3 | 4 | 5 | Here is the HTML example: 6 | 7 |
 8 | <iframe style="width: 700px;height: 400px;" src="https://www.youtube-nocookie.com/embed/KeJJ34BvA7Q" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
 9 | 
10 | 11 | *Note:* On the Intro panel, the width and height must be set via the style attribute. 12 | -------------------------------------------------------------------------------- /credit-where-credit-due/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Credit where credit due", 3 | "description": "Possible ways to provide credit for the content or ideas within the scenario", 4 | "difficulty": "Beginner", 5 | "time": "5 minutes", 6 | "details": { 7 | "steps": [ 8 | { 9 | "title": "Hello World", 10 | "text": "step1.md" 11 | } 12 | ], 13 | "intro": { 14 | "text": "intro.md", 15 | "credits": "Here we can provide **credit** to others such as a link to a https://github.com repo" 16 | }, 17 | "finish": { 18 | "text": "finish.md" 19 | } 20 | }, 21 | "environment": { 22 | "uilayout": "terminal" 23 | }, 24 | "backend": { 25 | "imageid": "bash" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /exclusion-patterns/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "exclusion-patterns", 3 | "title": "Exclusion patterns", 4 | "description": "Exclude files or directories of your scenario", 5 | "details": { 6 | "steps": [ 7 | { 8 | "title": "Exclusion patterns", 9 | "text": "step1.md" 10 | } 11 | ] 12 | }, 13 | "files": [ 14 | "poc.sh" 15 | ], 16 | "environment": { 17 | "hideintro": true, 18 | "hidefinish": true, 19 | "uilayout": "editor-terminal-v1", 20 | "uisettings": "bash", 21 | "exclusionPatterns": ["*test", "./test/*", "./logs"] 22 | }, 23 | "backend": { 24 | "imageid": "nodejs:12" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /notebooks-py/Index.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "# A example Notebook\n", 10 | "## Katacoda" 11 | ] 12 | } 13 | ], 14 | "metadata": { 15 | "kernelspec": { 16 | "display_name": "Python 3", 17 | "language": "python", 18 | "name": "python3" 19 | }, 20 | "language_info": { 21 | "codemirror_mode": { 22 | "name": "ipython", 23 | "version": 3 24 | }, 25 | "file_extension": ".py", 26 | "mimetype": "text/x-python", 27 | "name": "python", 28 | "nbconvert_exporter": "python", 29 | "pygments_lexer": "ipython3", 30 | "version": "3.8.6" 31 | } 32 | }, 33 | "nbformat": 4, 34 | "nbformat_minor": 4 35 | } 36 | -------------------------------------------------------------------------------- /notebooks-py-slim/Index.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "# A example Notebook\n", 10 | "## Katacoda" 11 | ] 12 | } 13 | ], 14 | "metadata": { 15 | "kernelspec": { 16 | "display_name": "Python 3", 17 | "language": "python", 18 | "name": "python3" 19 | }, 20 | "language_info": { 21 | "codemirror_mode": { 22 | "name": "ipython", 23 | "version": 3 24 | }, 25 | "file_extension": ".py", 26 | "mimetype": "text/x-python", 27 | "name": "python", 28 | "nbconvert_exporter": "python", 29 | "pygments_lexer": "ipython3", 30 | "version": "3.8.6" 31 | } 32 | }, 33 | "nbformat": 4, 34 | "nbformat_minor": 4 35 | } 36 | -------------------------------------------------------------------------------- /uilayouts/uilayout-terminal-iframe/step1.md: -------------------------------------------------------------------------------- 1 | The Katacoda `terminal-iframe` UI Layout provides a full Terminal experience with the ability to include webpages as iframes alongside the content. 2 | 3 | # Index.json 4 | 5 | Example: 6 | 7 |
 8 | "environment": {
 9 |     "showdashboards": true,
10 |     "uilayout": "terminal-iframe"
11 | },
12 | "backend": {
13 |     "imageid": "nodejs:12",
14 |     "port": 3000
15 | }
16 | 
17 | 18 | More information can be found at https://katacoda.com/scenario-examples/scenarios/dashboard-tabs-iframe 19 | 20 | # Helper Functionality 21 | 22 | View the iFrame https://[[HOST_SUBDOMAIN]]-3000-[[KATACODA_HOST]].environments.katacoda.com 23 | 24 | Other links open in a new tab https://[[HOST_SUBDOMAIN]]-80-[[KATACODA_HOST]].environments.katacoda.com -------------------------------------------------------------------------------- /placeholders/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Using Katacoda Placeholders for dynamic content", 3 | "description": "Learn how to get the IP address and URL parts for the environment", 4 | "difficulty": "Beginner", 5 | "time": "10", 6 | "details": { 7 | "steps": [ 8 | { 9 | "title": "IP Addresses", 10 | "code": "foreground1.sh", 11 | "text": "step1.md" 12 | }, 13 | { 14 | "title": "URLs", 15 | "code": "foreground2.sh", 16 | "text": "step2.md" 17 | } 18 | ], 19 | "intro": { 20 | "text": "intro.md" 21 | }, 22 | "finish": { 23 | "text": "finish.md" 24 | } 25 | }, 26 | "environment": { 27 | "uilayout": "terminal" 28 | }, 29 | "backend": { 30 | "imageid": "docker-swarm" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /training/training-example-pathway.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Training Pathway Example", 3 | "description": "When using Katacoda for Trainers, the pathway defines the course for attendees", 4 | "courses": [ 5 | { 6 | "pathway_id": "istio", 7 | "id": "workshop/deploying-istio", 8 | "course_id": "deploying-istio", 9 | "title": "Deploying Istio to Kubernetes", 10 | "description": "Learn how to deploy Istio to a Kubernetes cluster" 11 | }, 12 | { 13 | "pathway_id": "istio", 14 | "id": "connecting-controlling-microservices/traffic-shaping", 15 | "course_id": "traffic-shaping", 16 | "title": "Connecting & Controlling: Traffic Shaping Microservices Connections", 17 | "description": "Learn Load Balancing, Routes, Rules with Istio" 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /uilayouts/uilayout-editor-terminal/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "noindex": true, 3 | "title": "Scenario with Editor Terminal UI", 4 | "description": "Katacoda Scenario Example", 5 | "details": { 6 | "steps": [ 7 | { 8 | "text": "step1.md", 9 | "code": "setup.sh" 10 | } 11 | ], 12 | "intro": { 13 | "text": "intro.md", 14 | "credits": "" 15 | } 16 | }, 17 | "files": [ 18 | "app.js", "index.js" 19 | ], 20 | "environment": { 21 | "hidefinish": true, 22 | "hideHiddenFiles": true, 23 | "uilayout": "editor-terminal", 24 | "uisettings": "javascript", 25 | "uieditorpath": "/root/example" 26 | }, 27 | "backend": { 28 | "imageid": "nodejs:12" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /verified-steps/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Verifying user actions during scenario", 3 | "description": "Run checks to make sure the user can proceed. Scenario also offers user solutions if they struggle", 4 | "noindex": true, 5 | "details": { 6 | "steps": [ 7 | { 8 | "title": "Verify", 9 | "text": "step1.md", 10 | "verify": "step1-verify.sh" 11 | }, 12 | { 13 | "title": "Show Answers", 14 | "text": "step2.md", 15 | "solutionText": "step2-answer.md" 16 | } 17 | ] 18 | }, 19 | "environment": { 20 | "hideintro": true, 21 | "hidefinish": true, 22 | "uilayout": "terminal" 23 | }, 24 | "backend": { 25 | "imageid": "git" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /challenges/challenge-hello-world/1_hint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # See hint documentation: https://www.katacoda.community/challenges.html#hints 4 | 5 | seconds_sofar=$1 6 | 7 | # echo "Debug Hint Task 1: $seconds_sofar" 8 | 9 | # This hint message will appear between 10-20 seconds elapsed after the task began 10 | if [[ $seconds_sofar -ge 10 && $seconds_sofar -lt 20 ]]; then 11 | echo "Still working on it? I'll show a hint very soon..." 12 | fi 13 | 14 | # This hint message will appear 20+ seconds elapsed after the task began 15 | if [ $seconds_sofar -ge 20 ]; then 16 | echo "**Hint:** Normally, this hint would give help nudge you toward the solution. (As it is, I'm just going to tell you the answer, in case you're new to the command line. The simplest way to create a new file is the command 'touch'. Try typing 'touch bananas.txt' and then hit enter.)" 17 | fi 18 | -------------------------------------------------------------------------------- /visualise-docker/step1.md: -------------------------------------------------------------------------------- 1 | Katacoda has integrated [Weave Scope](https://weave.works/scope) to help visualise Docker and Kubernetes based deployments. 2 | 3 | The aim of integrating Scope is to help people understand what has been deployed and as changes new aspects are deployed to automatically see the impact. 4 | 5 | To launch Scope, click the Tab. 6 | 7 | ## Index.json 8 | 9 | To add the visualise tab to your scenarios, include the following JSON snippet within the environments node. This will automatically add the tab to the scenarios. When the tab is pressed, the command to launch the Scope container will run. 10 | 11 |
12 | "showvisualise": true,
13 | "scope": "docker run --name=scope -d --net=host --pid=host --privileged -v /var/run/docker.sock:/var/run/docker.sock:rw weaveworks/scope:1.9.1 --probe.docker=true",
14 | "scopePort": 4040,
15 | 
16 | -------------------------------------------------------------------------------- /vscode-extensions/step1.md: -------------------------------------------------------------------------------- 1 | To install a VSCode extension execute the following in a background script: 2 | 3 | The use of bsdtar is required due to the packaging format of VS Extensions. 4 | 5 | ```sh 6 | echo 'debconf debconf/frontend select Noninteractive' | sudo debconf-set-selections 7 | cd /tmp && apt-get update -y && apt install libarchive-tools -y # install bsdtar 8 | curl -L https://marketplace.visualstudio.com/_apis/public/gallery/publishers/humao/vsextensions/rest-client/0.24.3/vspackage | bsdtar -xvf - extension 9 | mv extension /opt/.katacodacode/extensions/humao.rest-client-0.24.3 10 | ``` 11 | 12 | The name of the directory for the extension should use the same pattern that when the extension is installed manually `.-`. 13 | 14 | See the [source code](https://github.com/katacoda/scenario-examples/tree/main/vscode-extensions) of this example. 15 | -------------------------------------------------------------------------------- /displaying-progress-spinner/step1.md: -------------------------------------------------------------------------------- 1 | In this scenario, a long-running task has been started in the background. 2 | 3 | To display feedback to the user, a wait script is run in the foreground. The wait script was uploaded as an Asset to Katacoda. 4 | 5 | The purpose of the wait script is to wait for certain files to be created. These files are created at certain points within the background script to indicate certain actions have been completed. After 10 seconds, you should see the progress change. 6 | 7 | The result is the user knows that actions are being performed and won't attempt to use the scenario until the environment is ready. 8 | 9 | The following will output the wait script in a second terminal. 10 | `cat /usr/local/bin/wait.sh`{{execute T2}} 11 | 12 | The full script can be found on Github at https://github.com/katacoda/scenario-examples/tree/master/displaying-progress-spinner 13 | -------------------------------------------------------------------------------- /displaying-progress-spinner/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "noindex": true, 3 | "title": "Displaying Progress Spinner", 4 | "description": "Display a friendly spinner while long running jobs are completed", 5 | "details": { 6 | "intro": { 7 | "courseData": "background.sh", 8 | "code": "foreground.sh", 9 | "text": "intro.md" 10 | }, 11 | "steps": [ 12 | { 13 | "title": "Waiting Spinner Example", 14 | "text": "step1.md" 15 | } 16 | ], 17 | "assets": { 18 | "host01": [ 19 | {"file": "wait.sh", "target": "/usr/local/bin/", "chmod": "+x"} 20 | ] 21 | } 22 | }, 23 | "files": [], 24 | "environment": { 25 | "uilayout": "terminal" 26 | }, 27 | "backend": { 28 | "imageid": "ubuntu" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /challenges/challenge-linux-solver/assets/solutions.sh.md: -------------------------------------------------------------------------------- 1 | # Encryption Instructions 2 | 3 | The assets/solutions.sh has been encrypted to `assets/solutions.sh.enc` with the passcode: 4 | 5 | `BMXI8P7F20N7Q4XW` 6 | 7 | The passcode is written to `assets/solutions.sh.md` and should be stored in version control. This passcode is for authors and other testers and should never be revealed to learners. Never copy `solutions.sh.md` or the key as an asset to the Challenge. When in the Challenge, asan author or tester, refer to this key to install the solutions file with `solver solutions --decrypt `. Manual decryption can be done with `openssl enc -aes-128-ecb -d -in /opt/solutions.sh.enc -out /usr/local/bin/solutions.sh -K $(echo -n BMXI8P7F20N7Q4XW | hexdump -ve '1/1 "%.2x"')`When the `/usr/local/bin/solutions.sh` script is decrypted the solver testing commands`next`, `all`, and `until` will help solve each Challenge task. -------------------------------------------------------------------------------- /upload-assets/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "noindex": true, 3 | "title": "Upload File Assets", 4 | "description": "Automatically upload file assets to the environment", 5 | "details": { 6 | "steps": [ 7 | { 8 | "title": "Upload Assets", 9 | "text": "step1.md", 10 | "courseData": "background.sh", 11 | "code": "foreground.sh" 12 | } 13 | ], 14 | "assets": { 15 | "host01": [ 16 | {"file": "wait.sh", "target": "/usr/local/bin/", "chmod": "+x"}, 17 | {"file": "deploy.sh", "target": "/usr/local/bin/", "chmod": "+x"} 18 | ] 19 | } 20 | }, 21 | "environment": { 22 | "hideintro": true, "hidefinish": true, 23 | "uilayout": "terminal" 24 | }, 25 | "backend": { 26 | "imageid": "ubuntu" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /challenges/challenge-linux-solver/finish.md: -------------------------------------------------------------------------------- 1 | Well done! Clearly, you have mastered the basic commands of `Linux`. 2 | 3 | With these challenging tasks you have learned how to: 4 | 5 |     🏅 Install a Linux command line tool 6 |     🏅 Format some output 7 |     🏅 Counts words in a PDF 8 |     🏅 Show your mastery of xargs 9 | 10 | ## References 📚 11 | 12 | - [Learning Modern Linux](https://learning.oreilly.com/library/view/learning-modern-linux/9781098108939/) 13 | - [Cowsay](https://github.com/tnalpgge/rank-amateur-cowsay) 14 | - [Linux Column](https://man7.org/linux/man-pages/man1/column.1.html) 15 | - [Linux xargs](https://learning.oreilly.com/library/view/how-linux-works/9781098128913/c11.xhtml) 16 | - [Linux First Steps (video)](https://learning.oreilly.com/attend/linux-systems-first-steps/0636920409205/0636920066553/) 17 | -------------------------------------------------------------------------------- /challenges/challenge-linux-solver/readme.md: -------------------------------------------------------------------------------- 1 | # An Example Challenge 2 | 3 | This challenge walks a learner through a few simple Linux challenges. 4 | 5 | ## About Challenges 6 | 7 | This is an example [challenge](https://www.katacoda.community/challenges/challenges.html) that shows to integrate the _solver_ tool. The _solver_ tool helps authors create high-quality challenges. 8 | 9 | The usage of _solver_ for O'Reilly challenge authors is detailed in the [Katacoda Documentation](https://www.katacoda.community/challenges/challenges-solver.html). 10 | 11 | ## About This Challenge 12 | 13 | This is an example challenge that helps authors see how to create a complete challenge that utilizes the _solver_ tool. This can be used as a skeleton archetype to create your own challenge. 14 | 15 | (If you are adopting this challenge as a canonical example, then add information here in this README about your challenge.) 16 | -------------------------------------------------------------------------------- /run-commands-automatically/step3.md: -------------------------------------------------------------------------------- 1 | When the background script is running, sometimes it's required that the user is blocked until the script finishes. 2 | 3 | In this case, using files as notifications can be useful. 4 | 5 | For example, the following is a background script that is running: 6 | 7 |
 8 | #!/bin/bash
 9 | 
10 | echo "This is a background script with a long running process"
11 | 
12 | sleep 10
13 | 
14 | echo "done" >> /opt/.backgroundfinished
15 | 
16 | 
17 | 18 | The foreground script waits for the file to be created. After the file exists, the while loop finishes and the user is allowed to access the terminal. 19 | 20 |
21 | echo "Waiting to complete"; while [ ! -f /opt/.backgroundfinished ] ; do sleep 2; done; echo "Done"
22 | 
23 | 24 | This can be improved by displaying a Progress Spinner to the user as described in an additional scenario. 25 | -------------------------------------------------------------------------------- /challenges/challenge-linux-solver/task_3.md: -------------------------------------------------------------------------------- 1 | There is a famous play and 1951 film _A Streetcar Named Desire_ by Tennessee Williams. It has a famous line, "Hey Stella!". Stella Kowalski is one of the main characters in the play. [Marlon Brando said her name the best](https://www.youtube.com/watch?v=S1A0p0F_iH8). Search the play's manuscript to see how many times her name is spoken with and without a passionate exclamation point. Create a property file called `stella.properties` and place the word counts for each of these keys: 2 | 3 | ```properties 4 | stella=? 5 | stella_exclamation=? 6 | ``` 7 | 8 | In the current directory, there is a file `streetcar.pdf`. Using [pdftotext](https://ubuntu.pkgs.org/20.04/ubuntu-main-arm64/poppler-utils_0.86.1-0ubuntu1_arm64.deb.html), you'll need to convert this `streetcar.pdf` to `streetcar.txt` to count the words. 9 | 10 | 💡 Consider that water closets are no places to count words. 11 | -------------------------------------------------------------------------------- /course-data-host01-reference/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Background script with explicit reference to host01", 3 | "difficulty": "beginner", 4 | "time": "10 minutes", 5 | "details": { 6 | "assets": { 7 | "host01": [ 8 | { 9 | "file": "wait-script.sh", 10 | "target": "/tmp/" 11 | }, 12 | { 13 | "file": "dummy.json", 14 | "target": "/root" 15 | } 16 | ] 17 | }, 18 | "steps": [ 19 | { 20 | "title": "Commands", 21 | "text": "step1.md" 22 | } 23 | ], 24 | "intro": { 25 | "text": "intro.md", 26 | "code": "set-env.sh", 27 | "courseData": "init-env.sh" 28 | } 29 | }, 30 | "environment": { 31 | "uilayout": "terminal", 32 | "hidefinish": true, 33 | "hideintro": true 34 | }, 35 | "backend": { 36 | "imageid": "kubernetes-cluster-running:1.18" 37 | } 38 | } -------------------------------------------------------------------------------- /challenges/kubernetes-challenge-1/.cypress/k8s_spec.js: -------------------------------------------------------------------------------- 1 | describe('Kubernetes Challenge', () => { 2 | before(() => { 3 | cy.startScenario() 4 | }); 5 | 6 | it('starts on Task 1', () => { 7 | cy.terminalShouldContain('Task 1'); 8 | cy.terminalNotShouldContain('Task 2'); 9 | }); 10 | 11 | it('can complete challenge 1', () => { 12 | cy.viewport(2560, 1600) 13 | 14 | cy.terminalShouldContain('Task 1'); 15 | 16 | cy.terminalNotShouldContain('Task 2'); 17 | 18 | cy.terminalType('curl "node01:30080?cmd=env" > /root/app-env'); 19 | 20 | cy.terminalShouldContain('Task 2'); 21 | 22 | }); 23 | 24 | it('can complete challenge 2', () => { 25 | cy.viewport(2560, 1600) 26 | 27 | cy.terminalShouldContain('Task 2'); 28 | 29 | cy.terminalType('curl "node01:30080?cmd=cat%20app.js" > /root/app.js'); 30 | 31 | cy.terminalShouldContain('Completed Challenge'); 32 | 33 | }); 34 | }) -------------------------------------------------------------------------------- /challenges/node-challenge-1/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "challenge@0.8", 3 | "title": "Challenge Example - Node.js", 4 | "description": "", 5 | "difficulty": "Beginner", 6 | "time": "60 minutes", 7 | "details": { 8 | "steps": [ 9 | { 10 | "title": "Fix Tests", 11 | "text": "1_task.md", 12 | "verify": "1_verify.sh" 13 | } 14 | ], 15 | "intro": { 16 | "text": "intro.md", 17 | "background": "background.sh" 18 | }, 19 | "finish": { 20 | "text": "finish.md" 21 | }, 22 | "assets": { 23 | "client": [ 24 | { 25 | "file": "cheat", 26 | "target": "/usr/local/bin/", 27 | "chmod": "+x" 28 | } 29 | ] 30 | } 31 | }, 32 | "environment": { 33 | "hidesidebar": true, 34 | "uilayout": "vscode-terminal-split" 35 | }, 36 | "backend": { 37 | "imageid": "nodejs:12" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /create-course/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Creating a Katacoda Course", 3 | "description": "Learn how to create a collection of Katacoda scenarios into a course", 4 | "details": { 5 | "steps": [ 6 | { 7 | "title": "Pathway Files", 8 | "text": "step1.md" 9 | }, 10 | { 11 | "title": "Reusing Scenarios", 12 | "text": "step2.md" 13 | }, 14 | { 15 | "title": "Using katacoda CLI to create a course", 16 | "text": "step3.md" 17 | }, 18 | { 19 | "title": "Using katacoda CLI to add existing scenarios to a course", 20 | "text": "step4.md" 21 | } 22 | ], 23 | "intro": { 24 | "text": "intro.md" 25 | }, 26 | "finish": { 27 | "text": "finish.md" 28 | } 29 | }, 30 | "environment": { 31 | "uilayout": "editor-terminal" 32 | }, 33 | "backend": { 34 | "imageid": "nodejs:12" 35 | } 36 | } -------------------------------------------------------------------------------- /verified-steps/step1.md: -------------------------------------------------------------------------------- 1 | Ensuring that users have successfully completed certain actions before the proceed can be a useful technique to ensure that are paying attention and they won't hit problems later on in the scenario. 2 | 3 | When the user clicks Continue, a script is run against the environment. 4 | 5 | For the user to be allowed to proceed, the script should output the text "done". For example, the following verify script checks to make sure the user has run `git init`{{execute}} before they can proceed. 6 | 7 |
 8 | [ -d /home/scrapbook/tutorial/.git ] && echo "done"
 9 | 
10 | 11 | If you run `git init`{{execute}}, you will be allowed to continue. 12 | 13 | The `index.json` example is: 14 |
15 | "details": {
16 |     "steps": [
17 |         {
18 |             "title": "Verify",
19 |             "text": "step1.md",
20 |             "verify": "step1-verify.sh"
21 |         }
22 |     ]
23 | }
24 | 
25 | -------------------------------------------------------------------------------- /dashboard-tabs-iframe/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "noindex": true, 3 | "title": "Dashboard and Terminal Tabs (iframe)", 4 | "description": "Add Additional Tabs to the UI with iframe integration", 5 | "details": { 6 | "steps": [ 7 | { 8 | "title": "Tab Types", 9 | "text": "step1.md" 10 | } 11 | ] 12 | }, 13 | "environment": { 14 | "showide": true, 15 | "hideintro": true, 16 | "showdashboard": true, 17 | "dashboards": [ 18 | {"name": "URL", "href": "https://www.katacoda.com"}, 19 | {"name": "Port 80", "port": 80}, 20 | {"name": "Placeholder", "href": "https://[[HOST_SUBDOMAIN]]-8080-[[KATACODA_HOST]].environments.katacoda.com/somepage", "port": 8080}], 21 | "uilayout": "terminal-iframe" 22 | }, 23 | "backend": { 24 | "imageid": "ubuntu", 25 | "port": 80 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /challenges-pathway.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Challenges Examples", 3 | "description": "Examples of how to create Challenges on Katacoda", 4 | "courses": [{ 5 | "course_id": "challenge-hello-world", 6 | "title": "Challenge Template", 7 | "description": "Basic template for a challenge" 8 | }, 9 | { 10 | "course_id": "node-challenge-1", 11 | "title": "Challenge Example - Node.js", 12 | "description": "How to create a challenge on using Node.js" 13 | }, 14 | { 15 | "course_id": "kubernetes-challenge-1", 16 | "title": "Challenge Example - Kubernetes", 17 | "description": "How to create a challenge on using Kubernetes" 18 | }, 19 | { 20 | "course_id": "challenge-linux-solver", 21 | "title": "Challenge Example - Linux Challenge Using the Solver Utility", 22 | "description": "An example challenge showing authors how to use the solver features" 23 | } 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /create-scenario-101/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Creating Your First Katacoda Scenario", 3 | "description": "Learn how to create your first Katacoda scenario", 4 | "details": { 5 | "steps": [ 6 | { 7 | "title": "Scenario Structure", 8 | "text": "step1.md" 9 | }, 10 | { 11 | "title": "Scenario Syntax", 12 | "text": "step2.md" 13 | }, 14 | { 15 | "title": "CLI", 16 | "text": "step3.md" 17 | }, 18 | { 19 | "title": "Visual Studio Code Extension", 20 | "text": "step4.md" 21 | }, 22 | { 23 | "title": "Webhooks", 24 | "text": "step5.md" 25 | } 26 | ], 27 | "intro": { 28 | "text": "intro.md" 29 | }, 30 | "finish": { 31 | "text": "finish.md" 32 | } 33 | }, 34 | "environment": { 35 | "uilayout": "editor-terminal" 36 | }, 37 | "backend": { 38 | "imageid": "nodejs:12" 39 | } 40 | } -------------------------------------------------------------------------------- /upload-assets/step1.md: -------------------------------------------------------------------------------- 1 | Katacoda supports automatically uploading assets to scenarios. This is designed for configuration and short scripts. 2 | 3 | The options are: 4 | 5 | 1) `file`: The name of the file within the Assets directory. 6 | 7 | 2) `target`: The directory where the file should be uploaded to. 8 | 9 | 3) `chmod`: Optional, automatically set a chmod flag after uploading the file. 10 | 11 | The following is an example from the `index.json`. 12 | 13 |
14 | "details": {
15 |     "assets": {
16 |         "host01": [
17 |             {"file": "wait.sh", "target": "/usr/local/bin/", "chmod": "+x"},
18 |             {"file": "deploy.sh", "target": "/usr/local/bin/", "chmod": "+x"}
19 |         ]
20 |     }
21 | },
22 | 
23 | 24 | View the uploaded files: 25 | 26 | `cat /usr/local/bin/wait.sh`{{execute}} 27 | 28 | `cat /usr/local/bin/deploy.sh`{{execute}} 29 | 30 | **Note:** There is currently a file limit of 1mb. If the file is greater than 1mb, for performance, we recommend using a CDN and using cURL to download the file. 31 | -------------------------------------------------------------------------------- /custom-events/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "custom-events", 3 | "title": "Raise Custom Events From Environments", 4 | "description": "Raise events from the user environment to Katacoda", 5 | "details": { 6 | "intro": { 7 | "text": "intro.md", 8 | "code": "env-init.sh", 9 | "credits": "" 10 | }, 11 | "steps": [ 12 | { 13 | "title": "Custom events", 14 | "text": "step1.md" 15 | } 16 | ] 17 | }, 18 | "asyncFiles": ["index.html"], 19 | "environment": { 20 | "hidefinish": true, 21 | "showdashboard": true, 22 | "delayToSaveFileAfterStopTypingMilliseconds": 2000, 23 | "dashboards": [ 24 | {"name": "Web Application", "port": 3000} 25 | ], 26 | "uilayout": "editor-iframe-split", 27 | "uisettings": "html" 28 | }, 29 | "backend": { 30 | "imageid": "nodejs:12", 31 | "port": 3000 32 | }, 33 | "events": { 34 | "hideprogressbar": "reload-finished" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /clipboard/step1.md: -------------------------------------------------------------------------------- 1 | This is an example of Katacoda's clipboard integration. 2 | 3 | The following will copy the text into the clipboard. This is useful if users need to interact with a web interface. 4 | 5 | `docker`{{copy}} 6 | 7 | Within the Markdown step, you would write: 8 |
 9 | `docker`{{copy}}
10 | 
11 | 12 | Katacoda supports copying code snippets or longer text into the clipboard by adding the attribute `data-target`. 13 | 14 |
15 | Copy Me To The Clipboard!!
16 | 
17 | 18 | This is created by embedded HTML into the Markdown. 19 | 20 |
21 | <pre class="file" data-target="clipboard">
22 | Copy Me To The Clipboard!!
23 | </pre>
24 | 
25 | 26 | **Note** Without the class="file" it will not display the clipboard functionality. For example: 27 | 28 |
29 | Not a file
30 | 
31 | 32 | This was created by the HTML: 33 | 34 |
35 | <pre data-target="clipboard">
36 | Not a file
37 | </pre>
38 | 
39 | -------------------------------------------------------------------------------- /upload-assets/assets/wait.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | show_progress() 4 | { 5 | echo -n "Starting" 6 | local -r pid="${1}" 7 | local -r delay='0.75' 8 | local spinstr='\|/-' 9 | local temp 10 | while true; do 11 | sudo grep -i "done" /root/katacoda-finished &> /dev/null 12 | if [[ "$?" -ne 0 ]]; then 13 | temp="${spinstr#?}" 14 | printf " [%c] " "${spinstr}" 15 | spinstr=${temp}${spinstr%"${temp}"} 16 | sleep "${delay}" 17 | printf "\b\b\b\b\b\b" 18 | else 19 | break 20 | fi 21 | done 22 | printf " \b\b\b\b" 23 | echo "" 24 | echo "Started" 25 | echo -n "Configuring" 26 | while true; do 27 | sudo grep -i "done" /root/katacoda-background-finished &> /dev/null 28 | if [[ "$?" -ne 0 ]]; then 29 | temp="${spinstr#?}" 30 | printf " [%c] " "${spinstr}" 31 | spinstr=${temp}${spinstr%"${temp}"} 32 | sleep "${delay}" 33 | printf "\b\b\b\b\b\b" 34 | else 35 | break 36 | fi 37 | done 38 | printf " \b\b\b\b" 39 | echo "" 40 | echo "Configured" 41 | } 42 | 43 | show_progress -------------------------------------------------------------------------------- /displaying-progress-spinner/assets/wait.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | show_progress() 4 | { 5 | echo -n "Starting" 6 | local -r pid="${1}" 7 | local -r delay='0.75' 8 | local spinstr='\|/-' 9 | local temp 10 | while true; do 11 | sudo grep -i "done" /root/katacoda-finished &> /dev/null 12 | if [[ "$?" -ne 0 ]]; then 13 | temp="${spinstr#?}" 14 | printf " [%c] " "${spinstr}" 15 | spinstr=${temp}${spinstr%"${temp}"} 16 | sleep "${delay}" 17 | printf "\b\b\b\b\b\b" 18 | else 19 | break 20 | fi 21 | done 22 | printf " \b\b\b\b" 23 | echo "" 24 | echo "Started" 25 | echo -n "Configuring" 26 | while true; do 27 | sudo grep -i "done" /root/katacoda-background-finished &> /dev/null 28 | if [[ "$?" -ne 0 ]]; then 29 | temp="${spinstr#?}" 30 | printf " [%c] " "${spinstr}" 31 | spinstr=${temp}${spinstr%"${temp}"} 32 | sleep "${delay}" 33 | printf "\b\b\b\b\b\b" 34 | else 35 | break 36 | fi 37 | done 38 | printf " \b\b\b\b" 39 | echo "" 40 | echo "Configured" 41 | } 42 | 43 | show_progress -------------------------------------------------------------------------------- /create-course/step4.md: -------------------------------------------------------------------------------- 1 | The CLI can be used to add existing scenarios to a course. 2 | 3 | You can list your available scenarios, using this command: 4 | 5 | `find ./ -type f | grep index.json`{{execute}} 6 | 7 | For example, can add the existing scenario, called *quiz* to the previous created course *test-course* running the following command and follow the steps: 8 | 9 | `katacoda courses:add:scenarios`{{execute}} 10 | 11 | The CLI will prompt you a few questions about: 12 | 13 | - Scenario path: type `./quiz` 14 | - Course path: type `./test-course` 15 | 16 | And then select if you want to copy or move the scenario to the course folder. 17 | 18 | After that, you can see the scenario was added in your `test-course` opening `katacoda-scenario-examples/test-course-pathway.json`{{open}} 19 | 20 |
21 | {
22 |   "title": "test-course",
23 |   "description": "Example course",
24 |   "courses": [
25 |     {
26 |       "course_id": "quiz",
27 |       "title": "Interactive Quiz",
28 |       "description": "Verify understand and key points by using an interactive quiz"
29 |     }
30 |   ]
31 | 
32 | -------------------------------------------------------------------------------- /dashboard-tabs/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "noindex": true, 3 | "title": "Dashboard and Terminal Tabs", 4 | "description": "Add Additional Tabs to the UI", 5 | "details": { 6 | "steps": [ 7 | { 8 | "title": "Dashboard Tabs", 9 | "text": "step1.md" 10 | }, 11 | { 12 | "title": "Terminal Tabs", 13 | "text": "step2.md" 14 | } 15 | ] 16 | }, 17 | "environment": { 18 | "hideintro": true, 19 | "showdashboard": true, 20 | "dashboards": [{"name": "Port 80", "port": 80}, 21 | {"name": "URL", "href": "https://www.google.co.uk"}, 22 | {"name": "Placeholder", "href": "https://[[HOST_SUBDOMAIN]]-80-[[KATACODA_HOST]].environments.katacoda.com"}], 23 | "terminals": [ 24 | {"name": "Terminal 2", "target": "host01"}, 25 | {"name": "Docker Stats", "command": "docker stats", "target": "host01"} 26 | ], 27 | "uilayout": "terminal" 28 | }, 29 | "backend": { 30 | "imageid": "ubuntu", 31 | "port": 80 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /dashboard-tabs-iframe/step1.md: -------------------------------------------------------------------------------- 1 | By default the Dashboard Tabs will open in a new window. When combined with the layout `terminal-iframe`, the Dashboard tabs can be embedded as an iframe. 2 | 3 | This allows the user to keep a consistent view and allow the steps to explain actions that need to be performed within the UI. 4 | 5 |
 6 | "environment": {
 7 |     "showdashboard": true,
 8 |     "dashboards": [{"name": "URL", "href": "https://www.katacoda.com"},
 9 |         {"name": "Port 80", "port": 80},
10 |         {"name": "Placeholder", "href": "https://[[HOST_SUBDOMAIN]]-80-[[KATACODA_HOST]].environments.katacoda.com"}],
11 |     "uilayout": "terminal-iframe"
12 | }
13 | 
14 | 15 | ## Switching User Context 16 | 17 | If the URL matches the iframe then links will automatically switch the user to the correct tab when they are selected, such as https://www.katacoda.com and https://[[HOST_SUBDOMAIN]]-8080-[[KATACODA_HOST]].environments.katacoda.com 18 | 19 | **Note:** This approach uses iframes, as such, websites such as Google.co.uk will not load due to Browser Security and Google's iframe configuration. Look in your browser's console to view the errors. 20 | -------------------------------------------------------------------------------- /challenges/kubernetes-challenge-1/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "challenge@0.8", 3 | "title": "Challenge Example - Kubernetes", 4 | "description": "", 5 | "difficulty": "Advance", 6 | "time": "60 minutes", 7 | "details": { 8 | "steps": [ 9 | { 10 | "title": "Output env", 11 | "text": "1_task.md", 12 | "verify": "1_verify.sh", 13 | "hint": "1_hint.sh" 14 | }, 15 | { 16 | "title": "Extract app.js", 17 | "text": "2_task.md", 18 | "verify": "2_verify.sh" 19 | } 20 | ], 21 | "intro": { 22 | "text": "intro.md", 23 | "code": "foreground.sh", 24 | "courseData": "configure.sh" 25 | }, 26 | "assets": { 27 | "host01": [ 28 | {"file": "cheat", "target": "/usr/local/bin/", "chmod": "+x"}, 29 | {"file": "cheat2", "target": "/usr/local/bin/", "chmod": "+x"}, 30 | {"file": "deploy.yaml", "target": "/opt/"} 31 | ] 32 | } 33 | }, 34 | "environment": { 35 | "uilayout": "terminal", 36 | "showide": true, 37 | "hidesidebar": true 38 | }, 39 | "backend": { 40 | "imageid": "kubernetes-cluster-running:1.18" 41 | } 42 | } -------------------------------------------------------------------------------- /challenges/challenge-hello-world/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "challenge@0.8", 3 | "title": "Challenge Template", 4 | "description": "Basic template for a challenge", 5 | "difficulty": "Beginner", 6 | "time": "5 minutes", 7 | "details": { 8 | "steps": [ 9 | { 10 | "title": "Bananas", 11 | "text": "1_task.md", 12 | "verify": "1_verify.sh", 13 | "hint": "1_hint.sh" 14 | }, 15 | { 16 | "title": "Apples", 17 | "text": "2_task.md", 18 | "verify": "2_verify.sh", 19 | "hint": "2_hint.sh" 20 | } 21 | ], 22 | "intro": { 23 | "text": "intro.md" 24 | }, 25 | "finish": { 26 | "text": "finish.md" 27 | }, 28 | "assets": { 29 | "client": [ 30 | { "file": "*", "target": "~/" } 31 | ] 32 | } 33 | }, 34 | "environment": { 35 | "uilayout": "editor-terminal", 36 | "hideHiddenFiles": true 37 | }, 38 | "backend": { 39 | "imageid": "ubuntu:2004" 40 | } 41 | } -------------------------------------------------------------------------------- /exclusion-patterns/step1.md: -------------------------------------------------------------------------------- 1 | Let's create a script that adds a new test folder and creates a file every 1 second. Also this script register the message in a log file. 2 | 3 |
 4 | rm -rf test/
 5 | mkdir test/
 6 | for i in $(seq 1 50000);
 7 | do
 8 |    echo "Welcome $i times" >> logs
 9 |    touch test/$i.cache
10 |    sleep 1
11 | done
12 | 
13 | 14 | Add execution permissions to the script 15 | `chmod +x ./poc.sh`{{execute}} 16 | 17 | Execute the script 18 | `./poc.sh`{{execute}} 19 | 20 | If we see, the numbers of files in the test directory are increasing every 1 second, but, in the editor, we don't see those files. 21 | `watch ls -la ./test`{{execute T2}} 22 | 23 | This is accomplished using the property `exclusionPatterns` in the definition of the scenario `index.json`. 24 | 25 |
26 |   "environment": {
27 |       ...
28 |       "exclusionPatterns": ["*test", "./test/*", "./logs"]
29 |   }
30 | 
31 | 32 | Also, we can exclude the hidden files, setting the property `hideHiddenFiles` in true 33 | 34 |
35 |   "environment": {
36 |       ...
37 |       "hideHiddenFiles": true,
38 |   }
39 | 
40 | -------------------------------------------------------------------------------- /create-course/step1.md: -------------------------------------------------------------------------------- 1 | A Katacoda course is defined by creating a pathway file. The pathway defines which scenarios should be included in the course and the order to display them. 2 | 3 | The collection of examples contains two courses, one to describe all the Katacoda content and another to describe the key Katacoda environments. 4 | 5 | ## Clone Example 6 | 7 | Clone the example repository with the command `git clone https://github.com/katacoda/scenario-examples.git katacoda-scenario-examples`{{execute}} 8 | 9 | Within the root of a repository, a course has been created called `uilayouts`. The contents of the course have been defined as `katacoda-scenario-examples/uilayouts-pathway.json`{{open}}. 10 | 11 | Within the JSON file, the courses element defines each scenario. For example: 12 | 13 |
14 | {
15 |     "course_id": "uilayout-terminal",
16 |     "title": "Scenario with Terminal UI",
17 |     "description": "Katacoda Scenario Example"
18 | },
19 | 
20 | 21 | The **course_id** is the scenario name directory within the course directory. For example `ls katacoda-scenario-examples/uilayouts/uilayout-terminal`{{execute}}. The **title** and **description** are shown on the course page. 22 | -------------------------------------------------------------------------------- /automatedtest/.cypress/example_spec.js: -------------------------------------------------------------------------------- 1 | describe('My First Test', () => { 2 | before(() => { 3 | cy.startScenario() // This would automatically go to the scenario being tested. Without this the test will fail. 4 | }); 5 | 6 | it('finds the "Start Scenario" button', () => { 7 | cy.contains('Start Scenario'); 8 | }); 9 | 10 | it('can run a command', () => { 11 | cy.terminalType("uptime"); 12 | 13 | cy.terminalShouldContain('load average'); 14 | }); 15 | 16 | it('can verify contents of a step', () => { 17 | cy.stepShouldBeVisible(1); 18 | 19 | cy.stepHasText("This is an example scenario that will be tested using the Cypress integration"); 20 | }); 21 | 22 | it('can go to the next step and verify contents', () => { 23 | cy.goToStep(2); 24 | 25 | cy.stepShouldBeVisible(2); 26 | 27 | cy.stepHasText('This will be the second step.'); 28 | }); 29 | 30 | it('can run execute snippets based on name', () => { 31 | // TODO: The goToStep should be able to ignore being asked to move to the same step. At the moment this test depends on the above. 32 | // cy.goToStep(2); 33 | 34 | cy.get('code.execute.test-uname').click(); 35 | 36 | cy.terminalShouldContain('Linux'); 37 | }); 38 | }) -------------------------------------------------------------------------------- /challenges/challenge-linux-solver/assets/solutions.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script is called by the solver script. Each function should be named solve_task_#, 4 | # where # is the number of the task each function will solve. The calling solver will call 5 | # the corresponding verify_task_# function after each solver_task_# function completes. 6 | 7 | function solve_task_1() { 8 | yes | sudo apt update 9 | yes | sudo apt-get install cowsay 10 | cowsay "O'Reilly, inspiring the future for more than 40 years" > cowsay.txt 11 | } 12 | 13 | 14 | function solve_task_2() { 15 | cat /etc/passwd | column -t -s : > kinder-passwd.txt 16 | } 17 | 18 | 19 | function solve_task_3() { 20 | yes | sudo apt update 21 | yes | sudo apt-get install poppler-utils 22 | pdftotext streetcar.pdf streetcar.txt 23 | echo "stella=$(grep -c "Stella" streetcar.txt)" > stella.properties 24 | echo "stella_exclamation=$(grep -c "Stella!" streetcar.txt)" >> stella.properties 25 | } 26 | 27 | 28 | function solve_task_4() { 29 | echo -n "1 2 3 4 5" | xargs -d ' ' -i rm {} 30 | 31 | cat < my-xargs.sh 32 | #!/bin/bash 33 | echo -n '1 2 3 4 5' | xargs -d ' ' -i sh -c "touch {}.txt ; echo 'I am {}' > {}.txt" 34 | EOF 35 | 36 | chmod +x my-xargs.sh 37 | ./my-xargs.sh 38 | } 39 | -------------------------------------------------------------------------------- /run-commands-automatically/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "noindex": true, 3 | "title": "Run Commands Automatically", 4 | "description": "Automatically run commands in the foreground and background when a scenario starts", 5 | "details": { 6 | "steps": [ 7 | { 8 | "title": "Scripts On Intro Page", 9 | "text": "step1.md" 10 | }, 11 | { 12 | "title": "Scripts On Steps", 13 | "courseData": "step2-background.sh", 14 | "code": "step2-foreground.sh", 15 | "text": "step2.md" 16 | }, 17 | { 18 | "title": "Asynchronous and Sychronous Scripts", 19 | "courseData": "step3-background.sh", 20 | "code": "step3-foreground.sh", 21 | "text": "step3.md" 22 | } 23 | ], 24 | "intro": { 25 | "text": "intro.md", 26 | "courseData": "background.sh", 27 | "code": "foreground.sh", 28 | "credits": "" 29 | } 30 | }, 31 | "files": [], 32 | "environment": { 33 | "hidefinish": true, 34 | "uilayout": "terminal" 35 | }, 36 | "backend": { 37 | "imageid": "ubuntu" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /create-scenario-101/step1.md: -------------------------------------------------------------------------------- 1 | A Katacoda scenario is a series of Markdown files, bash scripts and a JSON file to define how your scenario should be configured, the text for the scenario and any automation required. 2 | 3 | ## Task 4 | 5 | Clone our example repository that contains the set of documentation with the following command: 6 | 7 | `git clone https://github.com/katacoda/scenario-examples.git katacoda-scenario-examples`{{execute}} 8 | 9 | Within the repository, you will see a set of examples of implementing various Katacoda functionality. 10 | 11 | The scenario you are currently reading is in the directory `ls -lha katacoda-scenario-examples/create-scenario-101`{{execute}}. The directory name is what defines the URL. 12 | 13 | An example of the current step is `katacoda-scenario-examples/create-scenario-101/step1.md`{{open}} 14 | 15 | All the steps are collected via a JSON file, for example, `katacoda-scenario-examples/create-scenario-101/index.json`{{open}}. 16 | 17 | The JSON file defines the scenario title, the description, steps order, the UI layout and environment. You can find more about the layouts within our scenarios at [Supported Layouts](https://www.katacoda.community/essentials/layouts.html) and environments at [Supported Environments](https://www.katacoda.community/essentials/environments.html). 18 | -------------------------------------------------------------------------------- /dashboard-tabs/step1.md: -------------------------------------------------------------------------------- 1 | Adding Dashboard tabs to a Katacoda scenario can improve the user experience by making commonly used websites, or ports, easily accessible. 2 | 3 | Katacoda supports three types of Dashboard tabs. 4 | 5 | 1) **Displaying External Webpages**. This is useful when you require a link to an external service such as a Cloud Dashboard or Documentation. 6 | 7 | 2) **Rendering Proxied Port**. When running a service on a Port within the Environment, Katacoda provides a dynamic URL for the session. This tab will automatically create the correct URL based on the Port you want to display. 8 | 9 | 3) **Rendering Proxied URL**. Similar to Approach 2, the href parameter supports the standard Katacoda placeholder values, allowing you to direct users to a particular page within the service, running within the Katacoda environment. 10 | 11 | The `index.json` used to create the scenarios is shown below. It is important to remember to set the "showdashboard" variable. 12 | 13 |
14 | "environment": {
15 |     "showdashboard": true,
16 |     "dashboards": [{"name": "URL", "href": "https://www.google.co.uk"},
17 |         {"name": "Port 80", "port": 80},
18 |         {"name": "Placeholder", "href": "https://[[HOST_SUBDOMAIN]]-80-[[KATACODA_HOST]].environments.katacoda.com"}]
19 | }
20 | 
21 | 22 | The next step describes how to create additional Terminal tabs. 23 | -------------------------------------------------------------------------------- /challenges/challenge-linux-solver/intro.md: -------------------------------------------------------------------------------- 1 | This challenge helps strengthen your understanding of the some basics of Linux commands. It assumes you are comfortable with basic Linux commands and know how to access the common help and documentation sources. 2 | 3 | In this challenge, you will use a basic Linux shell to complete the solutions for each task. 4 | 5 | ## Challenge 6 | 7 | In the following steps you will be asked to: 8 | 9 |     ☐ Install a Linux command line tool 10 |     ☐ Format some output 11 |     ☐ Counts words in a PDF 12 |     ☐ Show your mastery of xargs 13 | 14 | 15 | If you are unfamiliar with these concepts, [you may want to start with this documentation first](https://learning.oreilly.com/library/view/learning-modern-linux/9781098108939/). 16 | 17 | --- 18 | 19 | Your mission in this challenge, should you choose to accept it, is to complete the stated goals. This challenge presents a series of tasks as you successfully complete each goal. The scenario continuously inspects the state of your work to verify your solutions for each task. When the verification passes, you move forward. When the verification fails, be sure you understand the details of the step's goal(s) and try again. If you are really stuck, try revealing a hint. 20 | 21 | This challenge will self-destruct in 60 minutes. 🍀 **Good luck!** 🍀 22 | -------------------------------------------------------------------------------- /dashboard-tabs/step2.md: -------------------------------------------------------------------------------- 1 | Certain scenarios will require multiple terminal tabs to be running. These can be opened dynamically using the [Markdown Extensions](), but they can also be opened when the scenario starts. 2 | 3 | ## Terminal Tab 4 | 5 | The `index.json` supports the following syntax that allows you to define an additional terminal tab. 6 | 7 |
 8 | "environment": {
 9 |   "terminals": [{"name": "Terminal 2", "target": "host01"}]
10 | }
11 | 
12 | 13 | ## Automatically Run Commands 14 | 15 | These tabs can automatically run certain commands to help the user understand what is happening. The command below will open a new Terminal tab and automatically run `docker container stats` command. 16 | 17 |
18 | "environment": {
19 |   "terminals": [{"name": "Docker Stats", "command": "docker container stats", "target": "host01"}]
20 | }
21 | 
22 | 23 | The can be used for tasks such as watching an event stream, or viewing all the processes running on a system. The command can also run a shell script that perhaps you create and load as an asset. Define the command as a script when a terminal starts: 24 | 25 |
26 | "environment": {
27 |   "terminals": [{"name": "Docker Stats", "command": "scenario-setup-configuration", "target": "host01"}]
28 | }
29 | 
30 | 31 | Ensure the script is available in the path: 32 | 33 |
34 |     "assets": {
35 |       "host01": [
36 |         {"file": "scenario-setup-configuration.sh", "target": "/usr/local/bin", "chmod": "+x"}
37 |       ]
38 |     }
39 | 
40 | -------------------------------------------------------------------------------- /create-course/step3.md: -------------------------------------------------------------------------------- 1 | Katacoda has a command line interface that helps to create the required files of courses and scenarios, etc. 2 | 3 | You can install the CLI using the following command: 4 | 5 | `npm i katacoda-cli --global`{{execute}} 6 | 7 | The commands follow the syntax: 8 | 9 | `$ katacoda COMMAND` 10 | 11 | If you need help, to see the available commands, you can run: 12 | 13 | `katacoda --help`{{execute}} 14 | 15 | To create a course, for example, called *test-course*, you can run the following command and follow the steps: 16 | 17 | ```sh 18 | cd katacoda-scenario-examples 19 | katacoda courses:create 20 | ```{{execute}} 21 | 22 | The CLI will prompt you a few questions about: 23 | - **Title:** title of the course, displayed on the intro screen 24 | - **Description:** description of the course, displayed on the intro screen 25 | - **Friendly-url:** here you will type `test-course`. This attribute will determine the name of the folder of your course, and the URL to access it, so, should not contain spaces, should be lower case, etc. For example, if your username is *test-username* and your course was called *test-course* the URL to point the course in the platform will be https://katacoda.com/test-username/courses/test-course/ 26 | 27 | After that the CLI will create the pathway file and the folder. 28 | `ls test-course*`{{execute}} 29 | 30 | You can see the definition of the empty course in `katacoda-scenario-examples/test-course-pathway.json`{{open}} 31 | 32 |
33 | {
34 |   "title": "test-course",
35 |   "description": "Example course",
36 |   "courses": []
37 | }
38 | 
39 | -------------------------------------------------------------------------------- /delivering-training/creating-training-pathway-json/step1.md: -------------------------------------------------------------------------------- 1 | A training pathway follows the same structure as course pathway files that was discussed in the scenario [katacoda.com/scenario-examples/scenarios/create-course](https://katacoda.com/scenario-examples/scenarios/create-course). 2 | 3 | Clone the example repository with the command `git clone https://github.com/katacoda/scenario-examples.git katacoda-scenario-examples`{{execute}} 4 | 5 | Within the root of a repository the training pathway files need to be in a directory called training. The contents of the course has been defined as `katacoda-scenario-examples/training/training-example-pathway.json`{{open}}. 6 | 7 | Within the file, the training outlines the content that will be delivered. In this case, the scenario from the Istio workshop will be included. 8 | 9 |
10 | {
11 | "pathway_id": "istio",
12 | "id": "workshop/deploying-istio",
13 | "course_id": "deploying-istio",
14 | "title": "Deploying Istio to Kubernetes",
15 | "description": "Learn how to deploy Istio to a Kubernetes cluster"
16 | }
17 | 
18 | 19 | The **id** is the scenario id and any courses that it could be within, in this case, the course is called workshop. The **course_id** allows the ID to be overridden and the possibility to change the URL. 20 | 21 | When live, the training would appear under the profile at [katacoda.com/scenario-examples/training/training-example](https://katacoda.com/scenario-examples/training/training-example). 22 | 23 | When delivering the training, Katacoda for Trainers, offers a number of capabilities. Firstly, attendees would have guaranteed capacity, with the possibility of increased performance that last for the entire workshop. 24 | -------------------------------------------------------------------------------- /quiz/step1.md: -------------------------------------------------------------------------------- 1 | Katacoda supports inline interactive quiz elements that can be included as any step within the scenario. The Quiz format supports different question and answer styles. Users cannot proceed until they have answered all the questions correctly. 2 | 3 | ## Example Quiz 4 | 5 | Within Q1, users are required to enter the exact string. 6 | 7 | >>Q1: Enter the exact string test<< 8 | === test 9 | 10 | For Q2, the question requires user to enter a string containing a certain keyword. 11 | 12 | >>Q2: Enter the string containing test<< 13 | =~= test 14 | 15 | Q3 is multiple choice question, requiring users to select all the correct answers. 16 | 17 | >>Q3: Multiple Choice << 18 | [*] Correct 19 | [*] Correct 20 | [ ] Incorrect 21 | 22 | Q4 is a single choice where users must select the correct answer. 23 | 24 | >>Q4: Single Choice << 25 | (*) Correct 26 | ( ) Incorrect 27 | 28 | ## Markdown 29 | 30 | All of the above questions have been defined within markdown. There is no official syntax for a Quiz within markdown, as such the syntax for the above quiz is as follows: 31 | 32 |
33 | >>Q1: Enter the extract string test<<
34 | === test
35 | 
36 | >>Q2: Enter the string containing test<<
37 | =~= test
38 | 
39 | >>Q3: Multiple Choice <<
40 | [*] Correct
41 | [*] Correct
42 | [ ] Incorrect
43 | 
44 | >>Q4: Single Choice <<
45 | (*) Correct
46 | ( ) Incorrect
47 | 
48 | 49 | The ***** within single and multiple choice indicates the correct answer. The syntax **===** is exact match, while **=~=** is a string containing match. 50 | 51 | **Note:** There should not be a blank line between the question and the possible answers. 52 | 53 | ## Correct and Incorrect Answers 54 | 55 | When a user clicks **Check Answers**, the correct answers will appear with a Green tick! If they have entered anything incorrect they will be asked to check and try again. 56 | -------------------------------------------------------------------------------- /challenges/challenge-linux-solver/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "challenge@0.8", 3 | "title": "Challenge Example - Linux Challenge Using the Solver Utility", 4 | "description": "An example challenge showing authors how to use the solver features.", 5 | "difficulty": "Beginner", 6 | "time": "15 minutes", 7 | "details": { 8 | "intro": { 9 | "text": "intro.md", 10 | "courseData": "init-background.sh", 11 | "code": "init-foreground.sh", 12 | "credits": "[Jonathan Johnson](http://www.dijure.com)" 13 | }, 14 | "finish": { 15 | "text": "finish.md" 16 | }, 17 | "steps": [ 18 | { 19 | "title": "Moo!", 20 | "text": "task_1.md", 21 | "verify": "verify.sh", 22 | "hint": "hint.sh" 23 | }, 24 | { 25 | "title": "Formatting Output", 26 | "text": "task_2.md", 27 | "verify": "verify.sh", 28 | "hint": "hint.sh" 29 | }, 30 | { 31 | "title": "Hey Stella!", 32 | "text": "task_3.md", 33 | "verify": "verify.sh", 34 | "hint": "hint.sh" 35 | }, 36 | { 37 | "title": "Powerful xargs", 38 | "text": "task_4.md", 39 | "verify": "verify.sh", 40 | "hint": "hint.sh" 41 | } 42 | ], 43 | "assets": { 44 | "host01": [ 45 | {"file": "verifications.sh", "target": "/usr/local/bin/", "chmod": "+x"}, 46 | {"file": "hints.md", "target": "/opt"}, 47 | {"file": "solutions.sh.enc", "target": "/opt"}, 48 | 49 | {"file": "streetcar.pdf", "target": "/root"}, 50 | {"file": "my-xargs.sh", "target": "/root", "chmod": "+x"} 51 | ] 52 | } 53 | }, 54 | 55 | "environment": { 56 | "showide": true, 57 | "hidesidebar": true, 58 | "uilayout": "terminal" 59 | }, 60 | 61 | "backend": { 62 | "imageid": "ubuntu:2004" 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /environments/kubernetes-cluster-1-16/master/build/1_init.sh: -------------------------------------------------------------------------------- 1 | # Build time 2 | install_kompose() { 3 | # Linux 4 | curl -L https://github.com/kubernetes/kompose/releases/download/v1.20.0/kompose-linux-amd64 -o kompose 5 | chmod +x kompose 6 | sudo mv ./kompose /usr/local/bin/kompose 7 | } 8 | 9 | install_helm() { 10 | curl -s https://storage.googleapis.com/kubernetes-helm/helm-v2.9.0-linux-amd64.tar.gz | tar xz 11 | cp linux-amd64/helm /usr/local/bin/ 12 | } 13 | 14 | ## Install CSI host path driver 15 | install_csi_driver() { 16 | git clone https://github.com/kubernetes-csi/csi-driver-host-path.git /opt/csi-driver-host-path 17 | } 18 | 19 | install_kompose 20 | install_helm 21 | install_csi_driver 22 | 23 | # Runtime 24 | cat < /opt/configure-environment.sh 25 | #!/bin/bash 26 | # Wait until k8s is ready 27 | waitk8s=true 28 | while [ \$waitk8s == true ] 29 | do 30 | if [[ "\$(kubectl get nodes 2>/dev/null | grep Ready | wc | awk '{ print \$1}')" == "2" ]]; then 31 | waitk8s=false 32 | else 33 | echo "Waiting for k8s" >> /opt/configure-environment.logs 34 | sleep 1 35 | fi 36 | done 37 | # Tiller 38 | kubectl -n kube-system create serviceaccount tiller 39 | kubectl create clusterrolebinding tiller --clusterrole cluster-admin --serviceaccount=kube-system:tiller 40 | # Helm 41 | # helm init --service-account tiller 42 | helm init --service-account tiller --output yaml | sed 's@apiVersion: extensions/v1beta1@apiVersion: apps/v1@' | sed 's@ replicas: 1@ replicas: 1\n selector: {"matchLabels": {"app": "helm", "name": "tiller"}}@' | kubectl apply -f - 43 | until (kubectl get pods -n kube-system -l app=helm,name=tiller 2>/dev/null | grep Running); do sleep 1; done 44 | 45 | ## Install CSI host path driver 46 | /opt/csi-driver-host-path/deploy/kubernetes-1.16/deploy-hostpath.sh 47 | EOF 48 | chmod +x /opt/configure-environment.sh 49 | -------------------------------------------------------------------------------- /uilayouts-pathway.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Katacoda UI Layouts Example", 3 | "description": "Example of different Katacoda UI Layouts. Also, an example of creating a Katacoda Course!", 4 | "icon": "fa-katacoda", 5 | "courses": [ 6 | { 7 | "course_id": "uilayout-terminal", 8 | "title": "Scenario with Terminal UI", 9 | "description": "Katacoda Scenario Example" 10 | }, 11 | { 12 | "title": "Scenario with Terminal and VS Code UI as Tab", 13 | "description": "", 14 | "pathway_id": "scenario-examples", 15 | "course_id": "uilayout-terminal-with-vscode" 16 | }, 17 | { 18 | "course_id": "uilayout-vscode-terminal", 19 | "title": "Scenario with VS Code / Terminal UI Split Screen", 20 | "description": "Katacoda Scenario Example" 21 | }, 22 | { 23 | "course_id": "uilayout-editor-terminal", 24 | "title": "Scenario with Editor Terminal UI", 25 | "description": "Katacoda Scenario Example" 26 | }, 27 | { 28 | "course_id": "uilayout-terminal-iframe", 29 | "title": "Scenario with Terminal iFrame UI", 30 | "description": "Katacoda Scenario Example" 31 | }, 32 | { 33 | "course_id": "uilayout-terminal-iframe-split", 34 | "title": "Scenario with Terminal iFrame Split UI", 35 | "description": "Katacoda Scenario Example" 36 | }, 37 | { 38 | "course_id": "uilayout-iframe", 39 | "title": "Scenario with iFrame only UI", 40 | "description": "" 41 | }, 42 | { 43 | "course_id": "uilayout-terminal-terminal", 44 | "title": "Scenario with Terminal Terminal UI", 45 | "description": "Katacoda Scenario Example" 46 | }, 47 | { 48 | "title": "Visualise Environment Tab", 49 | "description": "Learn how to add the Visualise Tab", 50 | "pathway_id": "scenario-examples", 51 | "course_id": "visualise-docker" 52 | } 53 | ] 54 | } 55 | 56 | -------------------------------------------------------------------------------- /custom-events/step1.md: -------------------------------------------------------------------------------- 1 | Katacoda provides a service that listens to events defined in the scenario and allows to override the default behavior of the platform. 2 | 3 | Let's see an example, in this scenario, we use the layout `editor-iframe-split`, and the pages updated in the editor are served by a nodejs and displayed in the iframe. 4 | 5 | Give the app a few minutes to start, and then, click in the reload button on the right. You should see the result of the content of index.html displayed in the iframe. 6 | 7 | By default, after the user stops typing, the editor saves the file. The number of seconds that the editor waits to save the file can be defined in the scenario with the property `delayToSaveFileAfterStopTypingMilliseconds` in the environment: 8 | 9 |
10 |   "environment": {
11 |       ...
12 |       "delayToSaveFileAfterStopTypingMilliseconds": 2000,
13 |   }
14 | 
15 | 16 | When a file is saved, a progress bar is shown, and the progress bar is hidden when the file was successfully saved. But for our example, we need to stop showing the progress bar when the gulp task `reload` finished. 17 | 18 | To do that, we need to need to send a message to the EventService, indicating the event we need to raise. The list of all events supported are available in this [link](https://katacoda.com/docs/scenarios/custom-events) 19 | 20 | In this example, after the `reload` task, we call to the EventService to send the `reload-finished` message. See `gulpfile.js`{{open}}, function callEventService 21 | 22 | ## Request to Event Service 23 | 24 | The request to the EventService should follow this structure: 25 | 26 | `curl -X POST https://environment-events.katacoda.com -d "socket=$1 message=message"` 27 | 28 | The socket parameter can be retrieved from the file `/tmp/socket`. 29 | 30 | ## Mapping event in index.json 31 | 32 | In the file `index.json` the message received in the EventService should be mapped to which event we want to raise, for example: 33 | 34 |
35 | "events": {
36 |   "hideprogressbar": "reload-finished"
37 | }
38 | 
39 | -------------------------------------------------------------------------------- /uilayouts/uilayout-terminal-with-vscode/step1.md: -------------------------------------------------------------------------------- 1 | The Katacoda `terminal` layout provides a full Terminal experience. This can be extended to include a full IDE experience as a separate tab by including `showide` within the `environment` section of the `index.json`. For example: 2 | 3 | ```json 4 | "environment": { 5 | "showide": true 6 | } 7 | ``` 8 | 9 | ## IDE Functionality 10 | 11 | With the IDE, you can open files certain files from Markdown - `newFile.js`{{open}} 12 | 13 | You can copy, extend or replace text from UI helpers. 14 | 15 |
var http = require('http');
16 | var requestListener = function (req, res) {
17 |   res.writeHead(200);
18 |   res.end('Hello, World!');
19 | }
20 | 
21 | var server = http.createServer(requestListener);
22 | server.listen(3000, function() { console.log("Listening on port 3000")});
23 | 
24 | 25 | The following snippet will prepend the contents of the editor: 26 | 27 |
console.log("Starting...")
28 | 
29 | 30 | Within the Markdown, include: 31 | 32 |
33 | <pre class="file" data-filename="app.js" data-target="prepend">console.log("Starting...")
34 | </pre>
35 | 
36 | 37 | The following snippet will append the contents of the editor: 38 | 39 |
console.log("Finishing...")
40 | 
41 | 42 | Within the Markdown, include: 43 | 44 |
45 | <pre class="file" data-filename="app.js" data-target="append">console.log("Finishing...")
46 | </pre>
47 | 
48 | 49 | The editor can copy to particular files based on the data-filename attribute: 50 | 51 |
console.log("Index.js here...")
52 | 
53 | 54 | Within the Markdown, include: 55 | 56 |
57 | <pre class="file" data-filename="index.js" data-target="replace">console.log("Index.js here...")
58 | </pre>
59 | 
60 | -------------------------------------------------------------------------------- /challenges/challenge-linux-solver/.cypress/solver_spec.js.disabled: -------------------------------------------------------------------------------- 1 | describe('Complete Challenge with Solver', () => { 2 | const zenMoment=5000 3 | 4 | before(() => { 5 | cy.startScenario() 6 | }); 7 | 8 | it('click start button', () => { 9 | cy.get('button[id="hide-intro"]').click() 10 | }); 11 | 12 | it('is terminal ready', () => { 13 | cy.wait(zenMoment) 14 | cy.terminalShouldContain('Challenge ready.'); 15 | }); 16 | 17 | it('are dependencies healthy', () => { 18 | cy.terminalType('uname -a'); 19 | cy.terminalShouldContain('Linux',{timeout: 500}); 20 | cy.terminalShouldContain('Ubuntu',{timeout: 500}); 21 | 22 | cy.terminalType('uptime'); 23 | cy.terminalShouldContain('1 user',{timeout: 500}); 24 | }); 25 | 26 | it('open solutions', () => { 27 | expect(Cypress.env('test')).to.equal('See this?') 28 | cy.log("Found for TEST=" + Cypress.env('test')) 29 | 30 | cy.terminalType('solver solutions --decrypt ' + Cypress.env('SOLVER_KEY')); 31 | cy.terminalShouldContain('Solutions now available'); 32 | }); 33 | 34 | it('solve all', () => { 35 | cy.terminalType('solver all'); 36 | cy.terminalShouldContain('Verification passed for task 1'); 37 | }); 38 | 39 | it('solve step 1', () => { 40 | cy.terminalType('solver next'); 41 | cy.terminalShouldContain('Verification passed for task 1'); 42 | }); 43 | 44 | it('solve step 2', () => { 45 | cy.terminalType('solver next'); 46 | cy.terminalShouldContain('Verification passed for task 2'); 47 | }); 48 | 49 | it('solve step 3', () => { 50 | cy.terminalType('solver next'); 51 | cy.terminalShouldContain('Verification passed for task 3'); 52 | }); 53 | 54 | it('solve step 4', () => { 55 | cy.terminalType('solver next'); 56 | cy.terminalShouldContain('Verification passed for task 4'); 57 | }); 58 | 59 | it('is complete', () => { 60 | 61 | // TODO: Problem with IFrames barriers with Cypress - may need a helper function instructionsShouldContain 62 | // cy.contains('Congratulations, you have successfully completed this challenge'); 63 | 64 | // TODO: Also, are there plans for the finish page to return 65 | 66 | cy.terminalType('solver status --quiet'); 67 | cy.terminalShouldContain('0'); 68 | }); 69 | }) 70 | -------------------------------------------------------------------------------- /environment-usages-pathway.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Katacoda Environments", 3 | "description": "Available Katacoda Environments", 4 | "icon": "fa-katacoda", 5 | "courses": [ 6 | { 7 | "course_id": "ubuntu-1804", 8 | "title": "Ubuntu 18.04 Instance", 9 | "description": "General purpose environment" 10 | }, 11 | { 12 | "course_id": "ubuntu-2004", 13 | "title": "Ubuntu 20.04 Instance", 14 | "description": "General purpose environment" 15 | }, 16 | { 17 | "course_id": "kubernetes-cluster", 18 | "title": "Kubernetes Cluster", 19 | "description": "Multi node Kubernetes cluster configured using Kubeadm" 20 | }, 21 | { 22 | "course_id": "kubernetes-cluster-running", 23 | "title": "Kubernetes Cluster Running", 24 | "description": "Multi node Kubernetes cluster configured using Kubeadm" 25 | }, 26 | { 27 | "course_id": "minikube", 28 | "title": "Minikube", 29 | "description": "Use Minikube to help explain Kubernetes" 30 | }, 31 | { 32 | "course_id": "java", 33 | "title": "Java / Scala", 34 | "description": "" 35 | }, 36 | { 37 | "course_id": "kotlin", 38 | "title": "Kotlin", 39 | "description": "" 40 | }, 41 | { 42 | "course_id": "python", 43 | "title": "Python 3", 44 | "description": "" 45 | }, 46 | { 47 | "course_id": "nodejs", 48 | "title": "Node.js", 49 | "description": "" 50 | }, 51 | { 52 | "course_id": "go", 53 | "title": "go", 54 | "description": "" 55 | }, 56 | { 57 | "course_id": "rust", 58 | "title": "rust", 59 | "description": "" 60 | }, 61 | { 62 | "course_id": "ruby", 63 | "title": "ruby", 64 | "description": "" 65 | }, 66 | { 67 | "course_id": "dotnet", 68 | "title": "C# / Dotnet", 69 | "description": "" 70 | }, 71 | { 72 | "course_id": "r", 73 | "title": "R", 74 | "description": "" 75 | }, 76 | { 77 | "course_id": "bash", 78 | "title": "Bash", 79 | "description": "" 80 | } 81 | ] 82 | } 83 | 84 | -------------------------------------------------------------------------------- /custom-events/site/gulpfile.js: -------------------------------------------------------------------------------- 1 | const gulp = require('gulp'); 2 | const browserSync = require('browser-sync'); 3 | const fileinclude = require('gulp-file-include'); 4 | const sass = require('gulp-sass'); 5 | const server = browserSync.create(); 6 | const request = require('request'); 7 | const fs = require('fs') 8 | var SERVICE_URL='https://environment-events.katacoda.com'; 9 | 10 | const paths = { 11 | html: { 12 | src: [ '**/*.html', '!node_modules', '!node_modules/**', '!dist/**'], 13 | dest: 'dist/' 14 | }, 15 | sass: { 16 | src: ['*.scss'], 17 | dest: 'dist/' 18 | } 19 | }; 20 | 21 | function html() { 22 | return gulp.src(paths.html.src) 23 | .pipe(gulp.dest(paths.html.dest)); 24 | } 25 | 26 | function reload(done) { 27 | server.reload(); 28 | done(); 29 | } 30 | 31 | function fileInclude() { 32 | return gulp.src(['server/template.html']) 33 | .pipe(fileinclude({ 34 | prefix: '@@', 35 | basepath: './' 36 | })) 37 | .pipe(gulp.dest(paths.html.dest + 'server')); 38 | } 39 | 40 | function style () { 41 | return gulp.src('./*.scss') 42 | .pipe(sass()) 43 | .pipe(gulp.dest('./dist/css')); 44 | } 45 | 46 | function serve(done) { 47 | server.init({ 48 | injectChanges: true, 49 | notify: false, 50 | server: { 51 | baseDir: './dist' 52 | }, 53 | index: 'server/template.html' 54 | }); 55 | done(); 56 | } 57 | 58 | 59 | function callEventService(cb) { 60 | var s = fs.readFileSync('/tmp/socket','utf8') 61 | if (s){ 62 | console.log ('Retrieved socket', s); 63 | const headers = { 64 | 'Content-Type': 'application/x-www-form-urlencoded' 65 | } 66 | 67 | const options = { 68 | url: SERVICE_URL, 69 | method: 'POST', 70 | headers: headers } 71 | 72 | request.post(options.url, { 73 | form: { 74 | message: 'reload-finished', 75 | socket: s 76 | } 77 | }, function(err, res) { 78 | if(err){ 79 | console.log(err, res); 80 | } 81 | cb(); 82 | }); 83 | } 84 | } 85 | 86 | const watch = () => gulp.watch(paths.html.src, gulp.series(html, fileInclude, reload, callEventService)); 87 | const sassWatch = () => gulp.watch(paths.sass.src, gulp.series(style, reload)); 88 | 89 | const dev = gulp.series(html, fileInclude, style, serve, gulp.parallel(sassWatch, watch)); 90 | exports.default = dev; 91 | -------------------------------------------------------------------------------- /create-scenario-101/step3.md: -------------------------------------------------------------------------------- 1 | To help create the index.json and scenario structure, Katacoda has developed a command line interactive (CLI). 2 | 3 | ## Install CLI 4 | 5 | Install the CLI with the command `npm i katacoda-cli --global`{{execute}}. 6 | 7 | The commands follow the syntax is: 8 | 9 | `$ katacoda COMMAND` 10 | 11 | After the install has finished, the command can be run via `katacoda --help`{{execute}}. 12 | 13 | ## Create scenario 14 | 15 | For example, to create a new scenario you would run the command `katacoda scenarios:create`{{execute}}. The CLI will prompt you for a few questions in order to create your scenario: 16 | 17 | - **Friendly URL:** here you will type `test-scenario`. This attribute will determine the name of the folder of your scenario, and the URL to access it, so, should not contain spaces, should be lower case, etc. For example, if your username is *test-username* and your scenario was called *test-scenario* as suggested, the URL to point the scenario in the platform will be https://katacoda.com/test-username/scenarios/test-scenario/ 18 | - **Title:** title the scenario 19 | - **Description:** description of the scenario, displayed on the intro screen 20 | - **Difficulty level:** provide users with a sense of the depth of content, displayed on the intro screen 21 | - **Estimated time:** provide users with an estimated time to complete, displayed on the intro screen 22 | - **Number of steps:** the numbers of the steps that the scenario will contain. The CLI will create all the template files for all the steps that you specified 23 | - **Image:** it will determine which base software will be available for your scenario. For example, if you need docker, java, go, etc as a pre-requisite. For more information read [Supported Environments](https://www.katacoda.community/essentials/environments.html) 24 | - **Layout:** it will determine the disposition of the elements of your scenario. For example, if you want to present only a terminal, or editor + terminal, etc. For more information read [Supported Layouts](https://www.katacoda.community/essentials/layouts.html) 25 | 26 | With this information, the CLI will create a folder with the name of the ***friendly URL*** introduced and will create inside of that folder the required files for your scenario. 27 | 28 | You can check your scenario created with this command: 29 | 30 | `ls test-scenario*`{{execute}} 31 | -------------------------------------------------------------------------------- /challenges/challenge-hello-world/README.md: -------------------------------------------------------------------------------- 1 | # Challenge Template 2 | 3 | Hi! Thanks for opening this README. I am feeling optimistic, as you must be the sort of person who reads the directions before trying to build something new. We are going to get along great. 4 | 5 | This folder is a "Hello, world!" example of a challenge. Consider this a bare minimum, skeletal starting point, which you will customize to suit your own purposes. 6 | 7 | Here is a quick lay of the land: 8 | 9 | **index.json** --- This is the core definition of any scenario, challenge or otherwise. Note especially: 10 | 11 | - `"type": "challenge@0.8"` --- to specify this is a challenge, not a standard scenario 12 | - `"imageid": "ubuntu:2004"` --- This example uses the Ubuntu 20.04 base image, but you should use whatever [base image](https://www.katacoda.community/essentials/environments.html) is most appropriate for your challenge. 13 | - Note that the `index.json` includes a `verify` and `hint` for each step: 14 | 15 | ```json 16 | "steps": [ 17 | { 18 | "title": "Bananas", 19 | "text": "1_task.md", 20 | "verify": "1_verify.sh", 21 | "hint": "1_hint.sh" 22 | }, 23 | … 24 | ] 25 | ``` 26 | 27 | The `verify` points to a shell script. This is run continuously until a success code (exit code 0) is returned. 28 | 29 | The `hint` is another shell script that defines what hints to display for that task/step and when (that is, under what conditions). 30 | 31 | **.md files** --- The Markdown files are standard Markdown, just as used for standard scenarios. Not all the Katacoda Markdown extensions can be used in this context, however (such as clickable code shortcuts). 32 | 33 | **.sh files** --- Bash shell scripts, as described above. 34 | 35 | For clarity, we strongly recommend following the naming convention here in this example, whereby files are prefixed with the related task/step number: 36 | 37 | ```sh 38 | 1_hint.sh 39 | 1_task.md 40 | 1_verify.sh 41 | 2_hint.sh 42 | 2_task.md 43 | 2_verify.sh 44 | ``` 45 | 46 | **SOLUTIONS.md** --- For each task, please provide instructions for the solution. This is _not_ shared with the learner, but is for our internal reference, to help with testing. 47 | 48 | Please also review the [challenge documentation here](https://www.katacoda.community/challenges/challenges.html). 49 | 50 | _Please reach out with feedback and questions about this example! And thank you for reading the directions._ ♥️ 51 | -------------------------------------------------------------------------------- /challenges/challenge-linux-solver/assets/verifications.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script is called by the solver utility. Each function should be named 4 | # verify_task_#, where # is the number of the task each function will solve. 5 | # When a verification fails for a step, the error number returned corresponds 6 | # to the hint number found in hints.md. 7 | 8 | function verify_task_1() { 9 | dpkg-query -l | grep cowsay 10 | if [[ $? -ne 0 ]] 11 | then 12 | return 1 13 | fi 14 | 15 | whereis cowsay 16 | if [[ $? -ne 0 ]] 17 | then 18 | return 2 19 | fi 20 | 21 | 22 | if [[ ! -f 'cowsay.txt' ]] 23 | then 24 | return 3 25 | fi 26 | 27 | cowsay "O'Reilly, inspiring the future for more than 40 years" > '/tmp/expected-cowsay.txt' 28 | diff '/tmp/expected-cowsay.txt' 'cowsay.txt' 29 | if [[ $? -ne 0 ]] 30 | then 31 | return 4 32 | fi 33 | } 34 | 35 | 36 | function verify_task_2() { 37 | if [[ ! -f 'kinder-passwd.txt' ]] 38 | then 39 | return 1 40 | fi 41 | 42 | cat /etc/passwd | column -t -s : > '/tmp/expected-format.txt' 43 | diff '/tmp/expected-format.txt' 'kinder-passwd.txt' 44 | if [[ $? -ne 0 ]] 45 | then 46 | return 2 47 | fi 48 | } 49 | 50 | 51 | function verify_task_3() { 52 | 53 | dpkg-query -l | grep poppler-utils 54 | 55 | if [[ $? -ne 0 ]] 56 | then 57 | return 1 58 | fi 59 | 60 | whereis pdftotext 61 | if [[ $? -ne 0 ]] 62 | then 63 | return 2 64 | fi 65 | 66 | if [[ ! -f 'streetcar.txt' ]] 67 | then 68 | return 3 69 | fi 70 | 71 | grep 'on a street in New Orleans' streetcar.txt 72 | if [[ $? -ne 0 ]] 73 | then 74 | return 4 75 | fi 76 | 77 | if [[ ! -f 'stella.properties' ]] 78 | then 79 | return 5 80 | fi 81 | 82 | grep 'stella=' stella.properties 83 | if [[ $? -ne 0 ]] 84 | then 85 | return 6 86 | fi 87 | 88 | grep 'stella_exclamation=' stella.properties 89 | if [[ $? -ne 0 ]] 90 | then 91 | return 7 92 | fi 93 | 94 | grep 'stella=155' stella.properties 95 | if [[ $? -ne 0 ]] 96 | then 97 | return 8 98 | fi 99 | 100 | grep 'stella_exclamation=16' stella.properties 101 | if [[ $? -ne 0 ]] 102 | then 103 | return 9 104 | fi 105 | } 106 | 107 | 108 | function verify_task_4() { 109 | 110 | if [[ ! -f 'my-xargs.sh' ]] 111 | then 112 | return 1 113 | fi 114 | 115 | if [[ $(grep -c 'xargs' my-xargs.sh) -ne 1 ]] 116 | then 117 | return 2 118 | fi 119 | 120 | echo -n "1 2 3 4 5" | xargs -d ' ' -i ls {}.txt 121 | if [[ $? -ne 0 ]] 122 | then 123 | return 3 124 | fi 125 | 126 | echo -n "1 2 3 4 5" | xargs -d ' ' -i grep "I am {}" {}.txt 127 | if [[ $? -ne 0 ]] 128 | then 129 | return 4 130 | fi 131 | } 132 | -------------------------------------------------------------------------------- /challenges/challenge-linux-solver/init-background.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Log script activity (https://serverfault.com/a/103569) 4 | exec 3>&1 4>&2 5 | trap 'exec 2>&4 1>&3' 0 1 2 3 6 | exec 1>/var/log/init-background.log 2>&1 7 | set -x 8 | 9 | # Add any installations or configurations here that the scenario may need 10 | # 11 | 12 | # Common curl switches 13 | echo '-s' >> ~/.curlrc 14 | 15 | # ========================= 16 | # Do not modify lines below 17 | 18 | # The Solver command-line tool cannot be committed to each challenge and installed via assets. Mostly because 19 | # scenarios limit the asset size to below 10Mb. Instead, this script downloads the solver utility from a public source. 20 | # The version of the solver release should be the exact version the author testing the scenario with. Authors are 21 | # encourage to periodically upgrade the solver release when new ones are available. 22 | # 23 | # Each time a scenario starts, this script is called from the background script (init-background.sh). If the solver 24 | # download fails the scenario will not work correctly. To greatly reduce this risk, the download of 25 | # the same version of solver comes from two independent sources: 26 | # 27 | # 1) GitHub container registry 28 | # 2) GitHub solver release page 29 | # 30 | # The two sources are still related to GitHub, but they are different storage services. The latter is less reliable 31 | # than the container registry. 32 | 33 | # The 'solver create' command will install this script and ensure this version matches the utilized solver version. 34 | SOLVER_VERSION=0.5.4 35 | 36 | function verify_solver_install() { 37 | solver --version | grep $SOLVER_VERSION 38 | return $? 39 | } 40 | 41 | # First download request - download container image, create it, copy solver out of the container, delete container 42 | SOLVER_CONTAINER_IMAGE=ghcr.io/javajon/solver 43 | ID=$(docker create $SOLVER_CONTAINER_IMAGE:$SOLVER_VERSION) 44 | docker cp "$ID":/application /usr/local/bin/solver 45 | 46 | verify_solver_install 47 | if [ $? -ne 0 ]; then 48 | echo "Failed to download solver from $SOLVER_CONTAINER_IMAGE:$SOLVER_VERSION" 49 | 50 | # Second download request - download solver linux binary from release page 51 | RELEASE="https://github.com/javajon/katacoda-solver/releases/download/$SOLVER_VERSION/solver-$SOLVER_VERSION-runner" 52 | wget -q -O solver $RELEASE 53 | chmod +x solver 54 | mv solver /usr/local/bin/ 55 | 56 | verify_solver_install 57 | if [ $? -ne 0 ]; then 58 | echo "Failed to download solver from github release page: $RELEASE" 59 | # init-foreground displays messsage on linux prompt that there is a problem. 60 | fi 61 | fi 62 | 63 | # Signal to challenge controller that the startup is complete 64 | echo 'done' > /opt/katacoda-background-finished 65 | 66 | # Signal to init-foreground.sh that the startup is complete 67 | echo 'done' > /opt/.backgroundfinished 68 | -------------------------------------------------------------------------------- /challenges/challenge-linux-solver/init-foreground.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | FREQUENCY=1 # Delay between each check for completion 4 | BACKGROUND_SIGNAL_FILE='/opt/.backgroundfinished' # File updated by background to indicate completion 5 | BACKGROUND_SAFE_WORD='done' # Word in BACKGROUND_SIGNAL_FILE indicating completion 6 | START_MESSAGE='Starting scenario' # Message before the progress animation 7 | END_NORMAL_MESSAGE='Challenge ready.' 8 | END_KILLED_MESSAGE='Interupted. This scenario may still be initializing.' 9 | 10 | SPINNER_COLOR_NUM=2 # Color to use, unless COLOR_CYCLE=1 11 | SPINNER_COLOR_CYCLE=0 # 1 to rotate colors between each animation 12 | INTERVAL=.25 13 | SPINNER_NORMAL=$(tput sgr0) # Reset encoding 14 | symbols=("▐⠂ ▌" "▐⠈ ▌" "▐ ⠂ ▌" "▐ ⠠ ▌" "▐ ⡀ ▌" "▐ ⠠ ▌" "▐ ⠂ ▌" "▐ ⠈ ▌" "▐ ⠂ ▌" "▐ ⠠ ▌" "▐ ⡀ ▌" "▐ ⠠ ▌" "▐ ⠂ ▌" "▐ ⠈ ▌" "▐ ⠂▌" "▐ ⠠▌" "▐ ⡀▌" "▐ ⠠ ▌" "▐ ⠂ ▌" "▐ ⠈ ▌" "▐ ⠂ ▌" "▐ ⠠ ▌" "▐ ⡀ ▌" "▐ ⠠ ▌" "▐ ⠂ ▌" "▐ ⠈ ▌" "▐ ⠂ ▌" "▐ ⠠ ▌" "▐ ⡀ ▌" "▐⠠ ▌") 15 | 16 | progress_pid=0 17 | 18 | cleanup () { 19 | kill $progress_pid >/dev/null 2>&1 20 | progress_pid=-1 21 | end_message=$END_KILLED_MESSAGE 22 | } 23 | 24 | show_progress () { 25 | while :; do 26 | tput civis 27 | for symbol in "${symbols[@]}"; do 28 | if [ $SPINNER_COLOR_CYCLE -eq 1 ]; then 29 | if [ $SPINNER_COLOR_NUM -eq 7 ]; then 30 | SPINNER_COLOR_NUM=1 31 | else 32 | SPINNER_COLOR_NUM=$((SPINNER_COLOR_NUM+1)) 33 | fi 34 | fi 35 | local color 36 | color=$(tput setaf ${SPINNER_COLOR_NUM}) 37 | tput sc 38 | printf "%s%s%s " "${color}" "${symbol}" "${SPINNER_NORMAL}" 39 | tput rc 40 | sleep "${INTERVAL}" 41 | done 42 | done 43 | tput cnorm 44 | return 0 45 | } 46 | 47 | start_progress () { 48 | show_progress & 49 | progress_pid=$! 50 | 51 | # Catch any exit and stop progress animation 52 | trap cleanup SIGINT EXIT INT QUIT TERM 53 | 54 | clear && echo -n "$START_MESSAGE " 55 | 56 | # Periodically check for background signal or user Ctrl-C interuption 57 | end_message=$END_NORMAL_MESSAGE 58 | while [[ $progress_pid -ge 0 ]]; do 59 | grep -i ${BACKGROUND_SAFE_WORD} ${BACKGROUND_SIGNAL_FILE} &> /dev/null 60 | if [[ "$?" -eq 0 ]]; then 61 | kill $progress_pid >/dev/null 2>&1 62 | break 63 | fi 64 | sleep ${FREQUENCY} 65 | done 66 | 67 | stty sane; tput cnorm; clear 68 | solver --version | grep "version">/dev/null 2>&1 69 | if [ $? -ne 0 ]; then 70 | printf "This challenge did not appear to start correctly. Refresh this browser page to try again.\n\n" 71 | else 72 | printf "%s\n\n" "${end_message}" 73 | fi 74 | 75 | # Pick up any changes during background 76 | source ~/.bashrc 77 | 78 | # In shell context for student, so set any environment variables for learner here, if needed: 79 | } 80 | 81 | clear && start_progress -------------------------------------------------------------------------------- /challenges/challenge-linux-solver/assets/hints.md: -------------------------------------------------------------------------------- 1 | # Task Hints Authoring Guidelines 2 | 3 | When authoring this collection of hints, mark each hint with the double pound (##) markdown header and title the header with Task n, Hint n. Capital T and H. Tasks and Hints nymbers start at 1. See this [Challenge Hints](https://www.katacoda.community/challenges.html#ui-example) in the authoring guide on how to provide hints for your challenge scenarios. The [Katacoda markdown extensions](https://www.katacoda.community/scenario-syntax.html#katacoda-s-markdown-extensions) can be applied in this markdown. An optional horizontal divider (`---`) can be added before each Task section. 4 | 5 | --- 6 | 7 | ## Task 1, Hint 1 8 | 9 | The latest version of `cowsay` may be herded into this challenge using apt-get. The package manager is not reporting cowsay is installed. 10 | 11 | ## Task 1, Hint 2 12 | 13 | The `cowsay` utility is not appearing in the `whereis` $PATH. 14 | 15 | ## Task 1, Hint 3 16 | 17 | The expected `cowsay.txt` file has not been created yet. 18 | 19 | ## Task 1, Hint 4 20 | 21 | The `cowsay.txt` file is present but does not contain the expected message formatted to the bovine culture as outputted by the cowsay utility. 22 | 23 | --- 24 | 25 | ## Task 2, Hint 1 26 | 27 | The expected `kinder-passwd.txt` file has not been created yet. 28 | 29 | ## Task 2, Hint 2 30 | 31 | The `kinder-passwd.txt` file does container the passwd data in its expected columnar form. Have you discovered the ['column'](https://man7.org/linux/man-pages/man1/column.1.html) utility yet? 32 | 33 | --- 34 | 35 | ## Task 3, Hint 1 36 | 37 | The apt package manager is not reporting poppler-utils is installed. 38 | 39 | ## Task 3, Hint 2 40 | 41 | The `pdf2text` utility is not appearing in the `whereis` $PATH. 42 | 43 | ## Task 3, Hint 3 44 | 45 | The expected `streetcar.txt` file has not been created yet. 46 | 47 | ## Task 3, Hint 4 48 | 49 | The `streetcar.txt` file does not contain the expect text from the script found in the PDF. Did you use pdf2text to fill the text file? 50 | 51 | ## Task 3, Hint 5 52 | 53 | The expected `stella.properties` file has not been created yet. 54 | 55 | ## Task 3, Hint 6 56 | 57 | The `stella.properties` file does not have a setting for `stella=`. 58 | 59 | ## Task 3, Hint 7 60 | 61 | The `stella.properties` file does not have a setting for `stella_exclamation=`. 62 | 63 | ## Task 3, Hint 8 64 | 65 | The `stella.properties` file does not have the correct value for `stella=?`. 66 | 67 | ## Task 3, Hint 9 68 | 69 | The `stella.properties` file does not have the correct value for `stella_exclamation=?`. 70 | --- 71 | 72 | ## Task 4, Hint 1 73 | 74 | The expected `my-xargs.sh` file has not been created yet. 75 | 76 | ## Task 4, Hint 2 77 | 78 | The `my-xargs.sh` should just have one usage of `xargs` in a single line. 79 | 80 | ## Task 4, Hint 3 81 | 82 | There should be 5 files present called 1.txt, 2.txt, 3.txt, 4.txt, and 5.txt. 83 | 84 | ## Task 4, Hint 4 85 | 86 | Each one of the 5 text files should contain the line "I am n", where n is the matching number in the file name. Did you consider this form `echo -n '1 2 3 4 5' | xargs -d ' ' -i sh -c "touch {}.txt ; echo 'I am {}' > {}.txt"`? 87 | -------------------------------------------------------------------------------- /uilayouts/uilayout-vscode-terminal/step1.md: -------------------------------------------------------------------------------- 1 | The Katacoda `editor-terminal` UI Layout combines an Editor with a Terminal. When changes are made to files using the editor, they are automatically sync'ed to the user's home directory. 2 | 3 | # Index.json 4 | 5 | The syntax for the editor is automatically inferred from the file extension. This can be enforced by including a "uisettings" 6 | 7 |
 8 | "environment": {
 9 |     "uilayout": "vscode-terminal-split"
10 | },
11 | 
12 | 13 | # Helper Functionality 14 | 15 | To support users, Katacoda has integrated various features to help users. 16 | 17 | Copy file to editor: 18 | 19 |
var http = require('http');
20 | var requestListener = function (req, res) {
21 |   res.writeHead(200);
22 |   res.end('Hello, World!');
23 | }
24 | 
25 | var server = http.createServer(requestListener);
26 | server.listen(3000, function() { console.log("Listening on port 3000")});
27 | 
28 | 29 | The following snippet will prepend the contents of the editor: 30 | 31 |
console.log("Starting...")
32 | 
33 | 34 | Within the Markdown, include: 35 | 36 |
37 | <pre class="file" data-filename="app.js" data-target="prepend">console.log("Starting...")
38 | </pre>
39 | 
40 | 41 | The following snippet will append the contents of the editor: 42 | 43 |
console.log("Finishing...")
44 | 
45 | 46 | Within the Markdown, include: 47 | 48 |
49 | <pre class="file" data-filename="app.js" data-target="append">console.log("Finishing...")
50 | </pre>
51 | 
52 | 53 | The editor can copy to particular files based on the data-filename attribute: 54 | 55 |
console.log("Index.js here...")
56 | 
57 | 58 | Within the Markdown, include: 59 | 60 |
61 | <pre class="file" data-filename="index.js" data-target="replace">console.log("Index.js here...")
62 | </pre>
63 | 
64 | 65 | Using the `data-target="insert"` attribute you can instruct the editor to insert the text in a particular position marked by `data-marker` attribute. 66 | 67 |
#TODO-insert
68 | 
69 | 70 |
71 | <pre class="file" data-filename="app.js" data-target="insert" data-marker="#TODO-insert">
72 | console.log("Inserted value using the data-marker attribute...")
73 | </pre>
74 | 
75 | 76 |
77 | console.log("Inserted value using the data-marker attribute...")
78 | 
79 | 80 | ## New Files 81 | 82 | Create a new file via the CLI: 83 | `touch newFile.js`{{execute}} 84 | 85 | The Markdown is: 86 |
`touch newFile.js`{{execute}}
87 | 88 | This can then be opened: 89 | `newFile.js`{{open}} 90 | 91 | The Markdown is: 92 |
`newFile.js`{{open}}
93 | -------------------------------------------------------------------------------- /uilayouts/uilayout-editor-terminal/step1.md: -------------------------------------------------------------------------------- 1 | The Katacoda `editor-terminal` UI Layout combines an Editor with a Terminal. 2 | When changes are made to files using the editor, they are automatically sync'ed 3 | to the user's home directory. 4 | 5 | # Index.json 6 | 7 | The editor will display and interact with files relative to the `uieditorpath` 8 | you set in the `index.json` file for your scenario. 9 | 10 |
 11 | "environment": {
 12 |   "uilayout": "editor-terminal",
 13 |   "uieditorpath": "/root/example"
 14 | }
 15 | 
16 | 17 | If not specified, the `uieditorpath` will default to the `/root` directory. 18 | 19 | You can pre-open a set of files in the editor by defining a `files` array in the root 20 | of the `index.json` file. 21 | 22 |
 23 | "files": [
 24 |     "app.js", "index.js"
 25 | ]
 26 | 
27 | 28 | Files open in the editor window are updated as you make changes in the editor. 29 | If the files do not already exist, the tabs will still open for them, but they 30 | will not be created until you have updated the content in the editor window. 31 | 32 | You can include a path with these filenames. Paths should be given 33 | relative to the `uieditorpath`. Only files under that path will be 34 | diplayed in the editor's directory tree. 35 | 36 | The syntax highlighting for the editor is automatically inferred from the file 37 | extension. This can be enforced by adding a `uisettings` to your environment. 38 | 39 |
 40 | "environment": {
 41 |     "uilayout": "editor-terminal",
 42 |     "uieditorpath": "/root/example",
 43 |     "uisettings": "javascript"
 44 | },
 45 | 
46 | 47 | # Helper Functionality 48 | 49 | You can replace, prepend, append, and insert text into an open editor file. 50 | 51 | Copy file to editor: 52 | 53 |
var http = require('http');
 54 | var requestListener = function (req, res) {
 55 |   res.writeHead(200);
 56 |   res.end('Hello, World!');
 57 | }
 58 | 
 59 | var server = http.createServer(requestListener);
 60 | server.listen(3000, function() { console.log("Listening on port 3000")});
 61 | 
62 | 63 | The following snippet will prepend the contents of the editor: 64 | 65 |
console.log("Starting...")
 66 | 
67 | 68 | Within the Markdown, include: 69 | 70 |
 71 | <pre class="file" data-filename="app.js" data-target="prepend">console.log("Starting...")
 72 | </pre>
 73 | 
74 | 75 | The following snippet will append the contents of the editor: 76 | 77 |
console.log("Finishing...")
 78 | 
79 | 80 | Within the Markdown, include: 81 | 82 |
 83 | <pre class="file" data-filename="app.js" data-target="append">console.log("Finishing...")
 84 | </pre>
 85 | 
86 | 87 | The editor can copy to particular files based on the data-filename attribute: 88 | 89 |
console.log("Index.js here...")
 90 | 
91 | 92 | Within the Markdown, include: 93 | 94 |
 95 | <pre class="file" data-filename="index.js" data-target="replace">console.log("Index.js here...")
 96 | </pre>
 97 | 
98 | 99 | Using the `data-target="insert"` attribute you can instruct the editor to insert the text in a particular position marked by `data-marker` attribute. 100 | 101 |
#TODO-insert
102 | 
103 | 104 |
105 | <pre class="file" data-filename="app.js" data-target="insert" data-marker="#TODO-insert">
106 | console.log("Inserted value using the data-marker attribute...")
107 | </pre>
108 | 
109 | 110 |
111 | console.log("Inserted value using the data-marker attribute...")
112 | 
113 | 114 | ## New Files 115 | 116 | Added files in the `uieditorpath` will automatically be added to the tree in the 117 | editor. A markdown extension also makes it easy to open new files in the editor. 118 | 119 | Create a new file via the CLI: 120 | `touch newFile.js`{{execute}} 121 | 122 | The Markdown is: 123 |
`touch newFile.js`{{execute}}
124 | 125 | This can then be opened: 126 | `newFile.js`{{open}} 127 | 128 | The Markdown is: 129 |
`newFile.js`{{open}}
130 | -------------------------------------------------------------------------------- /markdown-extensions/step1.md: -------------------------------------------------------------------------------- 1 | Katacoda has extended Markdown to simplify the users interaction while completing the scenarios and encounter less mistakes. 2 | 3 | ## Copy to Clipboard 4 | 5 | This extension will copy the command or text to the clipboard. 6 | 7 | Markdown: 8 |
`echo "Copy to Clipboard"`{{copy}}
9 | 10 | Results: 11 | `echo "Copy to Clipboard"`{{copy}} 12 | 13 | ## Multi-Line Copy to Clipboard 14 | 15 | The same functionality as above is available over multiple lines. 16 | 17 | Markdown: 18 |
 19 | ```sh
 20 | echo "Line 1"
 21 | 
 22 | echo "Line 2"
 23 | 
 24 | echo "Line 3"
 25 | ```{{copy}}
 26 | 
27 | 28 | Results: 29 | ```sh 30 | echo "Line 1" 31 | 32 | echo "Line 2" 33 | 34 | echo "Line 3" 35 | ```{{copy}} 36 | 37 | ## Execute in Terminal 38 | 39 | Katacoda has integration to automatically execute the commands for the terminal. 40 | 41 | This is done by adding `execute` to the markdown code block, for example: 42 |
`echo "Run in Terminal"`{{execute}}
43 | 44 | This creates: 45 | `echo "Run in Terminal"`{{execute}} 46 | 47 | ## Multi-Line Execute in Terminal 48 | 49 | The same functionality as above is available over multiple lines. 50 | 51 |
 52 | ```sh
 53 | echo "Line 1"
 54 | 
 55 | echo "Line 2"
 56 | 
 57 | echo "Line 3"
 58 | ```{{execute}}
 59 | 
 60 | 
61 | 62 | This creates: 63 | ```sh 64 | echo "Line 1" 65 | 66 | echo "Line 2" 67 | 68 | echo "Line 3" 69 | ```{{execute}} 70 | 71 | ## Interrupt 72 | 73 | When the user has long running commands, such as a watch, it can be useful to ensure that this is stopped but the user runs the next command. 74 | 75 |
`echo "Send Ctrl+C before running Terminal"`{{execute interrupt}}
76 | 77 | `echo "Send Ctrl+C before running Terminal"`{{execute interrupt}} 78 | 79 | ## Interrupt 80 | 81 | When the user has long running commands, such as `top`{{execute}}, it can be useful to ensure that this is stopped but the user runs the next command. 82 | 83 |
`echo "Send Ctrl+C before running Terminal"`{{execute interrupt}}
84 | 85 | `echo "Send Ctrl+C before running Terminal"`{{execute interrupt}} 86 | 87 | ## Control Sequences 88 | 89 | Alongside the interrupt command above, certain Control Sequences can be sent. 90 | 91 | Given a long running command, like `top`{{execute}}. It can be stopped using Ctrl+C. This can be executed as a control sequence with the command `^C`{{execute ctrl-seq}} 92 | 93 | The markdown for this is: 94 |
 95 | `^C`{{execute ctrl-seq}}
 96 | 
97 | 98 | The use of control sequences can be useful when teaching applications such as `vim`{{execute}}. 99 | 100 | The instructions can guide the user on how 101 | 102 | * Switch to insert mode by typing `i`{{execute no-newline}} 103 | 104 | * Once finished, press ESC (`^ESC`{{execute ctrl-seq}}) to switch back to normal mode 105 | 106 | * To exit, type `:q!`{{execute}} 107 | 108 | In the markdown, you would include: 109 |
110 | `i`{{execute no-newline}}
111 | 
112 | `^ESC`{{execute ctrl-seq}}
113 | 
114 | `:q!`{{execute}}
115 | 
116 | 117 | Notice the use of `no-newline` as a way to send a keystroke with a carriage return following it. 118 | 119 | ## Keyboard Icons 120 | 121 | This can also be helped by using Keyboard symbols to show users to use Ctrl+C 122 | 123 | The Markdown is: 124 |
125 | <kbd>Ctrl</kbd>+<kbd>C</kbd>
126 | 
127 | 128 | 129 | ## Execute on different hosts 130 | 131 | When using the `terminal-terminal` layout and multiple hosts within the cluster, you can have commands executed on which host is required. This is used within our [Kubernetes scenarios](https://www.katacoda.com/courses/kubernetes/getting-started-with-kubeadm). 132 | 133 |
134 | `echo "Run in Terminal Host 1"`{{execute HOST1}}
135 | 
136 | `echo "Run in Terminal Host 2"`{{execute HOST2}}
137 | 
138 | 139 | `echo "Run in Terminal Host 1"`{{execute HOST1}} 140 | 141 | `echo "Run in Terminal Host 2"`{{execute HOST2}} 142 | 143 | ## Execute in different Terminal windows 144 | 145 | When explaining complex systems, it can be useful to run commands in a separate terminal window. This can be run automatically by including the target Terminal number. 146 | 147 | If the terminal is not open, it will launch and the command will be executed. 148 | 149 |
150 | `echo "Run in Terminal 3"`{{execute T3}}
151 | 
152 | `echo "Open and Execute in Terminal 4"`{{execute T4}}
153 | 
154 | 
155 | 156 | `echo "Run in Terminal 3"`{{execute T3}} 157 | 158 | `echo "Open and Execute in Terminal 4"`{{execute T4}} 159 | -------------------------------------------------------------------------------- /profile-pathway.json: -------------------------------------------------------------------------------- 1 | { 2 | "courses": [ 3 | { 4 | "title": "Katacoda UI Layouts Example", 5 | "description": "Example of different Katacoda UI Layouts. Also, an example of creating a Katacoda Course!", 6 | "id": "uilayouts" 7 | }, 8 | { 9 | "title": "Katacoda Environments", 10 | "description": "Example of selective available Katacoda Environments. More examples coming soon!", 11 | "id": "environment-usages" 12 | }, 13 | { 14 | "title": "Katacoda Challenges", 15 | "description": "Examples of how to create Challenges on Katacoda", 16 | "id": "challenges" 17 | } 18 | ], 19 | "scenarios": [ 20 | { 21 | "title": "Creating Your First Katacoda Scenario", 22 | "description": "Learn how to create your first Katacoda scenario", 23 | "id": "create-scenario-101" 24 | }, 25 | { 26 | "title": "Creating a Katacoda Course", 27 | "description": "Learn how to create a collection of Katacoda scenarios into a course", 28 | "id": "create-course" 29 | }, 30 | { 31 | "title": "Markdown Extensions", 32 | "description": "Examples of how the Katacoda Markdown Extensions", 33 | "id": "markdown-extensions" 34 | }, 35 | { 36 | "title": "Katacoda Placeholders for IP addresses and URLs", 37 | "description": "Use Placeholders to dynamically replace values within your scenario content", 38 | "id": "placeholders" 39 | }, 40 | { 41 | "title": "Clipboard Integration", 42 | "description": "Understand how the Katacoda Clipboard integration", 43 | "id": "clipboard" 44 | }, 45 | { 46 | "title": "Interactive Quiz", 47 | "description": "Verify understand and key points by using an interactive quiz", 48 | "id": "quiz" 49 | }, 50 | { 51 | "title": "Run Commands Automatically", 52 | "description": "Automatically run commands in the foreground and background when a scenario starts", 53 | "id": "run-commands-automatically" 54 | }, 55 | { 56 | "title": "Displaying Progress Spinner", 57 | "description": "Display a friendly spinner while long running jobs are completed", 58 | "id": "displaying-progress-spinner" 59 | }, 60 | { 61 | "title": "Verifying user actions during scenario", 62 | "description": "Run checks to make sure the user can proceed. Scenario also offers user solutions if they struggle", 63 | "id": "verified-steps" 64 | }, 65 | { 66 | "title": "Displaying Web UI", 67 | "description": "Display a Web UI running on the environment", 68 | "id": "displaying-web-ui" 69 | }, 70 | { 71 | "title": "Dashboard and Terminal Tabs", 72 | "description": "Add Additional Tabs to the UI", 73 | "id": "dashboard-tabs" 74 | }, 75 | { 76 | "title": "Dashboard and Terminal Tabs (IFrame)", 77 | "description": "Add Additional Tabs to the UI with iFrame integration", 78 | "id": "dashboard-tabs-iframe" 79 | }, 80 | { 81 | "title": "Visualise Environment Tab", 82 | "description": "Learn how to add the Visualise Tab", 83 | "id": "visualise-docker" 84 | }, 85 | { 86 | "title": "Upload File Assets", 87 | "description": "Automatically upload file assets to the environment", 88 | "id": "upload-assets" 89 | }, 90 | { 91 | "title": "Displaying Images", 92 | "description": "Display images as part of the scenario", 93 | "id": "displaying-images" 94 | }, 95 | { 96 | "title": "Embed Videos into Scenarios", 97 | "description": "Learn how to embed YouTube videos into a scenario", 98 | "id": "embed-videos" 99 | }, 100 | { 101 | "title": "Credit where credit due", 102 | "description": "Possible ways to provide credit for the content or ideas within the scenario", 103 | "id": "credit-where-credit-due" 104 | }, 105 | { 106 | "title": "Writing files", 107 | "description": "How to write a file in your scenario", 108 | "id": "writing-files" 109 | }, 110 | { 111 | "title": "Exclusion patterns", 112 | "description": "Exclude files or directories of your scenario", 113 | "id": "exclusion-patterns" 114 | }, 115 | { 116 | "title": "Visual Studio Code - Install extensions", 117 | "description": "Install VS Code extensions using background scripts", 118 | "id": "vscode-extensions" 119 | } 120 | ] 121 | } 122 | --------------------------------------------------------------------------------