Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor quarkus getting started #232

Merged
merged 1 commit into from
Jan 30, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
239 changes: 84 additions & 155 deletions docs/tutorial/quarkusgetstarted.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -15,217 +15,148 @@ This tutorial will walk through downloading and building one of the quarkus gett

qDup connects to computers through ssh. You need to have a computer that will accept ssh connections. You can setup ssh on your own computer by following the steps in the link:./prerequisites.adoc[prerequisites]

Remember the username and hostname for your setup and use them in the `hosts` section of the qDup yaml
== Getting started

== Getting started with Getting started
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe Scripting Quarkus getting started ?

We are going to use the link:https://quarkus.io/guides/getting-started[Quarkus getting started] project. The best practice is to open a terminal and test each command to get familiar with the input and output. We normally run commands in terminal before adding them to a qDup script to see how the commands behave.
willr3 marked this conversation as resolved.
Show resolved Hide resolved

We are going to use the link:https://quarkus.io/guides/getting-started[Quarkus getting started] project to substitute for our application. We follow the steps in their guide the same way we would follow the README for other applications. The best practice is to open a terminal and test each command to get familiar with the output. Start with the first command in the README.

```
git clone https://github.com/quarkusio/quarkus-quickstarts.git
```
The first README step clones the example repository. We create a qDup script with the same step, but our script will first cd to the `tmp` directory.
```yaml
#> cat <<EOF > quarkus.yaml
scripts:
test-endpoint:
- wait-for: ready
then:
- sh: curl localhost:8080/hello
- signal: done #tells qDup that the "testing" is done
ensure-quarkus-cli:
- sh: quarkus version #to see if the command exists
then:
- regex: "command not found"
then: #install quarkus by following: https://quarkus.io/get-started/
- sh: "curl -Ls https://sh.jbang.dev | bash -s - trust add https://repo1.maven.org/maven2/io/quarkus/quarkus-cli/"
- sh: "curl -Ls https://sh.jbang.dev | bash -s - app install --fresh --force quarkus@quarkusio"
- sh: "source ~/.bashrc" # jbang change your environment if you don't have jbang in the PATH
getting-started:
- sh: cd /tmp/
- sh: git clone https://github.com/quarkusio/quarkus-quickstarts.git
- sh: "[[ ! -d quarkus-quickstarts ]] && git clone https://github.com/quarkusio/quarkus-quickstarts.git" # prevent cloning again
- sh: cd quarkus-quickstarts
- sh: cd getting-started
- script: ensure-quarkus-cli
- sh:
command: quarkus dev
prompt:
"Press [e] to edit command line args (currently ''), [r] to resume testing, [o] Toggle test output, [:] for the terminal, [h] for more options>": "r"
timer:
2m: #a short timeout
- abort: quarkus dev did not exit before the timer expired
watch:
- regex: "Tests completed"
then:
- signal: ready
on-signal:
done:
- ctrlC #exits the process
hosts:
test: me@localhost #replace this with your ssh username@hostname
test: $USER@localhost
roles:
example:
setup-env:
hosts:
- test
run-scripts:
- getting-started
- test-endpoint
EOF
```

Create a `qdup.yaml` script file with the above yaml and run it using qDup
Run with `java -jar qDup-0.8.5-uber.jar -i ~/.ssh/qdup quarkus.yaml -ix`. It will take some time and in the end you will see:
willr3 marked this conversation as resolved.
Show resolved Hide resolved
```
java -jar qdup-uber.jar qdup.yaml
All 2 tests are passing (0 skipped), 2 tests were run in 4289ms. Tests completed at 13:34:11.
Press [e] to edit command line args (currently ''), [r] to re-run, [o] Toggle test output, [:] for the terminal, [h] for more options>
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 17.915 s
[INFO] Finished at: 2025-01-09T13:34:12-03:00
[INFO] ------------------------------------------------------------------------
Finished in 31.238 at /tmp/20250109_133335
```
It means that the qDup script worked fine and finished in 31 seconds.

The quarkus guide next talks about creating our own project using the `quarkus` cli. We are going to skip ahead and use the `getting-started` project. Remember to run the `cd getting-started` in the terminal too. Walking through each step in a terminal while writing the script prevents most errors related to unexpected output.
=== Checkout project

```yaml
scripts:
getting-started:
- sh: cd /tmp/
- sh: git clone https://github.com/quarkusio/quarkus-quickstarts.git
- sh: cd quarkus-quickstarts
- sh: cd getting-started
```
Change directory to `/tmp` and clone the repository if `quarkus-quickstarts` doesn't exist. Change directory to `quarkus-quickstarts` and then to `getting-started`

If you add the `sh: cd getting-started` to `qdup.yaml` and run it again you will likely see an error message from `git clone` complaining that the directory already exists. We normally remove the existing folder, if it exists, with some bash conditionals
```yaml:
- sh: "[[-d quarkus-quickstarts ]] && rm -rf quarkus-quickstarts"
```
We do not want to download the full git repo after each change to our script. We will instead only run git clone if the directory does not exist
```yaml
scripts:
getting-started:
- sh: cd /tmp/
- sh: "[[ ! -d quarkus-quickstarts ]] && git clone https://github.com/quarkusio/quarkus-quickstarts.git"
- sh: cd quarkus-quickstarts
- sh: cd getting-started
```

The next command in the getting started guide is to run `quarkus dev`. Try running it in a terminal; it will likely result in `command not found`. We need to ensure we have the quarkus cli installed. It is good practice to split this into a separate script (e.g. `ensure-quarkus-cli`) and follow the steps for installing the cli. Run each step in a terminal then add them to the script after you have an expectation for the output.
=== Install `quarkus` if needed

Once `quarkus dev` runs you will have a script that looks like the yaml below but if you run it the script will hang.
Call the `qDup` `ensure-quarkus-cli` script.

```yaml
scripts:
ensure-quarkus-cli:
- sh: quarkus version #to see if the command exists
then:
- regex: command not found
then: #https://quarkus.io/get-started/
- sh: "curl -Ls https://sh.jbang.dev | bash -s - trust add https://repo1.maven.org/maven2/io/quarkus/quarkus-cli/"
- sh: "curl -Ls https://sh.jbang.dev | bash -s - app install --fresh --force quarkus@quarkusio"
getting-started:
- sh: cd /tmp/
- sh: "[[ ! -d quarkus-quickstarts ]] && git clone https://github.com/quarkusio/quarkus-quickstarts.git"
- sh: cd quarkus-quickstarts
- sh: cd getting-started
- script: ensure-quarkus-cli
- sh: quarkus dev
- script: ensure-quarkus-cli
```

Run `quarkus dev` in a terminal from the `/tmp/quarkus-quickstarts/getting-started` folder. We normally run commands in terminal before adding them to a qDup script to see how the commands behave. In this case, `quarkus dev` is interactive and expects user input.
Call `quarkus version` command and if the command has an output that matches `command not found`, then install `quarkus` using `jbang`

```
Tests paused
Press [r] to resume testing, [o] Toggle test output, [:] for the terminal, [h] for more options>
```
The execution pauses waiting for an `r` to run the unit tests. It also does not wait for input on a new line. This means we should use `sh` with `prompt` to respond to the message. The `prompt` looks for a set of characters from the ssh connection and sends the associated response if it finds those characters. Using `prompt` means we have to use the yaml mapping syntax for `sh`. Most qdup commands support a simplified string format (e.g. `sh: "./runScript.sh"`) but also a more complex mapping that includes options that are not always needed:
```yaml
- sh:
command: quarkus dev
prompt:
"Press [r] to resume testing, [o] Toggle test output, [:] for the terminal, [h] for more options>": "r"
ensure-quarkus-cli:
- sh: quarkus version
then:
- regex: "command not found"
then:
- sh: "curl -Ls https://sh.jbang.dev | bash -s - trust add https://repo1.maven.org/maven2/io/quarkus/quarkus-cli/"
- sh: "curl -Ls https://sh.jbang.dev | bash -s - app install --fresh --force quarkus@quarkusio"
- sh: "source ~/.bashrc"
```

The above `sh` command responds to the quarkus prompt and runs the test but `quarkus dev` does not exit, and we want to test the endpoints while the process is running. We can start another script in `run-scripts` that will test an endpoint with a `curl` but we have to add coordination to ensure the script does not start testing before the process is ready.
=== prompt

Let's call our new script `test-endpoint` and use a signal named `ready` to coordinate the two scripts. First, we create our `test-endpoint` script that will `curl` the endpoint after quarkus is ready.
`quarkus dev` is interactive and expects user input. When the output matches `Press [e] to edit command line args (currently ''), [r] to resume testing, [o] Toggle test output, [:] for the terminal, [h] for more options>` we simulate pressing the letter `r`. This will run the test but `quarkus dev` does not exit, and we want to test the endpoints while the process is running. When the output has `Tests completed`, send the link:./../reference/command/signal.adoc[signal] `ready`.

```yaml
sripts:
test-endpoint:
- wait-for: ready
then:
- sh: curl localhost:8080/hello #replace localhost if you used a different ssh computer name
```
The `test-endpoint` script is ready; now we need to `signal` when `quarkus dev` is ready to receive requests. The `Tests paused` message from before the prompt occurs is an excellent option. We can `watch` the output and `regex: Test paused` to `signal` when quarkus is ready. The new `getting-started` scripts will now look like the following:
```yaml
scripts:
getting-started:
- sh: cd /tmp/
- sh: "[[ ! -d quarkus-quickstarts ]] && git clone https://github.com/quarkusio/quarkus-quickstarts.git"
- sh: cd quarkus-quickstarts
- sh: cd getting-started
- script: ensure-quarkus-cli
- sh:
command: quarkus dev
prompt:
"Press [r] to resume testing, [o] Toggle test output, [:] for the terminal, [h] for more options>": "r"
"Press [e] to edit command line args (currently ''), [r] to resume testing, [o] Toggle test output, [:] for the terminal, [h] for more options>": "r"
watch:
- regex: "Test paused"
- regex: "Tests completed"
then:
- signal: ready
```

Our full qDup script now looks like the following:
```yaml
scripts:
test-endpoint:
- wait-for: ready
then:
- sh: curl localhost:8080/hello #replace localhost if you used a differnet ssh computer name

ensure-quarkus-cli:
- sh: which quarkus
then:
- regex: no quarkus
then: #https://quarkus.io/get-started/
- sh: "curl -Ls https://sh.jbang.dev | bash -s - trust add https://repo1.maven.org/maven2/io/quarkus/quarkus-cli/"
- sh: "curl -Ls https://sh.jbang.dev | bash -s - app install --fresh --force quarkus@quarkusio"

getting-started:
- sh: cd /tmp/
- sh: "[[ ! -d quarkus-quickstarts ]] && git clone https://github.com/quarkusio/quarkus-quickstarts.git"
- sh: cd quarkus-quickstarts
- sh: cd getting-started
- script: ensure-quarkus-cli
- sh:
command: quarkus dev
prompt:
"Press [r] to resume testing, [o] Toggle test output, [:] for the terminal, [h] for more options>": "r"
watch:
- regex: "Tests paused"
then:
- signal: ready
=== Wait for `ready`

hosts:
test: me@localhost #replace this with your ssh username@hostname
roles:
example:
hosts:
- test
run-scripts:
- test-endpoint
- getting-started
```
When the `qDup` script `test-endpoint` receives the `ready` signal, call the endpoint and send the link:./../reference/command/signal.adoc[signal] `done`

If you run this you will see the curl output in the qDup console but qDup will not exit because the `quarkus dev` is still running. We need the `test-endoint` script to tell the `getting-started` script when it finished "testing" ( running `curl`) so that the script can end the `quarkus dev` command. We accomplish this with a signal from `test-endoint` that indicates the testing is `done` and we add an `on-signal` to the `sh: quarkus dev`. The new complete script should look like the following:
The curl output will show the output in the qDup console but qDup will not exit because the `quarkus dev` is still running.

```yaml
scripts:
test-endpoint:
- wait-for: ready
then:
- sh: curl localhost:8080/hello #replace localhost if you used a different ssh computer name
- signal: done #tells qDup that the "testing" is done
- sh: curl localhost:8080/hello
- signal: done
```

ensure-quarkus-cli:
- sh: which quarkus
then:
- regex: no quarkus
then: #https://quarkus.io/get-started/
- sh: "curl -Ls https://sh.jbang.dev | bash -s - trust add https://repo1.maven.org/maven2/io/quarkus/quarkus-cli/"
- sh: "curl -Ls https://sh.jbang.dev | bash -s - app install --fresh --force quarkus@quarkusio"
=== Wait for `done`

getting-started:
- sh: cd /tmp/
- sh: "[[ ! -d quarkus-quickstarts ]] && git clone https://github.com/quarkusio/quarkus-quickstarts.git"
- sh: cd quarkus-quickstarts
- sh: cd getting-started
- script: ensure-quarkus-cli
- sh:
command: quarkus dev
prompt:
"Press [r] to resume testing, [o] Toggle test output, [:] for the terminal, [h] for more options>": "r"
watch:
- regex: "Tests paused"
then:
- signal: ready
When the `qDup` script receives the `done` signal, send the `SIGINT` link:https://man7.org/linux/man-pages/man7/signal.7.html[POSIX] signal. This will stop the `quarkus dev` command and exit the `qDup` script.

```yaml
on-signal:
done:
- ctrlC #exits the process

hosts:
test: me@localhost #replace this with your ssh username@hostname
roles:
example:
hosts:
- test
run-scripts:
- test-endpoint
- getting-started
- ctrlC
```

=== Ignoring exit codes
If you rerun the script, it will fail because you have `quarkus-quickstarts` folder. In order to workaround that, we add the command `[[ ! -d quarkus-quickstarts ]] && git clone https://github.com/quarkusio/quarkus-quickstarts`. The command will have the exit code `0` if the folder doesn't exist. If the folder exists, the command will exit with code `1`. The `-ix` flag is added to the command line above to ignore individual status code checks for simplicity. However, in a production environment, your bash scripts should be designed to return an exit code of `0`.

== Troubleshooting

Some of you may find the qDup process is still stuck and you are not seeing `curl` in the logs. This usually happens when `quarkus dev` does not log `Tests paused` because it had an issue starting. qDup has an internal web server that exposes diagnostics data. We can get the active commands with:
```
curl localhost:31337/active
Expand All @@ -234,16 +165,14 @@ If you see `quarkus dev` as an active command then check the `output` for an err
We don't want our qDup scripts getting stuck in our automated environment. We add a `timer` to any `sh` commands that do not automatically exit. This forces a limit on execution time and alerts us to errors.

```yaml
- sh:
command: "quarkus dev"
timer:
2m: #a short timeout
2m:
- abort: quarkus dev did not exit before the timer expired
```

== Next

At this point you know how to write a script and how to work with `sh` commands that prompt and do not automatically exit. Next we will explore using `setup-scripts` and `cleaup-scripts` and how to work with commands that package their own cli by using hyperfoil to load test the getting-started application
At this point you know how to write a script and how to work with `sh` commands that prompt and do not automatically exit. Next we will explore using `setup-scripts` and `cleaup-scripts` and how to work with commands that package their own cli by using link:./hyperfoil.adoc[hyperfoil] to load test the getting-started application



Expand Down
Loading