From 4d683cf7639d3aa7ae15f53253490894f6ef9d48 Mon Sep 17 00:00:00 2001 From: Justin Ross Date: Sat, 3 Feb 2024 08:59:29 -0500 Subject: [PATCH] Skewer update --- README.md | 223 ++++++------- .../skewer-main/example/external/skewer-main | 1 - external/skewer-main/example/python/plano | 1 - external/skewer-main/example/python/skewer | 1 - external/skewer-main/python/plano | 1 - .../python/skewer/standardsteps.yaml | 278 ----------------- .../.github/workflows/main.yaml | 0 external/{skewer-main => skewer}/.gitignore | 0 external/{skewer-main => skewer}/.plano.py | 12 +- external/{skewer-main => skewer}/LICENSE.txt | 0 external/{skewer-main => skewer}/README.md | 70 +++-- .../config/.github/workflows/main.yaml | 0 .../{skewer-main => skewer}/config/.gitignore | 0 .../{skewer-main => skewer}/config/.plano.py | 0 .../example/.gitignore | 0 .../{skewer-main => skewer}/example/.plano.py | 0 .../{skewer-main => skewer}/example/README.md | 249 ++++++--------- .../{skewer-main => skewer}/example/plano | 0 external/skewer/example/python/plano | 1 + external/skewer/example/python/skewer | 1 + .../example/skewer.yaml | 16 +- .../plano}/.github/workflows/main.yaml | 0 .../external/plano}/.gitignore | 0 .../external/plano}/LICENSE.txt | 0 .../external/plano}/MANIFEST.in | 0 .../external/plano}/Makefile | 0 .../external/plano}/README.md | 0 .../external/plano}/bin/plano | 0 .../external/plano}/bin/plano-test | 0 .../external/plano}/docs/conf.py | 0 .../external/plano}/docs/index.rst | 0 .../external/plano}/pyproject.toml | 0 .../external/plano}/src/plano/__init__.py | 0 .../plano}/src/plano/_testproject/.plano.py | 2 +- .../_testproject/src/chucker/__init__.py | 0 .../_testproject/src/chucker/moretests.py | 24 ++ .../plano/_testproject/src/chucker/tests.py | 5 + .../external/plano}/src/plano/_tests.py | 58 +++- .../external/plano}/src/plano/command.py | 5 +- .../skewer/external/plano/src/plano/github.py | 80 +++++ .../external/plano}/src/plano/main.py | 114 ++++--- .../external/plano}/src/plano/test.py | 0 external/{skewer-main => skewer}/plano | 0 external/skewer/python/plano | 1 + .../python/skewer/__init__.py | 0 .../python/skewer/main.py | 32 +- .../python/skewer/planocommands.py | 46 +-- .../skewer/python/skewer/standardsteps.yaml | 292 ++++++++++++++++++ .../python/skewer/standardtext.yaml | 0 .../python/skewer/tests.py | 0 python/plano | 2 +- python/skewer | 2 +- skewer.yaml | 11 +- 53 files changed, 812 insertions(+), 716 deletions(-) delete mode 120000 external/skewer-main/example/external/skewer-main delete mode 120000 external/skewer-main/example/python/plano delete mode 120000 external/skewer-main/example/python/skewer delete mode 120000 external/skewer-main/python/plano delete mode 100644 external/skewer-main/python/skewer/standardsteps.yaml rename external/{skewer-main => skewer}/.github/workflows/main.yaml (100%) rename external/{skewer-main => skewer}/.gitignore (100%) rename external/{skewer-main => skewer}/.plano.py (86%) rename external/{skewer-main => skewer}/LICENSE.txt (100%) rename external/{skewer-main => skewer}/README.md (81%) rename external/{skewer-main => skewer}/config/.github/workflows/main.yaml (100%) rename external/{skewer-main => skewer}/config/.gitignore (100%) rename external/{skewer-main => skewer}/config/.plano.py (100%) rename external/{skewer-main => skewer}/example/.gitignore (100%) rename external/{skewer-main => skewer}/example/.plano.py (100%) rename external/{skewer-main => skewer}/example/README.md (52%) rename external/{skewer-main => skewer}/example/plano (100%) create mode 120000 external/skewer/example/python/plano create mode 120000 external/skewer/example/python/skewer rename external/{skewer-main => skewer}/example/skewer.yaml (61%) rename external/{skewer-main/external/plano-main => skewer/external/plano}/.github/workflows/main.yaml (100%) rename external/{skewer-main/external/plano-main => skewer/external/plano}/.gitignore (100%) rename external/{skewer-main/external/plano-main => skewer/external/plano}/LICENSE.txt (100%) rename external/{skewer-main/external/plano-main => skewer/external/plano}/MANIFEST.in (100%) rename external/{skewer-main/external/plano-main => skewer/external/plano}/Makefile (100%) rename external/{skewer-main/external/plano-main => skewer/external/plano}/README.md (100%) rename external/{skewer-main/external/plano-main => skewer/external/plano}/bin/plano (100%) rename external/{skewer-main/external/plano-main => skewer/external/plano}/bin/plano-test (100%) rename external/{skewer-main/external/plano-main => skewer/external/plano}/docs/conf.py (100%) rename external/{skewer-main/external/plano-main => skewer/external/plano}/docs/index.rst (100%) rename external/{skewer-main/external/plano-main => skewer/external/plano}/pyproject.toml (100%) rename external/{skewer-main/external/plano-main => skewer/external/plano}/src/plano/__init__.py (100%) rename external/{skewer-main/external/plano-main => skewer/external/plano}/src/plano/_testproject/.plano.py (97%) rename external/{skewer-main/external/plano-main => skewer/external/plano}/src/plano/_testproject/src/chucker/__init__.py (100%) create mode 100644 external/skewer/external/plano/src/plano/_testproject/src/chucker/moretests.py rename external/{skewer-main/external/plano-main => skewer/external/plano}/src/plano/_testproject/src/chucker/tests.py (95%) rename external/{skewer-main/external/plano-main => skewer/external/plano}/src/plano/_tests.py (95%) rename external/{skewer-main/external/plano-main => skewer/external/plano}/src/plano/command.py (98%) create mode 100644 external/skewer/external/plano/src/plano/github.py rename external/{skewer-main/external/plano-main => skewer/external/plano}/src/plano/main.py (94%) rename external/{skewer-main/external/plano-main => skewer/external/plano}/src/plano/test.py (100%) rename external/{skewer-main => skewer}/plano (100%) create mode 120000 external/skewer/python/plano rename external/{skewer-main => skewer}/python/skewer/__init__.py (100%) rename external/{skewer-main => skewer}/python/skewer/main.py (95%) rename external/{skewer-main => skewer}/python/skewer/planocommands.py (65%) create mode 100644 external/skewer/python/skewer/standardsteps.yaml rename external/{skewer-main => skewer}/python/skewer/standardtext.yaml (100%) rename external/{skewer-main => skewer}/python/skewer/tests.py (100%) diff --git a/README.md b/README.md index fa70040..150dae4 100644 --- a/README.md +++ b/README.md @@ -15,16 +15,13 @@ across cloud providers, data centers, and edge sites. * [Overview](#overview) * [Prerequisites](#prerequisites) -* [Step 1: Configure separate console sessions](#step-1-configure-separate-console-sessions) -* [Step 2: Access your clusters](#step-2-access-your-clusters) -* [Step 3: Set up your namespaces](#step-3-set-up-your-namespaces) -* [Step 4: Install Skupper in your namespaces](#step-4-install-skupper-in-your-namespaces) -* [Step 5: Check the status of your namespaces](#step-5-check-the-status-of-your-namespaces) -* [Step 6: Link your namespaces](#step-6-link-your-namespaces) -* [Step 7: Deploy SERVER](#step-7-deploy-server) -* [Step 8: Expose SERVER](#step-8-expose-server) -* [Step 9: Run CLIENT](#step-9-run-client) -* [Accessing the web console](#accessing-the-web-console) +* [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 3: Create your sites](#step-3-create-your-sites) +* [Step 4: Link your sites](#step-4-link-your-sites) +* [Step 5: Deploy SERVER](#step-5-deploy-server) +* [Step 6: Expose SERVER](#step-6-expose-server) +* [Step 7: Run CLIENT](#step-7-run-client) * [Cleaning up](#cleaning-up) * [Summary](#summary) * [Next steps](#next-steps) @@ -45,89 +42,99 @@ This example shows how you can use Skupper to access SERVER. [install-kubectl]: https://kubernetes.io/docs/tasks/tools/install-kubectl/ [kube-providers]: https://skupper.io/start/kubernetes.html -## Step 1: Configure separate console sessions +## Step 1: Install the Skupper command-line tool -Skupper is designed for use with multiple namespaces, usually on -different clusters. The `skupper` and `kubectl` commands use your -[kubeconfig][kubeconfig] and current context to select the -namespace where they operate. +This example uses the Skupper command-line tool to deploy Skupper. +You need to install the `skupper` command only once for each +development environment. -[kubeconfig]: https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/ +On Linux or Mac, you can use the install script (inspect it +[here][install-script]) to download and extract the command: -Your kubeconfig is stored in a file in your home directory. The -`skupper` and `kubectl` commands use the `KUBECONFIG` environment -variable to locate it. +~~~ shell +curl https://skupper.io/install.sh | sh +~~~ -A single kubeconfig supports only one active context per user. -Since you will be using multiple contexts at once in this -exercise, you need to create distinct kubeconfigs. +The script installs the command under your home directory. It +prompts you to add the command to your path if necessary. -Start a console session for each of your namespaces. Set the -`KUBECONFIG` environment variable to a different path in each -session. +For Windows and other installation options, see [Installing +Skupper][install-docs]. -_**Console for Public:**_ +[install-script]: https://github.com/skupperproject/skupper-website/blob/main/input/install.sh +[install-docs]: https://skupper.io/install/ -~~~ shell -export KUBECONFIG=~/.kube/config-public -~~~ +## Step 2: Set up your namespaces -_**Console for Private:**_ +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. -~~~ shell -export KUBECONFIG=~/.kube/config-private -~~~ +[kubeconfig]: https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/ -## Step 2: Access your clusters +Your kubeconfig is stored in a file in your home directory. The +`skupper` and `kubectl` commands use the `KUBECONFIG` environment +variable to locate it. -The procedure for accessing a Kubernetes cluster varies by -provider. [Find the instructions for your chosen -provider][kube-providers] and use them to authenticate and -configure access for each console session. +A single kubeconfig supports only one active context per user. +Since you will be using multiple contexts at once in this +exercise, you need to create distinct kubeconfigs. -[kube-providers]: https://skupper.io/start/kubernetes.html +For each namespace, open a new terminal window. In each terminal, +set the `KUBECONFIG` environment variable to a different path and +log in to your cluster. Then create the namespace you wish to use +and set the namespace on your current context. -## Step 3: Set up your namespaces +**Note:** The login procedure varies by provider. See the +documentation for yours: -Use `kubectl create namespace` to create the namespaces you wish -to use (or use existing namespaces). Use `kubectl config -set-context` to set the current namespace for each session. +* [Minikube](https://skupper.io/start/minikube.html#cluster-access) +* [Amazon Elastic Kubernetes Service (EKS)](https://skupper.io/start/eks.html#cluster-access) +* [Azure Kubernetes Service (AKS)](https://skupper.io/start/aks.html#cluster-access) +* [Google Kubernetes Engine (GKE)](https://skupper.io/start/gke.html#cluster-access) +* [IBM Kubernetes Service](https://skupper.io/start/ibmks.html#cluster-access) +* [OpenShift](https://skupper.io/start/openshift.html#cluster-access) -_**Console for Public:**_ +_**Public:**_ ~~~ shell +export KUBECONFIG=~/.kube/config-public +# Enter your provider-specific login command kubectl create namespace public kubectl config set-context --current --namespace public ~~~ -_**Console for Private:**_ +_**Private:**_ ~~~ shell +export KUBECONFIG=~/.kube/config-private +# Enter your provider-specific login command kubectl create namespace private kubectl config set-context --current --namespace private ~~~ -## Step 4: Install Skupper in your namespaces +## Step 3: Create your sites -The `skupper init` command installs the Skupper router and -controller in the current namespace. Run the `skupper init` command -in each namespace. +A Skupper _site_ is a location where components of your +application are running. Sites are linked together to form a +network for your application. In Kubernetes, a site is associated +with a namespace. -**Note:** If you are using Minikube, [you need to start `minikube -tunnel`][minikube-tunnel] before you install Skupper. - -[minikube-tunnel]: https://skupper.io/start/minikube.html#running-minikube-tunnel +For each namespace, use `skupper init` to create a site. This +deploys the Skupper router and controller. Then use `skupper +status` to see the outcome. -_**Console for Public:**_ +**Note:** If you are using Minikube, you need to [start minikube +tunnel][minikube-tunnel] before you run `skupper init`. -~~~ shell -skupper init --enable-console --enable-flow-collector -~~~ +[minikube-tunnel]: https://skupper.io/start/minikube.html#running-minikube-tunnel -_**Console for Private:**_ +_**Public:**_ ~~~ shell skupper init +skupper status ~~~ _Sample output:_ @@ -136,58 +143,54 @@ _Sample output:_ $ skupper init Waiting for LoadBalancer IP or hostname... Waiting for status... -Skupper is now installed in namespace ''. Use 'skupper status' to get more information. -~~~ - -## Step 5: Check the status of your namespaces - -Use `skupper status` in each console to check that Skupper is -installed. +Skupper is now installed in namespace 'west'. Use 'skupper status' to get more information. -_**Console for Public:**_ - -~~~ shell -skupper status +$ skupper status +Skupper is enabled for namespace "west". It is not connected to any other sites. It has no exposed services. ~~~ -_**Console for Private:**_ +_**Private:**_ ~~~ shell +skupper init skupper status ~~~ _Sample output:_ ~~~ console +$ skupper init +Waiting for LoadBalancer IP or hostname... +Waiting for status... +Skupper is now installed in namespace 'east'. Use 'skupper status' to get more information. + $ skupper status -Skupper is enabled for namespace "" in interior mode. It is connected to 1 other site. It has 1 exposed service. -The site console url is: -The credentials for internal console-auth mode are held in secret: 'skupper-console-users' +Skupper is enabled for namespace "east". It is not connected to any other sites. It has no exposed services. ~~~ As you move through the steps below, you can use `skupper status` at any time to check your progress. -## Step 6: Link your namespaces +## Step 4: Link your sites 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 namespace, The `skupper link -create` command uses the token to create a link to the namespace +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 namespace. Make sure that only those you -trust have access to it. +token can link to your site. Make sure that only those you trust +have access to it. -First, use `skupper token create` in one namespace to generate the -token. Then, use `skupper link create` in the other to create a -link. +First, use `skupper token create` in site Public to generate the +token. Then, use `skupper link create` in site Private to link +the sites. -_**Console for Public:**_ +_**Public:**_ ~~~ shell skupper token create ~/secret.token @@ -200,7 +203,7 @@ $ skupper token create ~/secret.token Token written to ~/secret.token ~~~ -_**Console for Private:**_ +_**Private:**_ ~~~ shell skupper link create ~/secret.token @@ -214,17 +217,17 @@ Site configured to link to https://10.105.193.154:8081/ed9c37f6-d78a-11ec-a8c7-0 Check the status of the link using 'skupper link status'. ~~~ -If your console sessions are on different machines, you may need +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. -## Step 7: Deploy SERVER +## Step 5: Deploy SERVER In the private namespace, use the `kubectl apply` command to install the server. -_**Console for Private:**_ +_**Private:**_ ~~~ shell kubectl apply -f server/kubernetes.yaml @@ -237,7 +240,7 @@ $ kubectl apply -f server/kubernetes.yaml deployment.apps/server created ~~~ -## Step 8: Expose SERVER +## Step 6: Expose SERVER In the private namespace, use `skupper expose` to expose SERVER on the Skupper network. @@ -245,7 +248,7 @@ on the Skupper network. Then, in the public namespace, use `kubectl get service/server` to check that the service appears after a moment. -_**Console for Private:**_ +_**Private:**_ ~~~ shell skupper expose deployment/server --port 8080 --target-port 80 @@ -258,7 +261,7 @@ $ skupper expose deployment/server --port 8080 --target-port 80 deployment server exposed as server ~~~ -_**Console for Public:**_ +_**Public:**_ ~~~ shell kubectl get service/server @@ -272,11 +275,11 @@ NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE server ClusterIP 10.100.58.95 8080/TCP 2s ~~~ -## Step 9: Run CLIENT +## Step 7: Run CLIENT In the public namespace, use `kubectl run` to run CLIENT. -_**Console for Public:**_ +_**Public:**_ ~~~ shell kubectl run client --attach --rm --image docker.io/library/nginx --restart Never -- curl -sf http://server:8080/ @@ -290,53 +293,19 @@ OUTPUT pod "client" deleted ~~~ -## Accessing the web console - -Skupper includes a web console you can use to view the application -network. To access it, use `skupper status` to look up the URL of -the web console. Then use `kubectl get -secret/skupper-console-users` to look up the console admin -password. - -**Note:** The `` and `` fields in the -following output are placeholders. The actual values are specific -to your environment. - -_**Console for Public:**_ - -~~~ shell -skupper status -kubectl get secret/skupper-console-users -o jsonpath={.data.admin} | base64 -d -~~~ - -_Sample output:_ - -~~~ console -$ skupper status -Skupper is enabled for namespace "public". It is connected to 1 other site. It has 1 exposed service. -The site console url is: -The credentials for internal console-auth mode are held in secret: 'skupper-console-users' - -$ kubectl get secret/skupper-console-users -o jsonpath={.data.admin} | base64 -d - -~~~ - -Navigate to `` in your browser. When prompted, log -in as user `admin` and enter the password. - ## Cleaning up To remove Skupper and the other resources from this exercise, use the following commands. -_**Console for Private:**_ +_**Private:**_ ~~~ shell skupper delete kubectl delete -f server/kubernetes.yaml ~~~ -_**Console for Public:**_ +_**Public:**_ ~~~ shell skupper delete diff --git a/external/skewer-main/example/external/skewer-main b/external/skewer-main/example/external/skewer-main deleted file mode 120000 index c25bddb..0000000 --- a/external/skewer-main/example/external/skewer-main +++ /dev/null @@ -1 +0,0 @@ -../.. \ No newline at end of file diff --git a/external/skewer-main/example/python/plano b/external/skewer-main/example/python/plano deleted file mode 120000 index a578137..0000000 --- a/external/skewer-main/example/python/plano +++ /dev/null @@ -1 +0,0 @@ -../external/skewer-main/python/plano \ No newline at end of file diff --git a/external/skewer-main/example/python/skewer b/external/skewer-main/example/python/skewer deleted file mode 120000 index 6ea41b9..0000000 --- a/external/skewer-main/example/python/skewer +++ /dev/null @@ -1 +0,0 @@ -../external/skewer-main/python/skewer \ No newline at end of file diff --git a/external/skewer-main/python/plano b/external/skewer-main/python/plano deleted file mode 120000 index a1aa027..0000000 --- a/external/skewer-main/python/plano +++ /dev/null @@ -1 +0,0 @@ -../external/plano-main/src/plano \ No newline at end of file diff --git a/external/skewer-main/python/skewer/standardsteps.yaml b/external/skewer-main/python/skewer/standardsteps.yaml deleted file mode 100644 index d5dbcbf..0000000 --- a/external/skewer-main/python/skewer/standardsteps.yaml +++ /dev/null @@ -1,278 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# - -install_the_skupper_command_line_tool: - title: Install the Skupper command-line tool - preamble: | - The `skupper` command-line tool is the entrypoint for installing - and configuring Skupper. You need to install the `skupper` - command only once for each development environment. - - On Linux or Mac, you can use the install script (inspect it - [here][install-script]) to download and extract the command: - - ~~~ shell - curl https://skupper.io/install.sh | sh - ~~~ - - The script installs the command under your home directory. It - prompts you to add the command to your path if necessary. - - For Windows and other installation options, see [Installing - Skupper][install-docs]. - - [install-script]: https://github.com/skupperproject/skupper-website/blob/main/input/install.sh - [install-docs]: https://skupper.io/install/ -configure_separate_console_sessions: - title: Configure separate console sessions - preamble: | - Skupper is designed for use with multiple namespaces, usually on - different clusters. The `skupper` and `kubectl` commands use your - [kubeconfig][kubeconfig] and current context to select the - namespace where they operate. - - [kubeconfig]: https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/ - - Your kubeconfig is stored in a file in your home directory. The - `skupper` and `kubectl` commands use the `KUBECONFIG` environment - variable to locate it. - - A single kubeconfig supports only one active context per user. - Since you will be using multiple contexts at once in this - exercise, you need to create distinct kubeconfigs. - - Start a console session for each of your namespaces. Set the - `KUBECONFIG` environment variable to a different path in each - session. - commands: - "*": - - run: export KUBECONFIG=@kubeconfig@ -access_your_clusters: - title: Access your clusters - preamble: | - - The procedure for accessing a Kubernetes cluster varies by - provider. [Find the instructions for your chosen - provider][kube-providers] and use them to authenticate and - configure access for each console session. - - [kube-providers]: https://skupper.io/start/kubernetes.html -set_up_your_namespaces: - title: Set up your namespaces - preamble: | - Use `kubectl create namespace` to create the namespaces you wish - to use (or use existing namespaces). Use `kubectl config - set-context` to set the current namespace for each session. - commands: - "*": - - run: kubectl create namespace @namespace@ - - run: kubectl config set-context --current --namespace @namespace@ -install_skupper_in_your_namespaces: - title: Install Skupper in your namespaces - preamble: | - The `skupper init` command installs the Skupper router and - controller in the current namespace. Run the `skupper init` command - in each namespace. - - **Note:** If you are using Minikube, [you need to start `minikube - tunnel`][minikube-tunnel] before you install Skupper. - - [minikube-tunnel]: https://skupper.io/start/minikube.html#running-minikube-tunnel - commands: - "0": - - run: skupper init --enable-console --enable-flow-collector - "*": - - run: skupper init - postamble: | - _Sample output:_ - - ~~~ console - $ skupper init - Waiting for LoadBalancer IP or hostname... - Waiting for status... - Skupper is now installed in namespace ''. Use 'skupper status' to get more information. - ~~~ -check_the_status_of_your_namespaces: - title: Check the status of your namespaces - preamble: | - Use `skupper status` in each console to check that Skupper is - installed. - commands: - "*": - - run: skupper status - postamble: | - _Sample output:_ - - ~~~ console - $ skupper status - Skupper is enabled for namespace "" in interior mode. It is connected to 1 other site. It has 1 exposed service. - The site console url is: - The credentials for internal console-auth mode are held in secret: 'skupper-console-users' - ~~~ - - As you move through the steps below, you can use `skupper status` at - any time to check your progress. -link_your_namespaces: - title: Link your namespaces - preamble: | - 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 namespace, The `skupper link - create` command uses the token to create a link to the namespace - that generated it. - - **Note:** The link token is truly a *secret*. Anyone who has the - token can link to your namespace. Make sure that only those you - trust have access to it. - - First, use `skupper token create` in one namespace to generate the - token. Then, use `skupper link create` in the other to create a - link. - 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 - apply: test - postamble: | - If your console 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. -accessing_the_web_console: - title: Accessing the web console - numbered: false - preamble: | - Skupper includes a web console you can use to view the application - network. To access it, use `skupper status` to look up the URL of - the web console. Then use `kubectl get - secret/skupper-console-users` to look up the console admin - password. - - **Note:** The `` and `` fields in the - following output are placeholders. The actual values are specific - to your environment. - commands: - "0": - - run: skupper status - output: | - Skupper is enabled for namespace "@namespace@". It is connected to 1 other site. It has 1 exposed service. - The site console url is: - The credentials for internal console-auth mode are held in secret: 'skupper-console-users' - - await_resource: secret/skupper-console-users - - run: kubectl get secret/skupper-console-users -o jsonpath={.data.admin} | base64 -d - output: - - await_console_ok: - postamble: | - Navigate to `` in your browser. When prompted, log - in as user `admin` and enter the password. -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 -hello_world/deploy_the_application: - title: Deploy the application - preamble: | - Use `kubectl create deployment` to deploy the frontend and backend - services. - commands: - "0": - - run: kubectl create deployment frontend --image quay.io/skupper/hello-world-frontend - "1": - - run: kubectl create deployment backend --image quay.io/skupper/hello-world-backend --replicas 3 -hello_world/expose_the_backend_service: - title: Expose the backend service - preamble: | - We now have two namespaces linked to form a Skupper network, but - no services are exposed on it. Skupper uses the `skupper - expose` command to select a service from one namespace for - exposure in all the linked namespaces. - - Use `skupper expose` to expose the backend service on the Skupper - network. - commands: - "1": - - await_resource: deployment/backend - - run: skupper expose deployment/backend --port 8080 - output: deployment backend exposed as backend -hello_world/test_the_application: - title: Test the application - preamble: | - We have established connectivity between the two namespaces and - made the backend available to the frontend. Before we can 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. - commands: - "0": - - run: kubectl expose deployment/frontend --port 8080 --type LoadBalancer - output: service/frontend exposed - - await_resource: service/frontend - - run: kubectl get service/frontend - 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"] - postamble: | - If everything is in order, you can now access the web interface by - navigating to `http://:8080/` in your browser. -hello_world/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: - "0": - - run: skupper delete - - run: kubectl delete service/frontend - - run: kubectl delete deployment/frontend - "1": - - run: skupper delete - - run: kubectl delete deployment/backend diff --git a/external/skewer-main/.github/workflows/main.yaml b/external/skewer/.github/workflows/main.yaml similarity index 100% rename from external/skewer-main/.github/workflows/main.yaml rename to external/skewer/.github/workflows/main.yaml diff --git a/external/skewer-main/.gitignore b/external/skewer/.gitignore similarity index 100% rename from external/skewer-main/.gitignore rename to external/skewer/.gitignore diff --git a/external/skewer-main/.plano.py b/external/skewer/.plano.py similarity index 86% rename from external/skewer-main/.plano.py rename to external/skewer/.plano.py index efc44d0..fe427c3 100644 --- a/external/skewer-main/.plano.py +++ b/external/skewer/.plano.py @@ -20,6 +20,7 @@ import skewer.tests from plano import * +from plano.github import * from skewer import * @command(passthrough=True) @@ -44,9 +45,10 @@ def render(verbose=False, quiet=False): """ Render README.html from README.md """ - check_program("pandoc") + markdown = read("README.md") + html = convert_github_markdown(markdown) - run(f"pandoc -o README.html README.md") + write("README.html", html) if not quiet: print(f"file:{get_real_path('README.html')}") @@ -63,8 +65,4 @@ def update_plano(): """ Update the embedded Plano repo """ - check_program("curl") - - make_dir("external") - remove("external/plano-main") - run("curl -sfL https://github.com/ssorj/plano/archive/main.tar.gz | tar -C external -xz", shell=True) + update_external_from_github("external/plano", "ssorj", "plano") diff --git a/external/skewer-main/LICENSE.txt b/external/skewer/LICENSE.txt similarity index 100% rename from external/skewer-main/LICENSE.txt rename to external/skewer/LICENSE.txt diff --git a/external/skewer-main/README.md b/external/skewer/README.md similarity index 81% rename from external/skewer-main/README.md rename to external/skewer/README.md index 76b30a0..f81793d 100644 --- a/external/skewer-main/README.md +++ b/external/skewer/README.md @@ -25,28 +25,31 @@ Change directory to the root of your example project: cd / -Add the Skewer code as a subdirectory in your example project: +Add the Skewer code as a subdirectory: mkdir -p external curl -sfL https://github.com/skupperproject/skewer/archive/main.tar.gz | tar -C external -xz + mv external/skewer-main external/skewer Symlink the Skewer and Plano libraries into your `python` directory: mkdir -p python - ln -s ../external/skewer-main/python/skewer python/skewer - ln -s ../external/skewer-main/python/plano python/plano + ln -s ../external/skewer/python/skewer python/skewer + ln -s ../external/skewer/python/plano python/plano Copy the `plano` command into the root of your project: - cp external/skewer-main/plano plano + cp external/skewer/plano plano -Copy the standard config files and workflow file into your project: +Copy the standard config files: - cp external/skewer-main/config/.plano.py .plano.py - cp external/skewer-main/config/.gitignore .gitignore + cp external/skewer/config/.plano.py .plano.py + cp external/skewer/config/.gitignore .gitignore + +Copy the standard workflow file: mkdir -p .github/workflows - cp external/skewer-main/config/.github/workflows/main.yaml .github/workflows/main.yaml + cp external/skewer/config/.github/workflows/main.yaml .github/workflows/main.yaml Use your editor to create a `skewer.yaml` file in the root of your project: @@ -90,7 +93,7 @@ The top level: ~~~ yaml title: # Your example's title (required) -subtitle: # Your chosen subtitle (required) +subtitle: # Your chosen subtitle (optional) workflow: # The filename of your GitHub workflow (optional, default 'main.yaml') overview: # Text introducing your example (optional) prerequisites: # Text describing prerequisites (optional, has default text) @@ -100,6 +103,8 @@ 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`. + A **site**: ~~~ yaml @@ -186,37 +191,42 @@ to `standard`: - run: skupper delete ~~~ -The initial steps are usually standard ones. There are also some -standard steps at the end. You may be able to use something like -this: +A typical mix of standard and custom steps might look like this: ~~~ yaml steps: - - standard: configure_separate_console_sessions - - standard: access_your_clusters - - standard: set_up_your_namespaces - - standard: install_skupper_in_your_namespaces - - standard: check_the_status_of_your_namespaces - - standard: link_your_namespaces - - - standard: accessing_the_web_console + - standard: install_the_skupper_command_line_tool + - standard: kubernetes/set_up_your_namespaces + + - standard: kubernetes/create_your_sites + - standard: link_your_sites + + - standard: cleaning_up ~~~ -Note that the `link_your_namespaces` step is less generic than the -other steps (it assumes only two sites), so check that the text and -commands it produces are doing what you need. If not, you'll need to -provide a custom step. +**Note:** The `link_your_sites`, `access_the_application`, and +`cleaning_up` steps are less generic than the other steps. +`link_your_sites` assumes just two sites. `access_the_application` +assumes you have a `frontend` service. `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 also some standard steps for examples based on the Skupper +There are some standard steps for examples based on the Skupper Hello World application: ~~~ yaml -steps: - - standard: hello_world/deploy_the_application - - standard: hello_world/expose_the_backend_service - - standard: hello_world/test_the_application - - standard: hello_world/cleaning_up +- 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 diff --git a/external/skewer-main/config/.github/workflows/main.yaml b/external/skewer/config/.github/workflows/main.yaml similarity index 100% rename from external/skewer-main/config/.github/workflows/main.yaml rename to external/skewer/config/.github/workflows/main.yaml diff --git a/external/skewer-main/config/.gitignore b/external/skewer/config/.gitignore similarity index 100% rename from external/skewer-main/config/.gitignore rename to external/skewer/config/.gitignore diff --git a/external/skewer-main/config/.plano.py b/external/skewer/config/.plano.py similarity index 100% rename from external/skewer-main/config/.plano.py rename to external/skewer/config/.plano.py diff --git a/external/skewer-main/example/.gitignore b/external/skewer/example/.gitignore similarity index 100% rename from external/skewer-main/example/.gitignore rename to external/skewer/example/.gitignore diff --git a/external/skewer-main/example/.plano.py b/external/skewer/example/.plano.py similarity index 100% rename from external/skewer-main/example/.plano.py rename to external/skewer/example/.plano.py diff --git a/external/skewer-main/example/README.md b/external/skewer/example/README.md similarity index 52% rename from external/skewer-main/example/README.md rename to external/skewer/example/README.md index 39b2ac4..aed9d8d 100644 --- a/external/skewer-main/example/README.md +++ b/external/skewer/example/README.md @@ -16,17 +16,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: Configure separate console sessions](#step-2-configure-separate-console-sessions) -* [Step 3: Access your clusters](#step-3-access-your-clusters) -* [Step 4: Set up your namespaces](#step-4-set-up-your-namespaces) -* [Step 5: Install Skupper in your namespaces](#step-5-install-skupper-in-your-namespaces) -* [Step 6: Check the status of your namespaces](#step-6-check-the-status-of-your-namespaces) -* [Step 7: Link your namespaces](#step-7-link-your-namespaces) -* [Step 8: Fail on demand](#step-8-fail-on-demand) -* [Step 9: Deploy the application](#step-9-deploy-the-application) -* [Step 10: Expose the backend service](#step-10-expose-the-backend-service) -* [Step 11: Test the application](#step-11-test-the-application) -* [Accessing the web console](#accessing-the-web-console) +* [Step 2: Set up your namespaces](#step-2-set-up-your-namespaces) +* [Step 3: Deploy the frontent and backend](#step-3-deploy-the-frontent-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) * [Cleaning up](#cleaning-up) * [Summary](#summary) * [Next steps](#next-steps) @@ -42,9 +38,9 @@ Some prerequisites ## Step 1: Install the Skupper command-line tool -The `skupper` command-line tool is the entrypoint for installing -and configuring Skupper. You need to install the `skupper` -command only once for each development environment. +This example uses the Skupper command-line tool to deploy Skupper. +You need to install the `skupper` command only once for each +development environment. On Linux or Mac, you can use the install script (inspect it [here][install-script]) to download and extract the command: @@ -62,12 +58,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: Configure separate console sessions +## Step 2: Set up your namespaces -Skupper is designed for use with multiple 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 namespaces, +usually on different clusters. The `skupper` and `kubectl` +commands use your [kubeconfig][kubeconfig] and current context to +select the namespace where they operate. [kubeconfig]: https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/ @@ -79,72 +75,81 @@ A single kubeconfig supports only one active context per user. Since you will be using multiple contexts at once in this exercise, you need to create distinct kubeconfigs. -Start a console session for each of your namespaces. Set the -`KUBECONFIG` environment variable to a different path in each -session. +For each namespace, open a new terminal window. In each terminal, +set the `KUBECONFIG` environment variable to a different path and +log in to your cluster. Then create the namespace you wish to use +and set the namespace on your current context. -_**Console for West:**_ +**Note:** The login procedure varies by provider. See the +documentation for yours: + +* [Minikube](https://skupper.io/start/minikube.html#cluster-access) +* [Amazon Elastic Kubernetes Service (EKS)](https://skupper.io/start/eks.html#cluster-access) +* [Azure Kubernetes Service (AKS)](https://skupper.io/start/aks.html#cluster-access) +* [Google Kubernetes Engine (GKE)](https://skupper.io/start/gke.html#cluster-access) +* [IBM Kubernetes Service](https://skupper.io/start/ibmks.html#cluster-access) +* [OpenShift](https://skupper.io/start/openshift.html#cluster-access) + +_**West:**_ ~~~ shell export KUBECONFIG=~/.kube/config-west +# Enter your provider-specific login command +kubectl create namespace west +kubectl config set-context --current --namespace west ~~~ -_**Console for East:**_ +_**East:**_ ~~~ shell export KUBECONFIG=~/.kube/config-east +# Enter your provider-specific login command +kubectl create namespace east +kubectl config set-context --current --namespace east ~~~ -## Step 3: Access your clusters - -The procedure for accessing a Kubernetes cluster varies by -provider. [Find the instructions for your chosen -provider][kube-providers] and use them to authenticate and -configure access for each console session. - -[kube-providers]: https://skupper.io/start/kubernetes.html +## Step 3: Deploy the frontent and backend -## Step 4: Set up your namespaces +This example runs the frontend and the backend in separate +Kubernetes namespaces, on different clusters. -Use `kubectl create namespace` to create the namespaces you wish -to use (or use existing namespaces). Use `kubectl config -set-context` to set the current namespace for each session. +Use `kubectl create deployment` to deploy the frontend in +namespace `west` and the backend in namespace +`east`. -_**Console for West:**_ +_**West:**_ ~~~ shell -kubectl create namespace west -kubectl config set-context --current --namespace west +kubectl create deployment frontend --image quay.io/skupper/hello-world-frontend ~~~ -_**Console for East:**_ +_**East:**_ ~~~ shell -kubectl create namespace east -kubectl config set-context --current --namespace east +kubectl create deployment backend --image quay.io/skupper/hello-world-backend --replicas 3 ~~~ -## Step 5: Install Skupper in your namespaces - -The `skupper init` command installs the Skupper router and -controller in the current namespace. Run the `skupper init` command -in each namespace. +## Step 4: Create your sites -**Note:** If you are using Minikube, [you need to start `minikube -tunnel`][minikube-tunnel] before you install Skupper. +A Skupper _site_ is a location where components of your +application are running. Sites are linked together to form a +network for your application. In Kubernetes, a site is associated +with a namespace. -[minikube-tunnel]: https://skupper.io/start/minikube.html#running-minikube-tunnel +For each namespace, use `skupper init` to create a site. This +deploys the Skupper router and controller. Then use `skupper +status` to see the outcome. -_**Console for West:**_ +**Note:** If you are using Minikube, you need to [start minikube +tunnel][minikube-tunnel] before you run `skupper init`. -~~~ shell -skupper init --enable-console --enable-flow-collector -~~~ +[minikube-tunnel]: https://skupper.io/start/minikube.html#running-minikube-tunnel -_**Console for East:**_ +_**West:**_ ~~~ shell skupper init +skupper status ~~~ _Sample output:_ @@ -153,58 +158,54 @@ _Sample output:_ $ skupper init Waiting for LoadBalancer IP or hostname... Waiting for status... -Skupper is now installed in namespace ''. Use 'skupper status' to get more information. -~~~ - -## Step 6: Check the status of your namespaces - -Use `skupper status` in each console to check that Skupper is -installed. +Skupper is now installed in namespace 'west'. Use 'skupper status' to get more information. -_**Console for West:**_ - -~~~ shell -skupper status +$ skupper status +Skupper is enabled for namespace "west". It is not connected to any other sites. It has no exposed services. ~~~ -_**Console for East:**_ +_**East:**_ ~~~ shell +skupper init skupper status ~~~ _Sample output:_ ~~~ console +$ skupper init +Waiting for LoadBalancer IP or hostname... +Waiting for status... +Skupper is now installed in namespace 'east'. Use 'skupper status' to get more information. + $ skupper status -Skupper is enabled for namespace "" in interior mode. It is connected to 1 other site. It has 1 exposed service. -The site console url is: -The credentials for internal console-auth mode are held in secret: 'skupper-console-users' +Skupper is enabled for namespace "east". It is not connected to any other sites. It has no exposed services. ~~~ As you move through the steps below, you can use `skupper status` at any time to check your progress. -## Step 7: Link your namespaces +## Step 5: Link your sites 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 namespace, The `skupper link -create` command uses the token to create a link to the namespace +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 namespace. Make sure that only those you -trust have access to it. +token can link to your site. Make sure that only those you trust +have access to it. -First, use `skupper token create` in one namespace to generate the -token. Then, use `skupper link create` in the other to create a -link. +First, use `skupper token create` in site West to generate the +token. Then, use `skupper link create` in site East to link +the sites. -_**Console for West:**_ +_**West:**_ ~~~ shell skupper token create ~/secret.token @@ -217,7 +218,7 @@ $ skupper token create ~/secret.token Token written to ~/secret.token ~~~ -_**Console for East:**_ +_**East:**_ ~~~ shell skupper link create ~/secret.token @@ -231,48 +232,31 @@ Site configured to link to https://10.105.193.154:8081/ed9c37f6-d78a-11ec-a8c7-0 Check the status of the link using 'skupper link status'. ~~~ -If your console sessions are on different machines, you may need +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. -## Step 8: Fail on demand +## Step 6: Fail on demand -_**Console for West:**_ +_**West:**_ ~~~ shell if [ -n "${SKEWER_FAIL}" ]; then expr 1 / 0; fi ~~~ -## Step 9: Deploy the application +## Step 7: Expose the backend -Use `kubectl create deployment` to deploy the frontend and backend -services. +We now have our sites linked to form a Skupper network, but no +services are exposed on it. Skupper uses the `skupper expose` +command to select a service from one site for exposure in all the +linked sites. -_**Console for West:**_ - -~~~ shell -kubectl create deployment frontend --image quay.io/skupper/hello-world-frontend -~~~ +Use `skupper expose` to expose the backend service in East to +the frontend in West. -_**Console for East:**_ - -~~~ shell -kubectl create deployment backend --image quay.io/skupper/hello-world-backend --replicas 3 -~~~ - -## Step 10: Expose the backend service - -We now have two namespaces linked to form a Skupper network, but -no services are exposed on it. Skupper uses the `skupper -expose` command to select a service from one namespace for -exposure in all the linked namespaces. - -Use `skupper expose` to expose the backend service on the Skupper -network. - -_**Console for East:**_ +_**East:**_ ~~~ shell skupper expose deployment/backend --port 8080 @@ -285,11 +269,10 @@ $ skupper expose deployment/backend --port 8080 deployment backend exposed as backend ~~~ -## Step 11: Test the application +## Step 8: Access the frontend -We have established connectivity between the two namespaces and -made the backend available to the frontend. Before we can test -the application, we need external access to 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. @@ -304,7 +287,7 @@ 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. -_**Console for West:**_ +_**West:**_ ~~~ shell kubectl expose deployment/frontend --port 8080 --type LoadBalancer @@ -329,46 +312,12 @@ OK If everything is in order, you can now access the web interface by navigating to `http://:8080/` in your browser. -## Accessing the web console - -Skupper includes a web console you can use to view the application -network. To access it, use `skupper status` to look up the URL of -the web console. Then use `kubectl get -secret/skupper-console-users` to look up the console admin -password. - -**Note:** The `` and `` fields in the -following output are placeholders. The actual values are specific -to your environment. - -_**Console for West:**_ - -~~~ shell -skupper status -kubectl get secret/skupper-console-users -o jsonpath={.data.admin} | base64 -d -~~~ - -_Sample output:_ - -~~~ console -$ skupper status -Skupper is enabled for namespace "west". It is connected to 1 other site. It has 1 exposed service. -The site console url is: -The credentials for internal console-auth mode are held in secret: 'skupper-console-users' - -$ kubectl get secret/skupper-console-users -o jsonpath={.data.admin} | base64 -d - -~~~ - -Navigate to `` in your browser. When prompted, log -in as user `admin` and enter the password. - ## Cleaning up To remove Skupper and the other resources from this exercise, use -the following commands. +the following commands: -_**Console for West:**_ +_**West:**_ ~~~ shell skupper delete @@ -376,7 +325,7 @@ kubectl delete service/frontend kubectl delete deployment/frontend ~~~ -_**Console for East:**_ +_**East:**_ ~~~ shell skupper delete diff --git a/external/skewer-main/example/plano b/external/skewer/example/plano similarity index 100% rename from external/skewer-main/example/plano rename to external/skewer/example/plano diff --git a/external/skewer/example/python/plano b/external/skewer/example/python/plano new file mode 120000 index 0000000..2366248 --- /dev/null +++ b/external/skewer/example/python/plano @@ -0,0 +1 @@ +../../python/plano \ No newline at end of file diff --git a/external/skewer/example/python/skewer b/external/skewer/example/python/skewer new file mode 120000 index 0000000..d33ad4b --- /dev/null +++ b/external/skewer/example/python/skewer @@ -0,0 +1 @@ +../../python/skewer \ No newline at end of file diff --git a/external/skewer-main/example/skewer.yaml b/external/skewer/example/skewer.yaml similarity index 61% rename from external/skewer-main/example/skewer.yaml rename to external/skewer/example/skewer.yaml index bb36722..afc0b6b 100644 --- a/external/skewer-main/example/skewer.yaml +++ b/external/skewer/example/skewer.yaml @@ -19,21 +19,17 @@ sites: KUBECONFIG: ~/.kube/config-east steps: - standard: install_the_skupper_command_line_tool - - standard: configure_separate_console_sessions - - standard: access_your_clusters - - standard: set_up_your_namespaces - - standard: install_skupper_in_your_namespaces - - standard: check_the_status_of_your_namespaces - - standard: link_your_namespaces + - standard: kubernetes/set_up_your_namespaces + - standard: hello_world/deploy_the_frontend_and_backend + - standard: kubernetes/create_your_sites + - standard: link_your_sites - title: Fail on demand commands: west: - run: | if [ -n "${SKEWER_FAIL}" ]; then expr 1 / 0; fi - - standard: hello_world/deploy_the_application - - standard: hello_world/expose_the_backend_service - - standard: hello_world/test_the_application - - standard: accessing_the_web_console + - standard: hello_world/expose_the_backend + - standard: hello_world/access_the_frontend - standard: hello_world/cleaning_up summary: | A summary diff --git a/external/skewer-main/external/plano-main/.github/workflows/main.yaml b/external/skewer/external/plano/.github/workflows/main.yaml similarity index 100% rename from external/skewer-main/external/plano-main/.github/workflows/main.yaml rename to external/skewer/external/plano/.github/workflows/main.yaml diff --git a/external/skewer-main/external/plano-main/.gitignore b/external/skewer/external/plano/.gitignore similarity index 100% rename from external/skewer-main/external/plano-main/.gitignore rename to external/skewer/external/plano/.gitignore diff --git a/external/skewer-main/external/plano-main/LICENSE.txt b/external/skewer/external/plano/LICENSE.txt similarity index 100% rename from external/skewer-main/external/plano-main/LICENSE.txt rename to external/skewer/external/plano/LICENSE.txt diff --git a/external/skewer-main/external/plano-main/MANIFEST.in b/external/skewer/external/plano/MANIFEST.in similarity index 100% rename from external/skewer-main/external/plano-main/MANIFEST.in rename to external/skewer/external/plano/MANIFEST.in diff --git a/external/skewer-main/external/plano-main/Makefile b/external/skewer/external/plano/Makefile similarity index 100% rename from external/skewer-main/external/plano-main/Makefile rename to external/skewer/external/plano/Makefile diff --git a/external/skewer-main/external/plano-main/README.md b/external/skewer/external/plano/README.md similarity index 100% rename from external/skewer-main/external/plano-main/README.md rename to external/skewer/external/plano/README.md diff --git a/external/skewer-main/external/plano-main/bin/plano b/external/skewer/external/plano/bin/plano similarity index 100% rename from external/skewer-main/external/plano-main/bin/plano rename to external/skewer/external/plano/bin/plano diff --git a/external/skewer-main/external/plano-main/bin/plano-test b/external/skewer/external/plano/bin/plano-test similarity index 100% rename from external/skewer-main/external/plano-main/bin/plano-test rename to external/skewer/external/plano/bin/plano-test diff --git a/external/skewer-main/external/plano-main/docs/conf.py b/external/skewer/external/plano/docs/conf.py similarity index 100% rename from external/skewer-main/external/plano-main/docs/conf.py rename to external/skewer/external/plano/docs/conf.py diff --git a/external/skewer-main/external/plano-main/docs/index.rst b/external/skewer/external/plano/docs/index.rst similarity index 100% rename from external/skewer-main/external/plano-main/docs/index.rst rename to external/skewer/external/plano/docs/index.rst diff --git a/external/skewer-main/external/plano-main/pyproject.toml b/external/skewer/external/plano/pyproject.toml similarity index 100% rename from external/skewer-main/external/plano-main/pyproject.toml rename to external/skewer/external/plano/pyproject.toml diff --git a/external/skewer-main/external/plano-main/src/plano/__init__.py b/external/skewer/external/plano/src/plano/__init__.py similarity index 100% rename from external/skewer-main/external/plano-main/src/plano/__init__.py rename to external/skewer/external/plano/src/plano/__init__.py diff --git a/external/skewer-main/external/plano-main/src/plano/_testproject/.plano.py b/external/skewer/external/plano/src/plano/_testproject/.plano.py similarity index 97% rename from external/skewer-main/external/plano-main/src/plano/_testproject/.plano.py rename to external/skewer/external/plano/src/plano/_testproject/.plano.py index 67904b2..8cda2e7 100644 --- a/external/skewer-main/external/plano-main/src/plano/_testproject/.plano.py +++ b/external/skewer/external/plano/src/plano/_testproject/.plano.py @@ -35,7 +35,7 @@ def extended_command(alpha, beta, omega="y"): @command(parameters=[CommandParameter("message_", help="The message to print", display_name="message"), CommandParameter("count", help="Print the message COUNT times"), CommandParameter("extra", default=1, short_option="e")]) -def echo(message_, count=1, extra=None, trouble=False): +def echo(message_, count=1, extra=None, trouble=False, verbose=False): """ Print a message to the console """ diff --git a/external/skewer-main/external/plano-main/src/plano/_testproject/src/chucker/__init__.py b/external/skewer/external/plano/src/plano/_testproject/src/chucker/__init__.py similarity index 100% rename from external/skewer-main/external/plano-main/src/plano/_testproject/src/chucker/__init__.py rename to external/skewer/external/plano/src/plano/_testproject/src/chucker/__init__.py diff --git a/external/skewer/external/plano/src/plano/_testproject/src/chucker/moretests.py b/external/skewer/external/plano/src/plano/_testproject/src/chucker/moretests.py new file mode 100644 index 0000000..2607880 --- /dev/null +++ b/external/skewer/external/plano/src/plano/_testproject/src/chucker/moretests.py @@ -0,0 +1,24 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +from plano import * + +@test +def hello_again(): + print("Hello again") diff --git a/external/skewer-main/external/plano-main/src/plano/_testproject/src/chucker/tests.py b/external/skewer/external/plano/src/plano/_testproject/src/chucker/tests.py similarity index 95% rename from external/skewer-main/external/plano-main/src/plano/_testproject/src/chucker/tests.py rename to external/skewer/external/plano/src/plano/_testproject/src/chucker/tests.py index 144a157..4e0cec1 100644 --- a/external/skewer-main/external/plano-main/src/plano/_testproject/src/chucker/tests.py +++ b/external/skewer/external/plano/src/plano/_testproject/src/chucker/tests.py @@ -63,3 +63,8 @@ def test_widget(message): for message in "hi", "lo", "in between": add_test(f"message-{message}", test_widget, message) + +@test(disabled=True) +def badbye2(): + print("Badbye 2") + assert False diff --git a/external/skewer-main/external/plano-main/src/plano/_tests.py b/external/skewer/external/plano/src/plano/_tests.py similarity index 95% rename from external/skewer-main/external/plano-main/src/plano/_tests.py rename to external/skewer/external/plano/src/plano/_tests.py index c4dc0a8..159c739 100644 --- a/external/skewer-main/external/plano-main/src/plano/_tests.py +++ b/external/skewer/external/plano/src/plano/_tests.py @@ -25,6 +25,8 @@ import sys as _sys import threading as _threading +from .github import * + try: import http.server as _http except ImportError: # pragma: nocover @@ -52,15 +54,15 @@ def archive_operations(): assert is_file("some-dir.tar.gz"), list_dir() extract_archive("some-dir.tar.gz", output_dir="some-subdir") - assert is_dir("some-subdir/some-dir") - assert is_file("some-subdir/some-dir/some-file") + assert is_dir("some-subdir/some-dir"), list_dir("some-subdir") + assert is_file("some-subdir/some-dir/some-file"), list_dir("some-subdir/some-dir") rename_archive("some-dir.tar.gz", "something-else") - assert is_file("something-else.tar.gz") + assert is_file("something-else.tar.gz"), list_dir() extract_archive("something-else.tar.gz") - assert is_dir("something-else") - assert is_file("something-else/some-file") + assert is_dir("something-else"), list_dir() + assert is_file("something-else/some-file"), list_dir("something-else") @test def command_operations(): @@ -94,6 +96,7 @@ def run(self): print("Hello") SomeCommand().main([]) + SomeCommand().main(["--verbose"]) SomeCommand().main(["--interrupt"]) with expect_system_exit(): @@ -311,6 +314,39 @@ def file_operations(): result = get_file_size(file) assert result == 10, result + zeta_dir = make_dir("zeta-dir") + zeta_file = touch(join(zeta_dir, "zeta-file")) + + eta_dir = make_dir("eta-dir") + eta_file = touch(join(eta_dir, "eta-file")) + + replace(zeta_dir, eta_dir) + assert not exists(zeta_file) + assert exists(zeta_dir) + assert is_file(join(zeta_dir, "eta-file")) + + with expect_exception(): + replace(zeta_dir, "not-there") + + assert exists(zeta_dir) + assert is_file(join(zeta_dir, "eta-file")) + + theta_file = write("theta-file", "theta") + iota_file = write("iota-file", "iota") + + replace(theta_file, iota_file) + assert not exists(iota_file) + assert read(theta_file) == "iota" + +@test +def github_operations(): + result = convert_github_markdown("# Hello, Fritz") + assert "Hello, Fritz" in result, result + + with working_dir(): + update_external_from_github("temp", "ssorj", "plano") + assert is_file("temp/Makefile"), list_dir("temp") + @test def http_operations(): class Handler(_http.BaseHTTPRequestHandler): @@ -467,7 +503,7 @@ def io_operations(): assert is_file(file_c), file_c file_d = write("d", "front@middle@@middle@back") - path = replace_in_file(file_d, "@middle@", "M", count=1) + path = string_replace_file(file_d, "@middle@", "M", count=1) result = read(path) assert result == "frontM@middle@back", result @@ -825,10 +861,10 @@ def process_operations(): @test def string_operations(): - result = replace("ab", "a", "b") + result = string_replace("ab", "a", "b") assert result == "bb", result - result = replace("aba", "a", "b", count=1) + result = string_replace("aba", "a", "b", count=1) assert result == "bba", result result = remove_prefix(None, "xxx") @@ -944,6 +980,7 @@ def test_operations(): with working_module_path("src"): import chucker import chucker.tests + import chucker.moretests print_tests(chucker.tests) @@ -965,6 +1002,9 @@ def test_operations(): with expect_error(): run_tests(chucker.tests, enable="*badbye*", fail_fast=True, verbose=verbose) + with expect_error(): + run_tests([chucker.tests, chucker.moretests], enable="*badbye2*", fail_fast=True, verbose=verbose) + with expect_exception(KeyboardInterrupt): run_tests(chucker.tests, enable="keyboard-interrupt", verbose=verbose) @@ -1289,6 +1329,8 @@ def run_command(*args): result = read_json("invisible.json") assert result == "nothing" + + def main(): PlanoTestCommand(_sys.modules[__name__]).main() diff --git a/external/skewer-main/external/plano-main/src/plano/command.py b/external/skewer/external/plano/src/plano/command.py similarity index 98% rename from external/skewer-main/external/plano-main/src/plano/command.py rename to external/skewer/external/plano/src/plano/command.py index 83ab041..219f964 100644 --- a/external/skewer-main/external/plano-main/src/plano/command.py +++ b/external/skewer/external/plano/src/plano/command.py @@ -260,7 +260,7 @@ def _process_commands(self): help="Print no logging to the console") for param in command.parameters.values(): - if param.name in ("verbose", "quiet"): + if not command.passthrough and param.name in ("verbose", "quiet"): continue if param.positional: @@ -322,11 +322,13 @@ def __init__(self, function): self.name = nvl(self.name, default) self.parameters = self._process_parameters(parameters) + self.passthrough = passthrough else: assert parameters is None self.name = nvl(self.name, self.parent.name) self.parameters = self.parent.parameters + self.passthrough = self.parent.passthrough doc = _inspect.getdoc(self.function) @@ -341,7 +343,6 @@ def __init__(self, function): self.help = nvl(self.help, self.parent.help) self.description = nvl(self.description, self.parent.description) - self.passthrough = passthrough self.hidden = hidden debug("Defining {}", self) diff --git a/external/skewer/external/plano/src/plano/github.py b/external/skewer/external/plano/src/plano/github.py new file mode 100644 index 0000000..e1714b5 --- /dev/null +++ b/external/skewer/external/plano/src/plano/github.py @@ -0,0 +1,80 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +from .main import * + +_html_template = """ + + + + + + +
+ +@content@ + +
+ + +""".strip() + +def convert_github_markdown(markdown): + json = emit_json({"text": markdown}) + content = http_post("https://api.github.com/markdown", json, content_type="application/json") + + # Remove the "user-content-" prefix from internal anchors + content = content.replace("id=\"user-content-", "id=\"") + + return _html_template.replace("@content@", content) + +def update_external_from_github(dir, owner, repo, ref="main"): + dir = get_absolute_path(dir) + make_parent_dir(dir) + + url = f"https://github.com/{owner}/{repo}/archive/{ref}.tar.gz" + + with temp_file() as temp: + assert exists(temp) + + http_get(url, output_file=temp) + + with working_dir(quiet=True): + extract_archive(temp) + + extracted_dir = list_dir()[0] + assert is_dir(extracted_dir) + + replace(dir, extracted_dir) diff --git a/external/skewer-main/external/plano-main/src/plano/main.py b/external/skewer/external/plano/src/plano/main.py similarity index 94% rename from external/skewer-main/external/plano-main/src/plano/main.py rename to external/skewer/external/plano/src/plano/main.py index 6b70539..903f654 100644 --- a/external/skewer-main/external/plano-main/src/plano/main.py +++ b/external/skewer/external/plano/src/plano/main.py @@ -74,22 +74,21 @@ class PlanoTimeout(PlanoException): ## Archive operations def make_archive(input_dir, output_file=None, quiet=False): - """ - group: archive_operations - """ - check_program("tar") archive_stem = get_base_name(input_dir) if output_file is None: - output_file = "{}.tar.gz".format(join(get_current_dir(), archive_stem)) + # tar on Windows needs this + base = join(get_current_dir(), archive_stem) + base = base.replace("\\", "/") + + output_file = f"{base}.tar.gz" _notice(quiet, "Making archive {} from directory {}", repr(output_file), repr(input_dir)) - with working_dir(get_parent_dir(input_dir)): - run("tar -czf temp.tar.gz {}".format(archive_stem)) - move("temp.tar.gz", output_file) + with working_dir(get_parent_dir(input_dir), quiet=True): + run(f"tar -czf {output_file} {archive_stem}", quiet=True) return output_file @@ -103,13 +102,11 @@ def extract_archive(input_file, output_dir=None, quiet=False): input_file = get_absolute_path(input_file) - with working_dir(output_dir): - copy(input_file, "temp.tar.gz") + # tar on Windows needs this + input_file = input_file.replace("\\", "/") - try: - run("tar -xf temp.tar.gz") - finally: - remove("temp.tar.gz") + with working_dir(output_dir, quiet=True): + run(f"tar -xf {input_file}", quiet=True) return output_dir @@ -119,17 +116,20 @@ def rename_archive(input_file, new_archive_stem, quiet=False): output_dir = get_absolute_path(get_parent_dir(input_file)) output_file = "{}.tar.gz".format(join(output_dir, new_archive_stem)) + # tar on Windows needs this + output_file = output_file.replace("\\", "/") + input_file = get_absolute_path(input_file) - with working_dir(): - extract_archive(input_file) + with working_dir(quiet=True): + extract_archive(input_file, quiet=True) input_name = list_dir()[0] - input_dir = move(input_name, new_archive_stem) + input_dir = move(input_name, new_archive_stem, quiet=True) - make_archive(input_dir, output_file=output_file) + make_archive(input_dir, output_file=output_file, quiet=True) - remove(input_file) + remove(input_file, quiet=True) return output_file @@ -543,6 +543,36 @@ def move(from_path, to_path, inside=True, quiet=False): return to_path +def replace(path, replacement, quiet=False): + path = expand(path) + replacement = expand(replacement) + + _notice(quiet, "Replacing {} with {}", repr(path), repr(replacement)) + + with temp_dir() as backup_dir: + backup = join(backup_dir, "backup") + backup_created = False + + if exists(path): + move(path, backup, quiet=True) + backup_created = True + + try: + move(replacement, path, quiet=True) + except OSError: + notice("Removing") + remove(path, quiet=True) + + if backup_created: + move(backup, path, quiet=True) + + raise + + assert not exists(replacement), replacement + assert exists(path), path + + return path + def remove(paths, quiet=False): if is_string(paths): paths = (paths,) @@ -649,9 +679,9 @@ def tail_lines(file, count): return lines[-count:] -def replace_in_file(file, expr, replacement, count=0): +def string_replace_file(file, expr, replacement, count=0): file = expand(file) - return write(file, replace(read(file), expr, replacement, count=count)) + return write(file, string_replace(read(file), expr, replacement, count=count)) def concatenate(file, input_files): file = expand(file) @@ -717,9 +747,11 @@ def print_json(data, **kwargs): ## HTTP operations def _run_curl(method, url, content=None, content_file=None, content_type=None, output_file=None, insecure=False, - user=None, password=None): + user=None, password=None, quiet=False): check_program("curl") + _notice(quiet, f"Sending {method} request to '{url}'") + args = ["curl", "-sfL"] if method != "GET": @@ -760,33 +792,37 @@ def _run_curl(method, url, content=None, content_file=None, content_type=None, o if output_file is None: return proc.stdout_result -def http_get(url, output_file=None, insecure=False, user=None, password=None): - return _run_curl("GET", url, output_file=output_file, insecure=insecure, user=user, password=password) +def http_get(url, output_file=None, insecure=False, user=None, password=None, quiet=False): + return _run_curl("GET", url, output_file=output_file, insecure=insecure, user=user, password=password, quiet=quiet) -def http_get_json(url, insecure=False, user=None, password=None): - return parse_json(http_get(url, insecure=insecure, user=user, password=password)) +def http_get_json(url, insecure=False, user=None, password=None, quiet=False): + return parse_json(http_get(url, insecure=insecure, user=user, password=password, quiet=quiet)) -def http_put(url, content, content_type=None, insecure=False, user=None, password=None): - _run_curl("PUT", url, content=content, content_type=content_type, insecure=insecure, user=user, password=password) +def http_put(url, content, content_type=None, insecure=False, user=None, password=None, quiet=False): + _run_curl("PUT", url, content=content, content_type=content_type, insecure=insecure, user=user, password=password, + quiet=quiet) -def http_put_file(url, content_file, content_type=None, insecure=False, user=None, password=None): +def http_put_file(url, content_file, content_type=None, insecure=False, user=None, password=None, quiet=False): _run_curl("PUT", url, content_file=content_file, content_type=content_type, insecure=insecure, user=user, - password=password) + password=password, quiet=quiet) -def http_put_json(url, data, insecure=False, user=None, password=None): - http_put(url, emit_json(data), content_type="application/json", insecure=insecure, user=user, password=password) +def http_put_json(url, data, insecure=False, user=None, password=None, quiet=False): + http_put(url, emit_json(data), content_type="application/json", insecure=insecure, user=user, password=password, + quiet=quiet) -def http_post(url, content, content_type=None, output_file=None, insecure=False, user=None, password=None): +def http_post(url, content, content_type=None, output_file=None, insecure=False, user=None, password=None, + quiet=False): return _run_curl("POST", url, content=content, content_type=content_type, output_file=output_file, - insecure=insecure, user=user, password=password) + insecure=insecure, user=user, password=password, quiet=quiet) -def http_post_file(url, content_file, content_type=None, output_file=None, insecure=False, user=None, password=None): +def http_post_file(url, content_file, content_type=None, output_file=None, insecure=False, user=None, password=None, + quiet=False): return _run_curl("POST", url, content_file=content_file, content_type=content_type, output_file=output_file, - insecure=insecure, user=user, password=password) + insecure=insecure, user=user, password=password, quiet=quiet) -def http_post_json(url, data, insecure=False, user=None, password=None): +def http_post_json(url, data, insecure=False, user=None, password=None, quiet=False): return parse_json(http_post(url, emit_json(data), content_type="application/json", insecure=insecure, user=user, - password=password)) + password=password, quiet=quiet)) ## Link operations @@ -1381,7 +1417,7 @@ def _default_sigterm_handler(signum, frame): ## String operations -def replace(string, expr, replacement, count=0): +def string_replace(string, expr, replacement, count=0): return _re.sub(expr, replacement, string, count) def remove_prefix(string, prefix): diff --git a/external/skewer-main/external/plano-main/src/plano/test.py b/external/skewer/external/plano/src/plano/test.py similarity index 100% rename from external/skewer-main/external/plano-main/src/plano/test.py rename to external/skewer/external/plano/src/plano/test.py diff --git a/external/skewer-main/plano b/external/skewer/plano similarity index 100% rename from external/skewer-main/plano rename to external/skewer/plano diff --git a/external/skewer/python/plano b/external/skewer/python/plano new file mode 120000 index 0000000..e9b6dc5 --- /dev/null +++ b/external/skewer/python/plano @@ -0,0 +1 @@ +../external/plano/src/plano \ No newline at end of file diff --git a/external/skewer-main/python/skewer/__init__.py b/external/skewer/python/skewer/__init__.py similarity index 100% rename from external/skewer-main/python/skewer/__init__.py rename to external/skewer/python/skewer/__init__.py diff --git a/external/skewer-main/python/skewer/main.py b/external/skewer/python/skewer/main.py similarity index 95% rename from external/skewer-main/python/skewer/main.py rename to external/skewer/python/skewer/main.py index c16be4e..052b456 100644 --- a/external/skewer-main/python/skewer/main.py +++ b/external/skewer/python/skewer/main.py @@ -96,7 +96,7 @@ def await_http_ok(service, url_template, user=None, password=None, timeout=240): notice(f"Waiting for HTTP OK from {url}") try: - http_get(url, insecure=insecure, user=user, password=password) + http_get(url, insecure=insecure, user=user, password=password, quiet=True) except PlanoError: if get_time() - start_time > timeout: fail(f"Timed out waiting for HTTP OK from {url}") @@ -179,7 +179,7 @@ def run_step(model, step, work_dir, check=True): def pause_for_demo(model): notice("Pausing for demo time") - first_site = list([x for _, x in model.sites])[0] + first_site = [x for _, x in model.sites][0] console_url = None password = None frontend_url = None @@ -187,7 +187,7 @@ def pause_for_demo(model): if first_site.platform == "kubernetes": with first_site: if resource_exists("service/frontend"): - if rsource_jsonpath("service/frontend", ".spec.type") == "LoadBalancer": + if get_resource_jsonpath("service/frontend", ".spec.type") == "LoadBalancer": frontend_ip = await_external_ip("service/frontend") frontend_url = f"http://{frontend_ip}:8080/" @@ -284,9 +284,9 @@ def append_toc_entry(heading, condition=True): if not condition: return - fragment = replace(heading, r"[ -]", "_") - fragment = replace(fragment, r"[\W]", "") - fragment = replace(fragment, "_", "-") + fragment = string_replace(heading, r"[ -]", "_") + fragment = string_replace(fragment, r"[\W]", "") + fragment = string_replace(fragment, "_", "-") fragment = fragment.lower() out.append(f"* [{heading}](#{fragment})") @@ -357,7 +357,7 @@ def generate_readme_step(model, step): site = dict(model.sites)[site_name] outputs = list() - out.append(f"_**Console for {site.title}:**_") + out.append(f"_**{site.title}:**_") out.append("") out.append("~~~ shell") @@ -416,7 +416,16 @@ def apply_standard_steps(model): def apply_attribute(name, default=None): if name not in step.data: - step.data[name] = standard_step_data.get(name, default) + value = standard_step_data.get(name, default) + + 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) + + if site.namespace: + value = value.replace(f"@namespace{i}@", site.namespace) + + step.data[name] = value apply_attribute("name") apply_attribute("title") @@ -424,12 +433,17 @@ def apply_attribute(name, default=None): apply_attribute("preamble") apply_attribute("postamble") + platform = standard_step_data.get("platform") + if "commands" not in step.data and "commands" in standard_step_data: step.data["commands"] = dict() for i, item in enumerate(dict(model.sites).items()): site_name, site = item + if platform and site.platform != platform: + continue + if str(i) in standard_step_data["commands"]: # Is a specific index in the standard commands? commands = standard_step_data["commands"][str(i)] @@ -523,7 +537,7 @@ def __repr__(self): return f"model '{self.skewer_file}'" def check(self): - check_required_attributes(self, "title", "subtitle", "sites", "steps") + check_required_attributes(self, "title", "sites", "steps") check_unknown_attributes(self) for _, site in self.sites: diff --git a/external/skewer-main/python/skewer/planocommands.py b/external/skewer/python/skewer/planocommands.py similarity index 65% rename from external/skewer-main/python/skewer/planocommands.py rename to external/skewer/python/skewer/planocommands.py index 28b3130..754fb1e 100644 --- a/external/skewer-main/python/skewer/planocommands.py +++ b/external/skewer/python/skewer/planocommands.py @@ -18,40 +18,9 @@ # from plano import * +from plano.github import * from skewer import * -_render_template = """ - - - - - - -
- -@content@ - -
- - -""".strip() - _debug_param = CommandParameter("debug", help="Produce extra debug output on failure") @command @@ -69,10 +38,7 @@ def render(quiet=False): generate() markdown = read("README.md") - data = {"text": markdown} - json = emit_json(data) - content = http_post("https://api.github.com/markdown", json, content_type="application/json") - html = _render_template.replace("@content@", content) + html = convert_github_markdown(markdown) write("README.html", html) @@ -121,9 +87,5 @@ def update_skewer(): This results in local changes to review and commit. """ - check_program("curl") - - make_dir("external") - remove("external/skewer-main") - run("curl -sfL https://github.com/skupperproject/skewer/archive/main.tar.gz | tar -C external -xz", shell=True) - copy("external/skewer-main/config/.github/workflows/main.yaml", ".github/workflows/main.yaml") + update_external_from_github("external/skewer", "skupperproject", "skewer") + copy("external/skewer/config/.github/workflows/main.yaml", ".github/workflows/main.yaml") diff --git a/external/skewer/python/skewer/standardsteps.yaml b/external/skewer/python/skewer/standardsteps.yaml new file mode 100644 index 0000000..ca128c0 --- /dev/null +++ b/external/skewer/python/skewer/standardsteps.yaml @@ -0,0 +1,292 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +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. + You need to install the `skupper` command only once for each + development environment. + + On Linux or Mac, you can use the install script (inspect it + [here][install-script]) to download and extract the command: + + ~~~ shell + curl https://skupper.io/install.sh | sh + ~~~ + + The script installs the command under your home directory. It + prompts you to add the command to your path if necessary. + + For Windows and other installation options, see [Installing + Skupper][install-docs]. + + [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 + 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. + + [kubeconfig]: https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/ + + Your kubeconfig is stored in a file in your home directory. The + `skupper` and `kubectl` commands use the `KUBECONFIG` environment + variable to locate it. + + A single kubeconfig supports only one active context per user. + Since you will be using multiple contexts at once in this + exercise, you need to create distinct kubeconfigs. + + For each namespace, open a new terminal window. In each terminal, + set the `KUBECONFIG` environment variable to a different path and + log in to your cluster. Then create the namespace you wish to use + and set the namespace on your current context. + + **Note:** The login procedure varies by provider. See the + documentation for yours: + + * [Minikube](https://skupper.io/start/minikube.html#cluster-access) + * [Amazon Elastic Kubernetes Service (EKS)](https://skupper.io/start/eks.html#cluster-access) + * [Azure Kubernetes Service (AKS)](https://skupper.io/start/aks.html#cluster-access) + * [Google Kubernetes Engine (GKE)](https://skupper.io/start/gke.html#cluster-access) + * [IBM Kubernetes Service](https://skupper.io/start/ibmks.html#cluster-access) + * [OpenShift](https://skupper.io/start/openshift.html#cluster-access) + commands: + "*": + - run: export KUBECONFIG=@kubeconfig@ + - run: "# Enter your provider-specific login command" + - run: kubectl create namespace @namespace@ + - run: kubectl config set-context --current --namespace @namespace@ +kubernetes/set_up_your_kubernetes_namespace: + title: Set up your Kubernetes namespace + platform: kubernetes + preamble: | + Open a new terminal window and log in to your cluster. Then + create the namespace you wish to use and set the namespace on your + current context. + + **Note:** The login procedure varies by provider. See the + documentation for your chosen providers: + + * [Minikube](https://skupper.io/start/minikube.html#cluster-access) + * [Amazon Elastic Kubernetes Service (EKS)](https://skupper.io/start/eks.html#cluster-access) + * [Azure Kubernetes Service (AKS)](https://skupper.io/start/aks.html#cluster-access) + * [Google Kubernetes Engine (GKE)](https://skupper.io/start/gke.html#cluster-access) + * [IBM Kubernetes Service](https://skupper.io/start/ibmks.html#cluster-access) + * [OpenShift](https://skupper.io/start/openshift.html#cluster-access) + commands: + "*": + - run: "# Enter your provider-specific login command" + - run: kubectl create namespace @namespace@ + - run: kubectl config set-context --current --namespace @namespace@ +kubernetes/create_your_sites: + title: Create your sites + platform: kubernetes + preamble: | + A Skupper _site_ is a location where components of your + application are running. Sites are linked together to form a + network for your application. In Kubernetes, a site is associated + with a namespace. + + For each namespace, use `skupper init` to create a site. This + deploys the Skupper router and controller. Then use `skupper + status` to see the outcome. + + **Note:** If you are using Minikube, you need to [start minikube + tunnel][minikube-tunnel] before you run `skupper init`. + + [minikube-tunnel]: https://skupper.io/start/minikube.html#running-minikube-tunnel + commands: + "0": + - run: skupper init + output: | + Waiting for LoadBalancer IP or hostname... + Waiting for status... + Skupper is now installed in namespace 'west'. Use 'skupper status' to get more information. + - run: skupper status + output: | + Skupper is enabled for namespace "west". It is not connected to any other sites. It has no exposed services. + "*": + - run: skupper init + output: | + Waiting for LoadBalancer IP or hostname... + Waiting for status... + Skupper is now installed in namespace 'east'. Use 'skupper status' to get more information. + - run: skupper status + output: | + Skupper is enabled for namespace "east". It is not connected to any other sites. It has no exposed services. + 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: + title: Link your sites + preamble: | + 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 site @site0@ to generate the + token. Then, use `skupper link create` in site @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 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 + 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: + 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 +hello_world/deploy_the_frontend_and_backend: + title: Deploy the frontent 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@`. + commands: + "0": + - run: kubectl create deployment frontend --image quay.io/skupper/hello-world-frontend + "1": + - run: kubectl create deployment backend --image quay.io/skupper/hello-world-backend --replicas 3 +hello_world/expose_the_backend: + title: Expose the backend + preamble: | + We now have our sites linked to form a Skupper network, but no + services are exposed on it. Skupper uses the `skupper expose` + command to select a service from one site for exposure in all the + linked sites. + + Use `skupper expose` to expose the backend service in @site1@ to + the frontend in @site0@. + commands: + "1": + - await_resource: deployment/backend + - run: skupper expose deployment/backend --port 8080 + output: deployment backend exposed as backend +hello_world/access_the_frontend: + title: Access the frontend + preamble: | + 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. + commands: + "0": + - run: kubectl expose deployment/frontend --port 8080 --type LoadBalancer + output: service/frontend exposed + - await_resource: service/frontend + - run: kubectl get service/frontend + 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"] + postamble: | + If everything is in order, you can now access the web interface by + navigating to `http://:8080/` in your browser. +hello_world/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: + "0": + - run: skupper delete + - run: kubectl delete service/frontend + - run: kubectl delete deployment/frontend + "1": + - run: skupper delete + - run: kubectl delete deployment/backend diff --git a/external/skewer-main/python/skewer/standardtext.yaml b/external/skewer/python/skewer/standardtext.yaml similarity index 100% rename from external/skewer-main/python/skewer/standardtext.yaml rename to external/skewer/python/skewer/standardtext.yaml diff --git a/external/skewer-main/python/skewer/tests.py b/external/skewer/python/skewer/tests.py similarity index 100% rename from external/skewer-main/python/skewer/tests.py rename to external/skewer/python/skewer/tests.py diff --git a/python/plano b/python/plano index a578137..431570b 120000 --- a/python/plano +++ b/python/plano @@ -1 +1 @@ -../external/skewer-main/python/plano \ No newline at end of file +../external/skewer/python/plano \ No newline at end of file diff --git a/python/skewer b/python/skewer index 6ea41b9..0cc66e2 120000 --- a/python/skewer +++ b/python/skewer @@ -1 +1 @@ -../external/skewer-main/python/skewer \ No newline at end of file +../external/skewer/python/skewer \ No newline at end of file diff --git a/skewer.yaml b/skewer.yaml index 2b74ebc..6055f17 100644 --- a/skewer.yaml +++ b/skewer.yaml @@ -15,12 +15,10 @@ sites: env: KUBECONFIG: ~/.kube/config-private steps: - - standard: configure_separate_console_sessions - - standard: access_your_clusters - - standard: set_up_your_namespaces - - standard: install_skupper_in_your_namespaces - - standard: check_the_status_of_your_namespaces - - standard: link_your_namespaces + - standard: install_the_skupper_command_line_tool + - standard: kubernetes/set_up_your_namespaces + - standard: kubernetes/create_your_sites + - standard: link_your_sites - title: Deploy SERVER preamble: | In the private namespace, use the `kubectl apply` command to @@ -57,7 +55,6 @@ steps: output: | OUTPUT pod "client" deleted - - standard: accessing_the_web_console - standard: cleaning_up commands: private: