Skip to content

Commit 9d29dc7

Browse files
authored
chore(examples): add more usage examples (#178)
1 parent be8c6ea commit 9d29dc7

10 files changed

Lines changed: 230 additions & 29 deletions

.ci/docs/generate_command_reference_nav.py renamed to .ci/docs/generate_dynamic_nav.py

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ def withBase(name, base):
88
def parse_name(name):
99
return name.replace('_', ' ').replace('.md', '').replace('index', '')
1010

11-
def generateNav(path, base=''):
11+
def generateCommandsReferenceNav(path, base=''):
1212
pages = []
1313

1414
for i in sorted(os.scandir(path), key=lambda i: parse_name(i.name)):
@@ -17,17 +17,27 @@ def generateNav(path, base=''):
1717
pages.append({withBase(name, base): i.path})
1818
if i.is_dir():
1919
name = i.name.replace('_', ' ')
20-
pages.append({withBase(name, base): generateNav(i.path, base=name.replace('upctl ', ''))})
20+
pages.append({withBase(name, base): generateCommandsReferenceNav(i.path, base=name.replace('upctl ', ''))})
2121

2222
return pages
2323

24+
def generateExamplesNav(path):
25+
return [i.path for i in sorted(os.scandir(path), key=lambda i: i.name) if i.name != 'README.md']
26+
27+
2428
if __name__ == '__main__':
29+
navs = dict()
30+
2531
os.chdir('docs/')
26-
nav = generateNav('commands_reference/')
32+
navs["Commands reference"] = generateCommandsReferenceNav('commands_reference/')
33+
navs["Examples"] = generateExamplesNav('examples/')
2734
os.chdir('..')
2835

2936
with open("mkdocs.base.yaml") as f:
30-
config = f.read().replace('Commands reference: []', f'Commands reference: {nav}')
31-
37+
config = f.read()
38+
39+
for key, nav in navs.items():
40+
config = config.replace(f'{key}: []', f'{key}: {nav}')
41+
3242
with open("mkdocs.yaml", "w") as f:
3343
f.write(config)
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
'''Prepare info texts for mkdocs
2+
3+
This script overwrites code fences in the .md files copied into docs/examples so that only language and title are left in-place, because mkdocs (and the used theme) has limited support for fenced code-block info texts.
4+
'''
5+
import fileinput
6+
import os
7+
import re
8+
import sys
9+
10+
def get_markdown_files(path):
11+
return (f.path for f in os.scandir(path) if f.name.endswith('.md'))
12+
13+
def simplify_info_texts(path):
14+
for line in fileinput.input(path, inplace=True):
15+
if line.startswith('```'):
16+
start = re.search(r'^```[a-zA-Z]*', line)
17+
title = re.search(r'title=".*"', line)
18+
19+
old = line.rstrip('\n')
20+
new = f'{start.group(0)} {title.group(0)}' if title else f'{start.group(0)}'
21+
22+
if new != old:
23+
sys.stderr.write(f'{fileinput.filename()}:{fileinput.filelineno()}:\n- {old}\n+ {new}\n')
24+
print(new)
25+
else:
26+
print(line, end='')
27+
28+
if __name__ == '__main__':
29+
files = get_markdown_files('docs/examples/')
30+
for f in files:
31+
simplify_info_texts(f)

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ dist/
3737

3838
# Generated docs content
3939
/docs/commands_reference/
40+
/docs/examples/
4041
/docs/CHANGELOG.md
4142
/mkdocs.yaml
4243
/site/

Makefile

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,13 @@ build: fmt | $(BIN_DIR) ; $(info building executable for the current target…)
3838
clean-md-docs:
3939
rm -f docs/changelog.md
4040
rm -rf docs/commands_reference/
41+
rm -rf docs/examples/
4142

4243
.PHONY: md-docs
4344
md-docs: clean-md-docs ## Generate documentation (markdown)
4445
$(GO) run ./.ci/docs/
4546
cp CHANGELOG.md docs/changelog.md
47+
cp -r examples/ docs/examples/
4648

4749
.PHONY: clean-docs
4850
clean-docs:
@@ -55,7 +57,8 @@ install-docs-tools:
5557

5658
.PHONY: docs
5759
docs: clean-docs md-docs install-docs-tools ## Generate documentation (mkdocs site)
58-
$(PYTHON) .ci/docs/generate_command_reference_nav.py
60+
$(PYTHON) .ci/docs/generate_dynamic_nav.py
61+
$(PYTHON) .ci/docs/prepare_info_texts_for_mkdocs.py
5962
mkdocs build
6063

6164
.PHONY: build-all

README.md

Lines changed: 2 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -178,30 +178,9 @@ Exit code | Description
178178

179179
## Examples
180180

181-
Every command has a help and examples included and you can find all its options
182-
by adding `-h` at the end of the command, like `upctl network list -h`. Below,
183-
you'll find a few common commands that have many other available options as
184-
well.
181+
Every command has a `--help` parameter that can be used to print detailed usage instructions and examples on how to use the command. For example, run `upctl network list --help`, to display usage instructions and examples for `upctl network list` command.
185182

186-
* Create a new server
187-
188-
```bash
189-
upctl server create --hostname test-server.io --zone de-fra1 --ssh-keys ~/.ssh/id_rsa.pub
190-
```
191-
192-
* Create storage
193-
194-
```bash
195-
upctl storage create --size 25 --title test-storage --zone es-mad1
196-
```
197-
198-
> Note: Storage size is in GB.
199-
200-
* Attach storage to server
201-
202-
```bash
203-
upctl server storage attach <SERVER-UUID> --storage <STORAGE-UUID>
204-
```
183+
See [examples](./examples/) directory for examples on more complex use-cases.
205184

206185
## Documentation
207186

examples/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Examples
2+
3+
This directory contains examples on more complex `upctl` use-cases. As `upctl` is often used in scripts the examples also aim to parse values from machine readable outputs. This allows using the examples also as end-to-end test cases and makes them more copy-pasteable.
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# Create a custom template
2+
3+
This example demonstrates how to create a custom template with `upctl`.
4+
5+
To keep track of resources created during this example, we will use common prefix in all resource names.
6+
7+
```env
8+
prefix=example-upctl-custom-template-
9+
```
10+
11+
First, we will create server which disk will be used as a source for the custom template.
12+
13+
```sh
14+
# Create ssh-key into current working directory
15+
ssh-keygen -t ed25519 -q -f "./id_ed25519" -N ""
16+
17+
upctl server create \
18+
--hostname ${prefix}source-server \
19+
--zone pl-waw1 \
20+
--ssh-keys ./id_ed25519.pub \
21+
--network type=public \
22+
--network type=utility \
23+
--wait
24+
```
25+
26+
After the server has started, you can connect to it and prepare the disk to be templatized. Then, to be able to templatize the storage disk, we will stop the server.
27+
28+
```sh
29+
upctl server stop --type hard --wait ${prefix}source-server
30+
```
31+
32+
The default name for the OS storage of servers created with `upctl` is `${server-title}-OS`, in this case `${prefix}source-server-OS`. We can use either that or the UUID of the storage, when creating the template. UUID of the storage can be printed, for example, by processing `json` output with jq.
33+
34+
```sh
35+
upctl server show ${prefix}source-server -o json \
36+
| jq -r ".storage[0].uuid"
37+
```
38+
39+
Now we are ready for creating the template.
40+
41+
```sh
42+
upctl storage templatise ${prefix}source-server-OS \
43+
--title ${prefix}template \
44+
--wait
45+
```
46+
47+
Once the template is created, we can delete the source server
48+
49+
```sh
50+
upctl server delete ${prefix}source-server --delete-storages
51+
```
52+
53+
To test that the template creation succeeded, create a new server from the just created template.
54+
55+
```sh
56+
upctl server create \
57+
--hostname ${prefix}server \
58+
--zone pl-waw1 \
59+
--network type=public \
60+
--network type=utility \
61+
--os ${prefix}template \
62+
--wait
63+
```
64+
65+
Finally, we can cleanup the created resources.
66+
67+
```sh
68+
upctl server stop --type hard --wait ${prefix}server
69+
upctl server delete ${prefix}server --delete-storages
70+
upctl storage delete ${prefix}template
71+
```
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Create and ssh into a server
2+
3+
This example demonstrates how to create a server with `upctl` and connect to the created server via ssh connection.
4+
5+
To keep track of resources created during this example, we will use common prefix in all resource names.
6+
7+
```env
8+
prefix=example-upctl-ssh-server-
9+
```
10+
11+
In order to be able to connect to the server we are going to create, we will need an ssh-key. If you already have a ssh-key available, you can skip this step. The example creates the ssh-key into the current working directory, if you want to use this key for other authentication purposes as well, create the key into `~/.ssh` directory instead.
12+
13+
```sh
14+
# Create ssh-key into current working directory
15+
ssh-keygen -t ed25519 -q -f "./id_ed25519" -N ""
16+
```
17+
18+
Create a server using the above created ssh-key as login method.
19+
20+
```sh
21+
upctl server create \
22+
--hostname ${prefix}server \
23+
--zone pl-waw1 \
24+
--ssh-keys ./id_ed25519.pub \
25+
--network type=public \
26+
--network type=utility \
27+
--wait
28+
```
29+
30+
Find the IP address of the created server from the JSON output of `upctl server show` and execute hostname command via ssh connection on the created server.
31+
32+
```sh
33+
# Parse public IP of the server with jq
34+
ip=$(upctl server show ${prefix}server -o json | jq -r '.networking.interfaces[] | select(.type == "public") | .ip_addresses[0].address')
35+
36+
# Wait for a moment for the ssh server to become available
37+
sleep 15
38+
39+
ssh -i id_ed25519 -o StrictHostKeyChecking=accept-new root@$ip "hostname"
40+
```
41+
42+
Finally, we can cleanup the created resources.
43+
44+
```sh
45+
upctl server stop --type hard --wait ${prefix}server
46+
upctl server delete ${prefix}server --delete-storages
47+
```

examples/possible_exit_codes.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# Possible exit codes
2+
3+
`upctl` sets exit code based on number of failed tasks up to exit code 99. This example demonstrates executions with few different exit codes.
4+
5+
To keep track of resources created during this example, we will use common prefix in all resource names.
6+
7+
```env
8+
prefix=example-upctl-exit-codes-
9+
```
10+
11+
Exit code 100 is set, for example, when command argument validation fails.
12+
13+
```sh exit_code=100
14+
upctl server create
15+
# Error: required flag(s) "hostname", "zone" not set
16+
```
17+
18+
Let's create two server and stop one of those to later see other failing exit codes. These command should succceed, and thus return zero exit code.
19+
20+
```sh
21+
# Create ssh-key into current working directory
22+
ssh-keygen -t ed25519 -q -f "./id_ed25519" -N ""
23+
24+
upctl server create --hostname ${prefix}vm-1 --zone pl-waw1 --ssh-keys ./id_ed25519.pub --wait
25+
upctl server create --hostname ${prefix}vm-2 --zone pl-waw1 --ssh-keys ./id_ed25519.pub --wait
26+
27+
upctl server stop ${prefix}vm-1 --wait
28+
```
29+
30+
Now let's try to stop both both of the created servers. Exit code will be one, as `${prefix}vm-1` is already stopped and thus cannot be stopped again. `${prefix}vm-2`, though, will be stopped as it was online. Thus one of the two operations failed.
31+
32+
```sh exit_code=1
33+
upctl server stop ${prefix}vm-1 ${prefix}vm-2 --wait
34+
```
35+
36+
If we now try to run above command again, exit code will be two as both of the servers are already stopped. Thus both stop operations failed.
37+
38+
```sh exit_code=2
39+
upctl server stop ${prefix}vm-1 ${prefix}vm-2 --wait
40+
```
41+
42+
Finally, we can cleanup the created resources.
43+
44+
```sh
45+
upctl server delete ${prefix}vm-1 ${prefix}vm-2 --delete-storages
46+
```

mkdocs.base.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ extra_css:
1313
nav:
1414
- index.md
1515
- Commands reference: []
16+
- Examples: []
1617
- changelog.md
1718

1819
theme:
@@ -29,3 +30,12 @@ theme:
2930

3031
plugins:
3132
- search
33+
34+
markdown_extensions:
35+
- pymdownx.highlight:
36+
anchor_linenums: true
37+
line_spans: __span
38+
pygments_lang_class: true
39+
- pymdownx.inlinehilite
40+
- pymdownx.snippets
41+
- pymdownx.superfences

0 commit comments

Comments
 (0)