mirror of
https://github.com/jpetazzo/container.training.git
synced 2026-07-18 12:29:18 +00:00
Improve autotest system
This commit is contained in:
@@ -1,14 +1,21 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
def print_snippet(snippet):
|
||||
print(78*'-')
|
||||
print(snippet)
|
||||
print(78*'-')
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
|
||||
def hrule():
|
||||
return "="*int(os.environ.get("COLUMNS", "80"))
|
||||
|
||||
# A "snippet" is something that the user is supposed to do in the workshop.
|
||||
# Most of the "snippets" are shell commands.
|
||||
# Some of them can be key strokes or other actions.
|
||||
# In the markdown source, they are the code sections (identified by triple-
|
||||
# quotes) within .exercise[] sections.
|
||||
|
||||
class Snippet(object):
|
||||
|
||||
@@ -28,26 +35,22 @@ class Slide(object):
|
||||
def __init__(self, content):
|
||||
Slide.current_slide += 1
|
||||
self.number = Slide.current_slide
|
||||
|
||||
# Remove commented-out slides
|
||||
# (remark.js considers ??? to be the separator for speaker notes)
|
||||
content = re.split("\n\?\?\?\n", content)[0]
|
||||
self.content = content
|
||||
|
||||
self.snippets = []
|
||||
exercises = re.findall("\.exercise\[(.*)\]", content, re.DOTALL)
|
||||
for exercise in exercises:
|
||||
if "```" in exercise and "<br/>`" in exercise:
|
||||
print("! Exercise on slide {} has both ``` and <br/>` delimiters, skipping."
|
||||
.format(self.number))
|
||||
print_snippet(exercise)
|
||||
elif "```" in exercise:
|
||||
if "```" in exercise:
|
||||
for snippet in exercise.split("```")[1::2]:
|
||||
self.snippets.append(Snippet(self, snippet))
|
||||
elif "<br/>`" in exercise:
|
||||
for snippet in re.findall("<br/>`(.*)`", exercise):
|
||||
self.snippets.append(Snippet(self, snippet))
|
||||
else:
|
||||
print(" Exercise on slide {} has neither ``` or <br/>` delimiters, skipping."
|
||||
.format(self.number))
|
||||
logging.warning("Exercise on slide {} does not have any ``` snippet."
|
||||
.format(self.number))
|
||||
self.debug()
|
||||
|
||||
def __str__(self):
|
||||
text = self.content
|
||||
@@ -55,6 +58,9 @@ class Slide(object):
|
||||
text = text.replace(snippet.content, ansi("7")(snippet.content))
|
||||
return text
|
||||
|
||||
def debug(self):
|
||||
logging.debug("\n{}\n{}\n{}".format(hrule(), self.content, hrule()))
|
||||
|
||||
|
||||
def ansi(code):
|
||||
return lambda s: "\x1b[{}m{}\x1b[0m".format(code, s)
|
||||
@@ -64,96 +70,51 @@ content = open(sys.argv[1]).read()
|
||||
for slide in re.split("\n---?\n", content):
|
||||
slides.append(Slide(slide))
|
||||
|
||||
is_editing_file = False
|
||||
placeholders = {}
|
||||
actions = []
|
||||
for slide in slides:
|
||||
for snippet in slide.snippets:
|
||||
content = snippet.content
|
||||
# Multi-line snippets should be ```highlightsyntax...
|
||||
# Single-line snippets will be interpreted as shell commands
|
||||
# Extract the "method" (e.g. bash, keys, ...)
|
||||
# On multi-line snippets, the method is alone on the first line
|
||||
# On single-line snippets, the data follows the method immediately
|
||||
if '\n' in content:
|
||||
highlight, content = content.split('\n', 1)
|
||||
method, data = content.split('\n', 1)
|
||||
else:
|
||||
highlight = "bash"
|
||||
content = content.strip()
|
||||
# If the previous snippet was a file fragment, and the current
|
||||
# snippet is not YAML or EDIT, complain.
|
||||
if is_editing_file and highlight not in ["yaml", "edit"]:
|
||||
print("! On slide {}, previous snippet was YAML, so what do what do?"
|
||||
.format(slide.number))
|
||||
print_snippet(content)
|
||||
is_editing_file = False
|
||||
if highlight == "yaml":
|
||||
is_editing_file = True
|
||||
elif highlight == "placeholder":
|
||||
for line in content.split('\n'):
|
||||
variable, value = line.split(' ', 1)
|
||||
placeholders[variable] = value
|
||||
elif highlight == "bash":
|
||||
for variable, value in placeholders.items():
|
||||
quoted = "`{}`".format(variable)
|
||||
if quoted in content:
|
||||
content = content.replace(quoted, value)
|
||||
del placeholders[variable]
|
||||
if '`' in content:
|
||||
print("! The following snippet on slide {} contains a backtick:"
|
||||
.format(slide.number))
|
||||
print_snippet(content)
|
||||
continue
|
||||
print("_ "+content)
|
||||
snippet.actions.append((highlight, content))
|
||||
elif highlight == "edit":
|
||||
print(". "+content)
|
||||
snippet.actions.append((highlight, content))
|
||||
elif highlight == "meta":
|
||||
print("^ "+content)
|
||||
snippet.actions.append((highlight, content))
|
||||
elif highlight == "keys":
|
||||
print("K "+content)
|
||||
snippet.actions.append((highlight, content))
|
||||
else:
|
||||
print("! Unknown highlight {!r} on slide {}.".format(highlight, slide.number))
|
||||
if placeholders:
|
||||
print("! Remaining placeholder values: {}".format(placeholders))
|
||||
method, data = content.split(' ', 1)
|
||||
actions.append((slide, snippet, method, data))
|
||||
|
||||
actions = sum([snippet.actions for snippet in sum([slide.snippets for slide in slides], [])], [])
|
||||
|
||||
# Strip ^{ ... ^} for now
|
||||
def strip_curly_braces(actions, in_braces=False):
|
||||
if actions == []:
|
||||
return []
|
||||
elif actions[0] == ("meta", "^{"):
|
||||
return strip_curly_braces(actions[1:], True)
|
||||
elif actions[0] == ("meta", "^}"):
|
||||
return strip_curly_braces(actions[1:], False)
|
||||
elif in_braces:
|
||||
return strip_curly_braces(actions[1:], True)
|
||||
else:
|
||||
return [actions[0]] + strip_curly_braces(actions[1:], False)
|
||||
|
||||
actions = strip_curly_braces(actions)
|
||||
|
||||
try:
|
||||
i = int(open("nextstep").read())
|
||||
logging.info("Loaded next step ({}) from file.".format(i))
|
||||
except Exception as e:
|
||||
print("Could not read nextstep file ({}), initializing to 0.".format(e))
|
||||
logging.warning("Could not read nextstep file ({}), initializing to 0.".format(e))
|
||||
i = 0
|
||||
|
||||
|
||||
keymaps = { "^C": "\x03" }
|
||||
|
||||
while True:
|
||||
with open("nextstep","w") as f:
|
||||
f.write(str(i))
|
||||
typ, cmd = actions[i]
|
||||
print_snippet(cmd)
|
||||
print("i={} shall we execute the snippet above with {}?".format(i, typ))
|
||||
slide, snippet, method, data = actions[i]
|
||||
data = data.strip()
|
||||
print(hrule())
|
||||
print(slide.content.replace(snippet.content, ansi(7)(snippet.content)))
|
||||
print(hrule())
|
||||
print("[{}] Shall we execute that snippet above?".format(i))
|
||||
command = raw_input()
|
||||
if command == "":
|
||||
if typ in ["bash", "keys"]:
|
||||
if typ=="keys" and cmd=="^C":
|
||||
print("^C detected")
|
||||
cmd="\x03"
|
||||
subprocess.check_call(["tmux", "send-keys", "{}\n".format(cmd)])
|
||||
if method=="keys" and data in keymaps:
|
||||
print("Mapping {!r} to {!r}.".format(data, keymaps[data]))
|
||||
data = keymaps[data]
|
||||
if method in ["bash", "keys"]:
|
||||
data = re.sub("\n +", "\n", data)
|
||||
if method == "bash":
|
||||
data += "\n"
|
||||
subprocess.check_call(["tmux", "send-keys", "{}".format(data)])
|
||||
else:
|
||||
print "DO NOT KNOW HOW TO HANDLE", typ, cmd
|
||||
print "DO NOT KNOW HOW TO HANDLE {} {!r}".format(method, data)
|
||||
i += 1
|
||||
elif command.isdigit():
|
||||
i = int(command)
|
||||
|
||||
@@ -91,6 +91,8 @@ The goo.gl URL expands to:
|
||||
|
||||
(You will have to work around the TLS certificate validation warning)
|
||||
|
||||
<!-- ```open https://node1:3xxxx/``` -->
|
||||
|
||||
]
|
||||
|
||||
- We have three authentication options at this point:
|
||||
|
||||
@@ -69,6 +69,8 @@ The `LoadBalancer` type is currently only available on AWS, Azure, and GCE.
|
||||
kubectl get pods -w
|
||||
```
|
||||
|
||||
<!-- ```keys ^C``` -->
|
||||
|
||||
]
|
||||
|
||||
The `-w` option "watches" events happening on the specified resources.
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
kubectl get deployments -w
|
||||
```
|
||||
|
||||
<!-- ```keys ^C``` -->
|
||||
|
||||
- Now, create more `worker` replicas:
|
||||
```bash
|
||||
kubectl scale deploy/worker --replicas=10
|
||||
|
||||
@@ -348,6 +348,8 @@ We should now see the `worker`, well, working happily.
|
||||
|
||||
- Open the web UI in your browser (http://node-ip-address:3xxxx/)
|
||||
|
||||
<!-- ```open http://node1:3xxxx/``` -->
|
||||
|
||||
]
|
||||
|
||||
--
|
||||
|
||||
@@ -65,6 +65,8 @@ class: extra-details
|
||||
- Go to [container.training](http://container.training/) to view these slides
|
||||
- Join the chat room on @@CHAT@@
|
||||
|
||||
<!-- ```open http://container.training/``` -->
|
||||
|
||||
]
|
||||
|
||||
---
|
||||
@@ -73,6 +75,12 @@ class: pic, in-person
|
||||
|
||||

|
||||
|
||||
<!--
|
||||
```bash
|
||||
kubectl get all -o name | grep -v services/kubernetes | xargs -n1 kubectl delete
|
||||
```
|
||||
-->
|
||||
|
||||
---
|
||||
|
||||
class: in-person
|
||||
@@ -102,11 +110,7 @@ done
|
||||
```
|
||||
- Type `exit` or `^D` to come back to node1
|
||||
|
||||
<!--
|
||||
```keys
|
||||
exit
|
||||
```
|
||||
-->
|
||||
<!-- ```keys exit``` -->
|
||||
|
||||
]
|
||||
|
||||
|
||||
@@ -79,6 +79,8 @@
|
||||
kubectl get deployments -w
|
||||
```
|
||||
|
||||
<!-- ```keys ^C``` -->
|
||||
|
||||
- Update `worker` either with `kubectl edit`, or by running:
|
||||
```bash
|
||||
kubectl set image deploy worker worker=$REGISTRY/worker:$TAG
|
||||
|
||||
@@ -264,6 +264,8 @@ class: extra-details
|
||||
|
||||
- In your browser, you need to enter the IP address of your node
|
||||
|
||||
<!-- ```open http://node1:8000``` -->
|
||||
|
||||
]
|
||||
|
||||
You should see a speed of approximately 4 hashes/second.
|
||||
@@ -316,9 +318,25 @@ class: extra-details
|
||||
|
||||
- run `top` to see CPU and memory usage (you should see idle cycles)
|
||||
|
||||
- run `vmstat 3` to see I/O usage (si/so/bi/bo)
|
||||
<!--
|
||||
```bash
|
||||
top
|
||||
```
|
||||
|
||||
```keys ^C```
|
||||
-->
|
||||
|
||||
- run `vmstat 1` to see I/O usage (si/so/bi/bo)
|
||||
<br/>(the 4 numbers should be almost zero, except `bo` for logging)
|
||||
|
||||
<!--
|
||||
```bash
|
||||
vmstat 1
|
||||
```
|
||||
|
||||
```keys ^C```
|
||||
-->
|
||||
|
||||
]
|
||||
|
||||
We have available resources.
|
||||
|
||||
Reference in New Issue
Block a user