diff --git a/autotest/autotest.py b/autotest/autotest.py index dbed5408..de9d237b 100755 --- a/autotest/autotest.py +++ b/autotest/autotest.py @@ -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 "
`" in exercise: - print("! Exercise on slide {} has both ``` and
` 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 "
`" in exercise: - for snippet in re.findall("
`(.*)`", exercise): - self.snippets.append(Snippet(self, snippet)) else: - print(" Exercise on slide {} has neither ``` or
` 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) diff --git a/docs/dashboard.md b/docs/dashboard.md index 3f593de7..21ef54b6 100644 --- a/docs/dashboard.md +++ b/docs/dashboard.md @@ -91,6 +91,8 @@ The goo.gl URL expands to: (You will have to work around the TLS certificate validation warning) + + ] - We have three authentication options at this point: diff --git a/docs/kubectlexpose.md b/docs/kubectlexpose.md index 30dd00dc..1010ca18 100644 --- a/docs/kubectlexpose.md +++ b/docs/kubectlexpose.md @@ -69,6 +69,8 @@ The `LoadBalancer` type is currently only available on AWS, Azure, and GCE. kubectl get pods -w ``` + + ] The `-w` option "watches" events happening on the specified resources. diff --git a/docs/kubectlscale.md b/docs/kubectlscale.md index 6744789c..d3a82786 100644 --- a/docs/kubectlscale.md +++ b/docs/kubectlscale.md @@ -10,6 +10,8 @@ kubectl get deployments -w ``` + + - Now, create more `worker` replicas: ```bash kubectl scale deploy/worker --replicas=10 diff --git a/docs/ourapponkube.md b/docs/ourapponkube.md index 8d3ba86f..bb5b6c75 100644 --- a/docs/ourapponkube.md +++ b/docs/ourapponkube.md @@ -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/) + + ] -- diff --git a/docs/prereqs-k8s.md b/docs/prereqs-k8s.md index 739730ec..428d1ded 100644 --- a/docs/prereqs-k8s.md +++ b/docs/prereqs-k8s.md @@ -65,6 +65,8 @@ class: extra-details - Go to [container.training](http://container.training/) to view these slides - Join the chat room on @@CHAT@@ + + ] --- @@ -73,6 +75,12 @@ class: pic, in-person ![You get five VMs](you-get-five-vms.jpg) + + --- class: in-person @@ -102,11 +110,7 @@ done ``` - Type `exit` or `^D` to come back to node1 - + ] diff --git a/docs/rollout.md b/docs/rollout.md index cbcbd529..4d98fc03 100644 --- a/docs/rollout.md +++ b/docs/rollout.md @@ -79,6 +79,8 @@ kubectl get deployments -w ``` + + - Update `worker` either with `kubectl edit`, or by running: ```bash kubectl set image deploy worker worker=$REGISTRY/worker:$TAG diff --git a/docs/sampleapp.md b/docs/sampleapp.md index 8a43c3c0..aa6fe9d3 100644 --- a/docs/sampleapp.md +++ b/docs/sampleapp.md @@ -264,6 +264,8 @@ class: extra-details - In your browser, you need to enter the IP address of your node + + ] 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) + + +- run `vmstat 1` to see I/O usage (si/so/bi/bo)
(the 4 numbers should be almost zero, except `bo` for logging) + + ] We have available resources.