diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index db00f3c..ca8214b 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -35,11 +35,7 @@ jobs: - uses: actions/setup-python@v5 with: python-version: "3.x" - - uses: manusa/actions-setup-minikube@v2.10.0 - with: - minikube version: "v1.32.0" - kubernetes version: "v1.29.0" - github token: ${{secrets.GITHUB_TOKEN}} + - uses: medyagh/setup-minikube@latest - run: curl https://skupper.io/install.sh | bash -s -- --version ${{matrix.skupper-version}} - run: echo "$HOME/.local/bin" >> "$GITHUB_PATH" - run: ./plano test diff --git a/README.md b/README.md index 2fa1429..db60b79 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ + + # Skupper Hello World public to private [![main](https://github.com/skupperproject/skupper-example-public-to-private/actions/workflows/main.yaml/badge.svg)](https://github.com/skupperproject/skupper-example-public-to-private/actions/workflows/main.yaml) @@ -16,14 +18,13 @@ across cloud providers, data centers, and edge sites. * [Overview](#overview) * [Prerequisites](#prerequisites) * [Step 1: Install the Skupper command-line tool](#step-1-install-the-skupper-command-line-tool) -* [Step 2: Set up your namespaces](#step-2-set-up-your-namespaces) +* [Step 2: Set up your clusters](#step-2-set-up-your-clusters) * [Step 3: Deploy the frontend and backend](#step-3-deploy-the-frontend-and-backend) * [Step 4: Create your sites](#step-4-create-your-sites) * [Step 5: Link your sites](#step-5-link-your-sites) * [Step 6: Expose the backend](#step-6-expose-the-backend) * [Step 7: Access the frontend](#step-7-access-the-frontend) * [Cleaning up](#cleaning-up) -* [Summary](#summary) * [Next steps](#next-steps) * [About this example](#about-this-example) @@ -82,12 +83,12 @@ Skupper][install-docs]. [install-script]: https://github.com/skupperproject/skupper-website/blob/main/input/install.sh [install-docs]: https://skupper.io/install/ -## Step 2: Set up your namespaces +## Step 2: Set up your clusters -Skupper is designed for use with multiple Kubernetes namespaces, -usually on different clusters. The `skupper` and `kubectl` -commands use your [kubeconfig][kubeconfig] and current context to -select the namespace where they operate. +Skupper is designed for use with multiple Kubernetes clusters. +The `skupper` and `kubectl` commands use your +[kubeconfig][kubeconfig] and current context to select the cluster +and namespace where they operate. [kubeconfig]: https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/ @@ -137,9 +138,8 @@ kubectl config set-context --current --namespace private This example runs the frontend and the backend in separate Kubernetes namespaces, on different clusters. -Use `kubectl create deployment` to deploy the frontend in -namespace `public` and the backend in namespace -`private`. +Use `kubectl create deployment` to deploy the frontend in Public +and the backend in Private. _**Public:**_ @@ -229,9 +229,9 @@ that generated it. token can link to your site. Make sure that only those you trust have access to it. -First, use `skupper token create` in site Public to generate the -token. Then, use `skupper link create` in site Private to link -the sites. +First, use `skupper token create` in Public to generate the +token. Then, use `skupper link create` in Private to link the +sites. _**Public:**_ @@ -293,43 +293,17 @@ deployment backend exposed as backend In order to use and test the application, we need external access to the frontend. -Use `kubectl expose` with `--type LoadBalancer` to open network -access to the frontend service. - -Once the frontend is exposed, use `kubectl get service/frontend` -to look up the external IP of the frontend service. If the -external IP is ``, try again after a moment. - -Once you have the external IP, use `curl` or a similar tool to -request the `/api/health` endpoint at that address. - -**Note:** The `` field in the following commands is a -placeholder. The actual value is an IP address. +Use `kubectl port-forward` to make the frontend available at +`localhost:8080`. _**Public:**_ ~~~ shell -kubectl expose deployment/frontend --port 8080 --type LoadBalancer -kubectl get service/frontend -curl http://:8080/api/health -~~~ - -_Sample output:_ - -~~~ console -$ kubectl expose deployment/frontend --port 8080 --type LoadBalancer -service/frontend exposed - -$ kubectl get service/frontend -NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE -frontend LoadBalancer 10.103.232.28 8080:30407/TCP 15s - -$ curl http://:8080/api/health -OK +kubectl port-forward deployment/frontend 8080:8080 ~~~ -If everything is in order, you can now access the web interface by -navigating to `http://:8080/` in your browser. +You can now access the web interface by navigating to +[http://localhost:8080](http://localhost:8080) in your browser. ## Cleaning up @@ -340,7 +314,6 @@ _**Public:**_ ~~~ shell skupper delete -kubectl delete service/frontend kubectl delete deployment/frontend ~~~ diff --git a/external/skewer/.github/workflows/main.yaml b/external/skewer/.github/workflows/main.yaml index 09e2b58..cdcf5a7 100644 --- a/external/skewer/.github/workflows/main.yaml +++ b/external/skewer/.github/workflows/main.yaml @@ -16,11 +16,7 @@ jobs: - uses: actions/setup-python@v5 with: python-version: "3.x" - - uses: manusa/actions-setup-minikube@v2.10.0 - with: - minikube version: "v1.32.0" - kubernetes version: "v1.29.0" - github token: ${{secrets.GITHUB_TOKEN}} + - uses: medyagh/setup-minikube@latest - run: curl https://skupper.io/install.sh | bash -s -- --version ${{matrix.skupper-version}} - run: echo "$HOME/.local/bin" >> $GITHUB_PATH - run: ./plano test diff --git a/external/skewer/README.md b/external/skewer/README.md index d1a94e4..039fa6b 100644 --- a/external/skewer/README.md +++ b/external/skewer/README.md @@ -8,6 +8,15 @@ A `skewer.yaml` file describes the steps and commands to achieve an objective using Skupper. Skewer takes the `skewer.yaml` file as input and produces two outputs: a `README.md` file and a test routine. +#### Contents + +* [An example example](#an-example-example) +* [Setting up Skewer for your own example](#setting-up-skewer-for-your-own-example) +* [Skewer YAML](#skewer-yaml) +* [Standard steps](#standard-steps) +* [Demo mode](#demo-mode) +* [Troubleshooting](#troubleshooting) + ## An example example [Example `skewer.yaml` file](example/skewer.yaml) @@ -89,7 +98,7 @@ commands: ## Skewer YAML -The top level: +The top level of the `skewer.yaml` file: ~~~ yaml title: # Your example's title (required) @@ -103,7 +112,18 @@ summary: # Text to summarize what the user did (optional) next_steps: # Text linking to more examples (optional, has default text) ~~~ -To disable the GitHub workflow, set it to `null`. +For fields with default text such as `prerequisites` and `next_steps`, +you can include the default text inside your custom text by using the +`@default@` placeholder: + +~~~ yaml +next_steps: + @default@ + + This Way to the Egress. +~~~ + +To disable the GitHub workflow and CI badge, set `workflow` to `null`. A **site**: @@ -167,77 +187,25 @@ steps: west: ~~~ -Or you can use a named step from the library of standard steps: - -~~~ yaml -- standard: configure_separate_console_sessions -~~~ - -The standard steps are defined in -[python/skewer/standardsteps.yaml](python/skewer/standardsteps.yaml). -Note that you should not edit this file. Instead, in your -`skewer.yaml` file, you can create custom steps based on the standard -steps. You can override the `title`, `preamble`, `commands`, or -`postamble` field of a standard step by adding the field in addition -to `standard`: - -~~~ yaml -- standard: cleaning_up - commands: - east: - - run: skupper delete - - run: kubectl delete deployment/database - west: - - run: skupper delete -~~~ - -A typical mix of standard and custom steps might look like this: - -~~~ yaml -steps: - - standard: install_the_skupper_command_line_tool - - standard: kubernetes/set_up_your_namespaces - - - standard: kubernetes/create_your_sites - - standard: kubernetes/link_your_sites - - - - standard: cleaning_up -~~~ - -**Note:** The `link_your_sites` and `cleaning_up` steps are less -generic than the other steps. For example, `cleaning_up` doesn't -delete any application workoads. Check that the text and commands -these steps produce are doing what you need for your example. If not, -you need to provide a custom step. - -There are some standard steps for examples based on the Skupper -Hello World application: - -~~~ yaml -- standard: hello_world/deploy_the_frontend_and_backend -- standard: hello_world/expose_the_backend -- standard: hello_world/access_the_frontend -- standard: hello_world/cleaning_up -~~~ - -And finally there are some special cases: -~~~ yaml -- standard: kubernetes/set_up_your_kubernetes_namespace -- standard: podman/set_up_your_podman_network -~~~ - The step commands are separated into named groups corresponding to the sites. Each named group contains a list of command entries. Each command entry has a `run` field containing a shell command and other fields for awaiting completion or providing sample output. +You can also use a named step from the library of [standard +steps](#standard-steps): + +~~~ yaml +- standard: kubernetes/set_up_your_clusters +~~~ + A **command**: ~~~ yaml - run: # A shell command (required) - apply: # Use this command only for "readme" or "test" (optional, default is both) + apply: # Use this command only for "readme" or "test" (default is both) output: # Sample output to include in the README (optional) + expect_failure: # If true, check that the command fails and keep going (default false) ~~~ Only the `run` and `output` fields are used in the README content. @@ -277,6 +245,83 @@ commands: backend ClusterIP 10.102.112.121 8080/TCP 30s ~~~ +## Standard steps + +Skewer includes a library of standard steps with descriptive text and +commands that we use a lot for our examples. + +The standard steps are defined in +[python/skewer/standardsteps.yaml](python/skewer/standardsteps.yaml). +They are the following: + +~~~ +general/install_the_skupper_command_line_tool +general/link_your_sites +general/cleaning_up +kubernetes/set_up_your_clusters +kubernetes/set_up_your_kubernetes_cluster # One cluster only +kubernetes/create_your_sites +kubernetes/link_your_sites +kubernetes/access_the_frontend +kubernetes/cleaning_up +podman/set_up_your_podman_environment +hello_world/deploy_the_frontend_and_backend +hello_world/expose_the_backend +hello_world/access_the_frontend +hello_world/cleaning_up +~~~ + +The `general` steps are generic (or pretty generic) with respect to +platform and application. The `kubernetes` and `podman` steps are +coupled to their platform. The `hello_world` steps are specific to +the Skupper Hello World application. + +**Note:** The `link_your_sites` and `cleaning_up` steps are less +generic than the other `general` steps. For example, `cleaning_up` +doesn't delete any application workoads. Check that the text and +commands these steps produce are doing what you need for your example. +If not, you need to provide a custom step. + +You can create custom steps based on the standard steps by overriding +the `title`, `preamble`, `commands`, or `postamble` fields. + +~~~ yaml +- standard: kubernetes/cleaning_up + commands: + east: + - run: skupper delete + - run: kubectl delete deployment/database + west: + - run: skupper delete +~~~ + +For string fields such as `preamble` and `postamble`, you can include +the standard text inside your custom text by using the `@default@` +placeholder: + +~~~ yaml +- standard: general/cleaning_up + preamble: | + @default@ + + Note: You may also want to flirp your krupke. +~~~ + +A typical mix of standard and custom steps for a Kubernetes-based +example might look like this: + +~~~ yaml +steps: + - standard: general/install_the_skupper_command_line_tool + - standard: kubernetes/set_up_your_clusters + + - standard: kubernetes/create_your_sites + - standard: kubernetes/link_your_sites + + + - standard: kubernetes/cleaning_up +~~~ + ## Demo mode Skewer has a mode where it executes all the steps, but before cleaning @@ -285,3 +330,24 @@ up and exiting, it pauses so you can inspect things. It is enabled by setting the environment variable `SKEWER_DEMO` to any value when you call `./plano run` or one of its variants. You can also use `./plano demo`, which sets the variable for you. + +## Troubleshooting + +### Subnet is already used + +Error: + +~~~ console +plano: notice: Starting Minikube +plano: notice: Running command 'minikube start -p skewer --auto-update-drivers false' +* Creating podman container (CPUs=2, Memory=16000MB) ...- E0229 05:44:29.821273 12224 network_create.go:113] error while trying to create podman network skewer 192.168.49.0/24: create podman network skewer 192.168.49.0/24 with gateway 192.168.49.1 and MTU of 0: sudo -n podman network create --driver=bridge --subnet=192.168.49.0/24 --gateway=192.168.49.1 --label=created_by.minikube.sigs.k8s.io=true --label=name.minikube.sigs.k8s.io=skewer skewer: exit status 125 + +Error: subnet 192.168.49.0/24 is already used on the host or by another config +~~~ + +Remove the existing Podman network. Note that it might belong to +another user on the host. + +~~~ shell +sudo podman network rm minikube +~~~ diff --git a/external/skewer/config/.github/workflows/main.yaml b/external/skewer/config/.github/workflows/main.yaml index db00f3c..ca8214b 100644 --- a/external/skewer/config/.github/workflows/main.yaml +++ b/external/skewer/config/.github/workflows/main.yaml @@ -35,11 +35,7 @@ jobs: - uses: actions/setup-python@v5 with: python-version: "3.x" - - uses: manusa/actions-setup-minikube@v2.10.0 - with: - minikube version: "v1.32.0" - kubernetes version: "v1.29.0" - github token: ${{secrets.GITHUB_TOKEN}} + - uses: medyagh/setup-minikube@latest - run: curl https://skupper.io/install.sh | bash -s -- --version ${{matrix.skupper-version}} - run: echo "$HOME/.local/bin" >> "$GITHUB_PATH" - run: ./plano test diff --git a/external/skewer/example/README.md b/external/skewer/example/README.md index 4da73ac..d52f9b6 100644 --- a/external/skewer/example/README.md +++ b/external/skewer/example/README.md @@ -1,3 +1,5 @@ + + # Skupper Hello World [![main](https://github.com/skupperproject/skewer/actions/workflows/main.yaml/badge.svg)](https://github.com/skupperproject/skewer/actions/workflows/main.yaml) @@ -16,13 +18,14 @@ across cloud providers, data centers, and edge sites. * [Overview](#overview) * [Prerequisites](#prerequisites) * [Step 1: Install the Skupper command-line tool](#step-1-install-the-skupper-command-line-tool) -* [Step 2: Set up your namespaces](#step-2-set-up-your-namespaces) +* [Step 2: Set up your clusters](#step-2-set-up-your-clusters) * [Step 3: Deploy the frontend and backend](#step-3-deploy-the-frontend-and-backend) * [Step 4: Create your sites](#step-4-create-your-sites) * [Step 5: Link your sites](#step-5-link-your-sites) * [Step 6: Fail on demand](#step-6-fail-on-demand) -* [Step 7: Expose the backend](#step-7-expose-the-backend) -* [Step 8: Access the frontend](#step-8-access-the-frontend) +* [Step 7: Fail expectedly](#step-7-fail-expectedly) +* [Step 8: Expose the backend](#step-8-expose-the-backend) +* [Step 9: Access the frontend](#step-9-access-the-frontend) * [Cleaning up](#cleaning-up) * [Summary](#summary) * [Next steps](#next-steps) @@ -58,12 +61,12 @@ Skupper][install-docs]. [install-script]: https://github.com/skupperproject/skupper-website/blob/main/input/install.sh [install-docs]: https://skupper.io/install/ -## Step 2: Set up your namespaces +## Step 2: Set up your clusters -Skupper is designed for use with multiple Kubernetes namespaces, -usually on different clusters. The `skupper` and `kubectl` -commands use your [kubeconfig][kubeconfig] and current context to -select the namespace where they operate. +Skupper is designed for use with multiple Kubernetes clusters. +The `skupper` and `kubectl` commands use your +[kubeconfig][kubeconfig] and current context to select the cluster +and namespace where they operate. [kubeconfig]: https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/ @@ -113,9 +116,8 @@ kubectl config set-context --current --namespace east This example runs the frontend and the backend in separate Kubernetes namespaces, on different clusters. -Use `kubectl create deployment` to deploy the frontend in -namespace `west` and the backend in namespace -`east`. +Use `kubectl create deployment` to deploy the frontend in West +and the backend in East. _**West:**_ @@ -189,6 +191,8 @@ any time to check your progress. ## Step 5: Link your sites A Skupper _link_ is a channel for communication between two sites. +Links serve as a transport for application connections and +requests. Creating a link requires use of two `skupper` commands in conjunction, `skupper token create` and `skupper link create`. @@ -203,9 +207,9 @@ that generated it. token can link to your site. Make sure that only those you trust have access to it. -First, use `skupper token create` in site West to generate the -token. Then, use `skupper link create` in site East to link -the sites. +First, use `skupper token create` in West to generate the +token. Then, use `skupper link create` in East to link the +sites. _**West:**_ @@ -230,7 +234,7 @@ _Sample output:_ ~~~ console $ skupper link create ~/secret.token -Site configured to link to (name=link1) +Site configured to link to https://10.105.193.154:8081/ed9c37f6-d78a-11ec-a8c7-04421a4c5042 (name=link1) Check the status of the link using 'skupper link status'. ~~~ @@ -245,10 +249,17 @@ _**West:**_ ~~~ shell if [ -n "${SKEWER_FAIL}" ]; then expr 1 / 0; fi +~~~ + +## Step 7: Fail expectedly + +_**West:**_ +~~~ shell +expr 1 / 0 ~~~ -## Step 7: Expose the backend +## Step 8: Expose the backend We now have our sites linked to form a Skupper network, but no services are exposed on it. Skupper uses the `skupper expose` @@ -271,59 +282,34 @@ $ skupper expose deployment/backend --port 8080 deployment backend exposed as backend ~~~ -## Step 8: Access the frontend +## Step 9: Access the frontend In order to use and test the application, we need external access to the frontend. -Use `kubectl expose` with `--type LoadBalancer` to open network -access to the frontend service. - -Once the frontend is exposed, use `kubectl get service/frontend` -to look up the external IP of the frontend service. If the -external IP is ``, try again after a moment. - -Once you have the external IP, use `curl` or a similar tool to -request the `/api/health` endpoint at that address. - -**Note:** The `` field in the following commands is a -placeholder. The actual value is an IP address. +Use `kubectl port-forward` to make the frontend available at +`localhost:8080`. _**West:**_ ~~~ shell -kubectl expose deployment/frontend --port 8080 --type LoadBalancer -kubectl get service/frontend -curl http://:8080/api/health +kubectl port-forward deployment/frontend 8080:8080 ~~~ -_Sample output:_ - -~~~ console -$ kubectl expose deployment/frontend --port 8080 --type LoadBalancer -service/frontend exposed - -$ kubectl get service/frontend -NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE -frontend LoadBalancer 10.103.232.28 8080:30407/TCP 15s - -$ curl http://:8080/api/health -OK -~~~ - -If everything is in order, you can now access the web interface by -navigating to `http://:8080/` in your browser. +You can now access the web interface by navigating to +[http://localhost:8080](http://localhost:8080) in your browser. ## Cleaning up To remove Skupper and the other resources from this exercise, use the following commands: +And more! + _**West:**_ ~~~ shell skupper delete -kubectl delete service/frontend kubectl delete deployment/frontend ~~~ @@ -336,11 +322,13 @@ kubectl delete deployment/backend ## Summary -A summary +More summary ## Next steps -Some next steps +Check out the other [examples][examples] on the Skupper website. + +More steps ## About this example diff --git a/external/skewer/example/skewer.yaml b/external/skewer/example/skewer.yaml index b9fe344..8991c39 100644 --- a/external/skewer/example/skewer.yaml +++ b/external/skewer/example/skewer.yaml @@ -18,20 +18,32 @@ sites: env: KUBECONFIG: ~/.kube/config-east steps: - - standard: install_the_skupper_command_line_tool - - standard: kubernetes/set_up_your_namespaces + - standard: general/install_the_skupper_command_line_tool + - standard: kubernetes/set_up_your_clusters - standard: hello_world/deploy_the_frontend_and_backend - standard: kubernetes/create_your_sites - standard: kubernetes/link_your_sites - title: Fail on demand commands: west: - - run: | - if [ -n "${SKEWER_FAIL}" ]; then expr 1 / 0; fi + - run: "if [ -n \"${SKEWER_FAIL}\" ]; then expr 1 / 0; fi" + - title: Fail expectedly + commands: + west: + - run: "expr 1 / 0" + expect_failure: true - standard: hello_world/expose_the_backend - standard: hello_world/access_the_frontend - standard: hello_world/cleaning_up + preamble: | + @default@ + + And more! summary: | - A summary + @default@ + + More summary next_steps: | - Some next steps + @default@ + + More steps diff --git a/external/skewer/external/plano/src/plano/main.py b/external/skewer/external/plano/src/plano/main.py index eaed213..9a99fb1 100644 --- a/external/skewer/external/plano/src/plano/main.py +++ b/external/skewer/external/plano/src/plano/main.py @@ -535,13 +535,13 @@ def copy(from_path, to_path, symlinks=True, inside=True, quiet=False): else: make_parent_dir(to_path, quiet=True) - if is_dir(from_path): + if is_link(from_path) and symlinks: + make_link(to_path, read_link(from_path), quiet=True) + elif is_dir(from_path): for name in list_dir(from_path): copy(join(from_path, name), join(to_path, name), symlinks=symlinks, inside=False, quiet=True) _shutil.copystat(from_path, to_path) - elif is_link(from_path) and symlinks: - make_link(to_path, read_link(from_path), quiet=True) else: _shutil.copy2(from_path, to_path) diff --git a/external/skewer/python/skewer/main.py b/external/skewer/python/skewer/main.py index 8db876f..297bf91 100644 --- a/external/skewer/python/skewer/main.py +++ b/external/skewer/python/skewer/main.py @@ -185,8 +185,20 @@ def run_step(model, step, work_dir, check=True): if command.await_console_ok: await_console_ok() + if command.await_port: + await_port(command.await_port, timeout=300) + if command.run: - run(command.run.replace("~", work_dir), shell=True, check=check) + proc = run(command.run.replace("~", work_dir), shell=True, check=False) + + if command.expect_failure: + if proc.exit_code == 0: + fail("A command expected to fail did not fail") + + continue + + if check and proc.exit_code > 0: + raise PlanoProcessError(proc) def pause_for_demo(model): notice("Pausing for demo time") @@ -198,10 +210,8 @@ def pause_for_demo(model): if first_site.platform == "kubernetes": with first_site: - if resource_exists("service/frontend"): - if get_resource_json("service/frontend", ".spec.type") == "LoadBalancer": - frontend_host = await_ingress("service/frontend") - frontend_url = f"http://{frontend_host}:8080/" + if resource_exists("deployment/frontend"): + frontend_url = f"http://localhost:8080/" if resource_exists("secret/skupper-console-users"): console_host = await_ingress("service/skupper") @@ -309,9 +319,12 @@ def append_section(heading, text): out.append(f"## {heading}") out.append("") - out.append(text.strip()) + out.append(text) out.append("") + out.append("") + out.append("") + out.append(f"# {model.title}") out.append("") @@ -330,14 +343,14 @@ def append_section(heading, text): out.append("") append_toc_entry("Overview", model.overview) - append_toc_entry("Prerequisites") + append_toc_entry("Prerequisites", model.prerequisites) for step in model.steps: append_toc_entry(generate_step_heading(step)) - append_toc_entry("Summary") - append_toc_entry("Next steps") - append_toc_entry("About this example") + append_toc_entry("Summary", model.summary) + append_toc_entry("Next steps", model.next_steps) + append_toc_entry("About this example", model.about_this_example) out.append("") @@ -352,7 +365,7 @@ def append_section(heading, text): append_section("Summary", model.summary) append_section("Next steps", model.next_steps) - append_section("About this example", standard_text["about_this_example"].strip()) + append_section("About this example", model.about_this_example) write(output_file, "\n".join(out).strip() + "\n") @@ -427,17 +440,22 @@ def apply_standard_steps(model): del step.data["standard"] def apply_attribute(name, default=None): - if name not in step.data: - value = standard_step_data.get(name, default) + standard_value = standard_step_data.get(name, default) + value = step.data.get(name, standard_value) + + if is_string(value): + if standard_value is not None: + value = value.replace("@default@", str(nvl(standard_value, "")).strip()) - if value and name in ("title", "preamble", "postamble"): - for i, site in enumerate([x for _, x in model.sites]): - value = value.replace(f"@site{i}@", site.title) + for i, site in enumerate([x for _, x in model.sites]): + value = value.replace(f"@site{i}@", site.title) - if site.namespace: - value = value.replace(f"@namespace{i}@", site.namespace) + if site.namespace: + value = value.replace(f"@namespace{i}@", site.namespace) - step.data[name] = value + value = value.strip() + + step.data[name] = value apply_attribute("name") apply_attribute("title") @@ -513,7 +531,13 @@ def get_github_owner_repo(): def object_property(name, default=None): def get(obj): - return obj.data.get(name, default) + value = obj.data.get(name, default) + + if is_string(value): + value = value.replace("@default@", str(nvl(default, "")).strip()) + value = value.strip() + + return value return property(get) @@ -534,9 +558,10 @@ class Model: subtitle = object_property("subtitle") workflow = object_property("workflow", "main.yaml") overview = object_property("overview") - prerequisites = object_property("prerequisites", standard_text["prerequisites"].strip()) + prerequisites = object_property("prerequisites", standard_text["prerequisites"]) summary = object_property("summary") - next_steps = object_property("next_steps", standard_text["next_steps"].strip()) + next_steps = object_property("next_steps", standard_text["next_steps"]) + about_this_example = object_property("about_this_example", standard_text["about_this_example"]) def __init__(self, skewer_file, kubeconfigs=[]): self.skewer_file = skewer_file @@ -600,7 +625,7 @@ def check(self): check_required_attributes(self, "platform") check_unknown_attributes(self) - if self.platform not in ("kubernetes", "podman"): + if self.platform not in ("kubernetes", "podman", None): fail(f"{self} attribute 'platform' has an illegal value: {self.platform}") if self.platform == "kubernetes": @@ -660,12 +685,14 @@ def commands(self): class Command: run = object_property("run") + expect_failure = object_property("expect_failure", False) apply = object_property("apply") output = object_property("output") await_resource = object_property("await_resource") await_ingress = object_property("await_ingress") await_http_ok = object_property("await_http_ok") await_console_ok = object_property("await_console_ok") + await_port = object_property("await_port") def __init__(self, model, data): self.model = model @@ -703,23 +730,34 @@ def __enter__(self): run("minikube start -p skewer --auto-update-drivers false") - tunnel_output_file = open(f"{self.work_dir}/minikube-tunnel-output", "w") - self.tunnel = start("minikube tunnel -p skewer", output=tunnel_output_file) + try: + tunnel_output_file = open(f"{self.work_dir}/minikube-tunnel-output", "w") + self.tunnel = start("minikube tunnel -p skewer", output=tunnel_output_file) - model = Model(self.skewer_file) - model.check() + try: + model = Model(self.skewer_file) + model.check() - kube_sites = [x for _, x in model.sites if x.platform == "kubernetes"] + kube_sites = [x for _, x in model.sites if x.platform == "kubernetes"] - for site in kube_sites: - kubeconfig = site.env["KUBECONFIG"].replace("~", self.work_dir) - site.env["KUBECONFIG"] = kubeconfig + for site in kube_sites: + kubeconfig = site.env["KUBECONFIG"] + kubeconfig = kubeconfig.replace("~", self.work_dir) + kubeconfig = expand(kubeconfig) - self.kubeconfigs.append(kubeconfig) + site.env["KUBECONFIG"] = kubeconfig - with site: - run("minikube update-context -p skewer") - check_file(ENV["KUBECONFIG"]) + self.kubeconfigs.append(kubeconfig) + + with site: + run("minikube update-context -p skewer") + check_file(ENV["KUBECONFIG"]) + except: + stop(self.tunnel) + raise + except: + run("minikube delete -p skewer") + raise return self diff --git a/external/skewer/python/skewer/standardsteps.yaml b/external/skewer/python/skewer/standardsteps.yaml index adc1620..3e47832 100644 --- a/external/skewer/python/skewer/standardsteps.yaml +++ b/external/skewer/python/skewer/standardsteps.yaml @@ -17,7 +17,7 @@ # under the License. # -install_the_skupper_command_line_tool: +general/install_the_skupper_command_line_tool: title: Install the Skupper command-line tool preamble: | This example uses the Skupper command-line tool to deploy Skupper. @@ -39,14 +39,63 @@ install_the_skupper_command_line_tool: [install-script]: https://github.com/skupperproject/skupper-website/blob/main/input/install.sh [install-docs]: https://skupper.io/install/ -kubernetes/set_up_your_namespaces: - title: Set up your namespaces +general/link_your_sites: + title: Link your sites + preamble: | + A Skupper _link_ is a channel for communication between two sites. + Links serve as a transport for application connections and + requests. + + Creating a link requires use of two `skupper` commands in + conjunction, `skupper token create` and `skupper link create`. + + The `skupper token create` command generates a secret token that + signifies permission to create a link. The token also carries the + link details. Then, in a remote site, The `skupper link + create` command uses the token to create a link to the site + that generated it. + + **Note:** The link token is truly a *secret*. Anyone who has the + token can link to your site. Make sure that only those you trust + have access to it. + + First, use `skupper token create` in @site0@ to generate the + token. Then, use `skupper link create` in @site1@ to link the + sites. + commands: + "0": + - run: skupper token create ~/secret.token + output: Token written to ~/secret.token + "1": + - run: skupper link create ~/secret.token + output: | + Site configured to link to (name=link1) + Check the status of the link using 'skupper link status'. + - run: skupper link status --wait 60 + apply: test + postamble: | + If your terminal sessions are on different machines, you may need + to use `scp` or a similar tool to transfer the token securely. By + default, tokens expire after a single use or 15 minutes after + creation. +general/cleaning_up: + name: cleaning_up + title: Cleaning up + numbered: false + preamble: | + To remove Skupper and the other resources from this exercise, use + the following commands. + commands: + "*": + - run: skupper delete +kubernetes/set_up_your_clusters: + title: Set up your clusters platform: kubernetes preamble: | - Skupper is designed for use with multiple Kubernetes namespaces, - usually on different clusters. The `skupper` and `kubectl` - commands use your [kubeconfig][kubeconfig] and current context to - select the namespace where they operate. + Skupper is designed for use with multiple Kubernetes clusters. + The `skupper` and `kubectl` commands use your + [kubeconfig][kubeconfig] and current context to select the cluster + and namespace where they operate. [kubeconfig]: https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/ @@ -81,8 +130,8 @@ kubernetes/set_up_your_namespaces: - run: kubectl create namespace @namespace@ --dry-run=client -o yaml | kubectl apply -f - apply: test - run: kubectl config set-context --current --namespace @namespace@ -kubernetes/set_up_your_kubernetes_namespace: - title: Set up your Kubernetes namespace +kubernetes/set_up_your_kubernetes_cluster: + title: Set up your Kubernetes cluster platform: kubernetes preamble: | Open a new terminal window and log in to your cluster. Then @@ -133,35 +182,9 @@ kubernetes/create_your_sites: postamble: | As you move through the steps below, you can use `skupper status` at any time to check your progress. -podman/set_up_your_podman_network: - title: Set up your Podman network - platform: podman - preamble: | - Open a new terminal window and set the `SKUPPER_PLATFORM` - environment variable to `podman`. This sets the Skupper platform - to Podman for this terminal session. - - Use `podman network create` to create the Podman network that - Skupper will use. - - Use `systemctl` to enable the Podman API service. - commands: - "*": - - run: export SKUPPER_PLATFORM=podman - - run: podman network create skupper - apply: readme - - run: if ! podman network exists skupper; then podman network create skupper; fi - apply: test - - run: systemctl --user enable --now podman.socket - postamble: | - If the `systemctl` command doesn't work, you can try the `podman - system service` command instead: - - ~~~ - podman system service --time=0 unix://$XDG_RUNTIME_DIR/podman/podman.sock & - ~~~ -link_your_sites: +kubernetes/link_your_sites: title: Link your sites + platform: kubernetes preamble: | A Skupper _link_ is a channel for communication between two sites. Links serve as a transport for application connections and @@ -180,9 +203,9 @@ link_your_sites: token can link to your site. Make sure that only those you trust have access to it. - First, use `skupper token create` in site @site0@ to generate the - token. Then, use `skupper link create` in site @site1@ to link - the sites. + First, use `skupper token create` in @site0@ to generate the + token. Then, use `skupper link create` in @site1@ to link the + sites. commands: "0": - run: skupper token create ~/secret.token @@ -190,7 +213,7 @@ link_your_sites: "1": - run: skupper link create ~/secret.token output: | - Site configured to link to (name=link1) + Site configured to link to https://10.105.193.154:8081/ed9c37f6-d78a-11ec-a8c7-04421a4c5042 (name=link1) Check the status of the link using 'skupper link status'. - run: skupper link status --wait 60 apply: test @@ -199,47 +222,28 @@ link_your_sites: to use `scp` or a similar tool to transfer the token securely. By default, tokens expire after a single use or 15 minutes after creation. -kubernetes/link_your_sites: - title: Link your sites - platform: kubernetes +kubernetes/access_the_frontend: + title: Access the frontend preamble: | - A Skupper _link_ is a channel for communication between two sites. - Links serve as a transport for application connections and - requests. - - Creating a link requires use of two `skupper` commands in - conjunction, `skupper token create` and `skupper link create`. - - The `skupper token create` command generates a secret token that - signifies permission to create a link. The token also carries the - link details. Then, in a remote site, The `skupper link - create` command uses the token to create a link to the site - that generated it. - - **Note:** The link token is truly a *secret*. Anyone who has the - token can link to your site. Make sure that only those you trust - have access to it. + In order to use and test the application, we need external access + to the frontend. - First, use `skupper token create` in site @site0@ to generate the - token. Then, use `skupper link create` in site @site1@ to link - the sites. + Use `kubectl port-forward` to make the frontend available at + `localhost:8080`. commands: "0": - - run: skupper token create ~/secret.token - output: Token written to ~/secret.token - "1": - - run: skupper link create ~/secret.token - output: | - Site configured to link to https://10.105.193.154:8081/ed9c37f6-d78a-11ec-a8c7-04421a4c5042 (name=link1) - Check the status of the link using 'skupper link status'. - - run: skupper link status --wait 60 + - await_resource: deployment/frontend + - run: kubectl port-forward deployment/frontend 8080:8080 + apply: readme + - run: kubectl port-forward deployment/frontend 8080:8080 > /dev/null & + apply: test + - await_port: 8080 + - run: curl http://localhost:8080/api/health apply: test postamble: | - If your terminal sessions are on different machines, you may need - to use `scp` or a similar tool to transfer the token securely. By - default, tokens expire after a single use or 15 minutes after - creation. -cleaning_up: + You can now access the web interface by navigating to + [http://localhost:8080](http://localhost:8080) in your browser. +kubernetes/cleaning_up: name: cleaning_up title: Cleaning up numbered: false @@ -249,15 +253,41 @@ cleaning_up: commands: "*": - run: skupper delete +podman/set_up_your_podman_environment: + title: Set up your Podman environment + platform: podman + preamble: | + Open a new terminal window and set the `SKUPPER_PLATFORM` + environment variable to `podman`. This sets the Skupper platform + to Podman for this terminal session. + + Use `podman network create` to create the Podman network that + Skupper will use. + + Use `systemctl` to enable the Podman API service. + commands: + "*": + - run: export SKUPPER_PLATFORM=podman + - run: podman network create skupper + apply: readme + - run: if ! podman network exists skupper; then podman network create skupper; fi + apply: test + - run: systemctl --user enable --now podman.socket + postamble: | + If the `systemctl` command doesn't work, you can try the `podman + system service` command instead: + + ~~~ + podman system service --time=0 unix://$XDG_RUNTIME_DIR/podman/podman.sock & + ~~~ hello_world/deploy_the_frontend_and_backend: title: Deploy the frontend and backend preamble: | This example runs the frontend and the backend in separate Kubernetes namespaces, on different clusters. - Use `kubectl create deployment` to deploy the frontend in - namespace `@namespace0@` and the backend in namespace - `@namespace1@`. + Use `kubectl create deployment` to deploy the frontend in @site0@ + and the backend in @site1@. commands: "0": - run: kubectl create deployment frontend --image quay.io/skupper/hello-world-frontend @@ -284,35 +314,21 @@ hello_world/access_the_frontend: In order to use and test the application, we need external access to the frontend. - Use `kubectl expose` with `--type LoadBalancer` to open network - access to the frontend service. - - Once the frontend is exposed, use `kubectl get service/frontend` - to look up the external IP of the frontend service. If the - external IP is ``, try again after a moment. - - Once you have the external IP, use `curl` or a similar tool to - request the `/api/health` endpoint at that address. - - **Note:** The `` field in the following commands is a - placeholder. The actual value is an IP address. + Use `kubectl port-forward` to make the frontend available at + `localhost:8080`. commands: "0": - - run: kubectl expose deployment/frontend --port 8080 --type LoadBalancer - output: service/frontend exposed - - await_resource: service/frontend - - run: kubectl get service/frontend + - await_resource: deployment/frontend + - run: kubectl port-forward deployment/frontend 8080:8080 apply: readme - output: | - NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE - frontend LoadBalancer 10.103.232.28 8080:30407/TCP 15s - - run: curl http://:8080/api/health - apply: readme - output: OK - - await_http_ok: [service/frontend, "http://{}:8080/api/health"] + - run: kubectl port-forward deployment/frontend 8080:8080 > /dev/null & + apply: test + - await_port: 8080 + - run: curl http://localhost:8080/api/health + apply: test postamble: | - If everything is in order, you can now access the web interface by - navigating to `http://:8080/` in your browser. + You can now access the web interface by navigating to + [http://localhost:8080](http://localhost:8080) in your browser. hello_world/cleaning_up: name: cleaning_up title: Cleaning up @@ -323,7 +339,6 @@ hello_world/cleaning_up: commands: "0": - run: skupper delete - - run: kubectl delete service/frontend - run: kubectl delete deployment/frontend "1": - run: skupper delete diff --git a/skewer.yaml b/skewer.yaml index c196518..0293896 100644 --- a/skewer.yaml +++ b/skewer.yaml @@ -34,8 +34,8 @@ sites: env: KUBECONFIG: ~/.kube/config-private steps: - - standard: install_the_skupper_command_line_tool - - standard: kubernetes/set_up_your_namespaces + - standard: general/install_the_skupper_command_line_tool + - standard: kubernetes/set_up_your_clusters - standard: hello_world/deploy_the_frontend_and_backend - standard: kubernetes/create_your_sites - standard: kubernetes/link_your_sites