Skip to content

Commit

Permalink
Merge pull request #457 from openziti/python-sdk
Browse files Browse the repository at this point in the history
Python SDK (#401)
  • Loading branch information
michaelquigley authored Dec 5, 2023
2 parents 669fdf7 + f1897e7 commit 26e2dff
Show file tree
Hide file tree
Showing 81 changed files with 11,839 additions and 1 deletion.
76 changes: 76 additions & 0 deletions .github/workflows/build-wheels.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
name: build wheels

on:
release:
types: [released]

jobs:
build_wheels:
defaults:
run:
working-directory: sdk/python/sdk/zrok
strategy:
fail-fast: false
matrix:
spec:
- { name: 'linux x86_64', runner: ubuntu-20.04, target: manylinux_2_27_x86_64 }
- { name: 'macOS x86_64', runner: macos-11, target: macosx_10_14_x86_64 }
- { name: 'Windows x86_64', runner: windows-2019, target: win_amd64 }
name: building ${{ matrix.spec.name }}
runs-on: ${{ matrix.spec.runner }}
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0

- name: Setup Python
uses: actions/setup-python@v3
with:
python-version: '3.x'

- name: Install Python Tools
run: python -m pip install -U pip setuptools

- name: Build distro
env:
ZROK_VERSION: ${{ github.event.release.tag_name }}
run: |
python setup.py sdist
- uses: actions/upload-artifact@v3
if: startsWith(matrix.spec.name, 'linux')
with:
name: zrok_sdk
path: ${{ github.workspace }}/sdk/python/sdk/zrok/dist/*

publish:
runs-on: ubuntu-20.04
needs: [ build_wheels ]
permissions:
id-token: write
steps:
- name: Download artifacts
uses: actions/download-artifact@v3
with:
path: download

- name: check
run: |
ls -lR download
mkdir dist
cp download/*/* dist
- name: Publish wheels (TestPYPI)
uses: pypa/gh-action-pypi-publish@release/v1
with:
repository-url: https://test.pypi.org/legacy/
packages_dir: dist
skip_existing: true
verbose: true

- name: Publish wheels (PyPI)
uses: pypa/gh-action-pypi-publish@release/v1
with:
packages_dir: dist
verbose: true
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ etc/dev-frontend.yml
.docusaurus
.cache-loader

sdk/python/sdk/build/

# Misc
.DS_Store
.env.local
Expand All @@ -24,6 +26,7 @@ etc/dev-frontend.yml
.env.production.local
go.work
go.work.sum
zrok-venv

npm-debug.log*
yarn-debug.log*
Expand Down
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

## v0.4.18

CHANGE: Moved the golang zrok sdk into `sdk/golang/sdk` to normalize location for future sdk's.
FEATURE: Python sdk added. Can be found on [pypi](https://test.pypi.org/project/zrok-sdk). `pastebin` example illustrates basic SDK usage (see `sdk/python/examples/README.md` for details) (https://github.com/openziti/zrok/issues/401)

CHANGE: Moved the golang zrok sdk into `sdk/golang/sdk` to normalize location for future sdk's.

CHANGE: add restart policies to docker compose samples used by the guide docs, e.g., reserved public share should auto-start on boot, temp public share should not.

Expand Down
9 changes: 9 additions & 0 deletions bin/generate_rest.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,19 @@ command -v openapi >/dev/null 2>&1 || {
echo >&2 "command 'openapi' not installed. see: https://www.npmjs.com/package/openapi-client for installation"
}

command -v swagger-codegen 2>&1 || {
echo >&2 "command 'swagger-codegen. see: https://github.com/swagger-api/swagger-codegen for installation"
}

scriptPath=$(realpath $0)
scriptDir=$(dirname "$scriptPath")

zrokDir=$(realpath "$scriptDir/..")

zrokSpec=$(realpath "$zrokDir/specs/zrok.yml")

pythonConfig=$(realpath "$zrokDir/bin/python_config.json")

echo "...generating zrok server"
swagger generate server -P rest_model_zrok.Principal -f "$zrokSpec" -s rest_server_zrok -t "$zrokDir" -m "rest_model_zrok" --exclude-main

Expand All @@ -27,4 +33,7 @@ swagger generate client -P rest_model_zrok.Principal -f "$zrokSpec" -c rest_clie
echo "...generating js client"
openapi -s specs/zrok.yml -o ui/src/api -l js

echo "...generating python client"
swagger-codegen generate -i specs/zrok.yml -o sdk/python/sdk/zrok -c $pythonConfig -l python

git checkout rest_server_zrok/configure_zrok.go
4 changes: 4 additions & 0 deletions bin/python_config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"packageName":"zrok_api",
"projectName":"zrok_sdk"
}
55 changes: 55 additions & 0 deletions sdk/python/examples/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# zrok Pastebin

This example shows the use of the zrok SDK spinning up a simple pastebin command.

## Self-hosting Setup :wrench:

You don't need this section if you're using hosted zrok from NetFoundry (https://api.zrok.io/).

Refer to the [setup guide](../../../docs/guides/self-hosting/self_hosting_guide.md) for details on setting up your zrok
environment if you're self-hosting zrok.

### Install Python Requirements

The zrok SDK requires Python 3.10 or later.

If you haven't already installed them, you'll need the dependent libraries used in the examples.

```bash
pip install -r ./sdk/python/examples/requirements.txt
```

## Running the Example :arrow_forward:

This example contains a `copyto` server portion and `pastefrom` client portion.

### copyto

The server portion expects to get data you want to send via stdin. It can be evoked by:

```bash
echo "this is a cool test" | python pastebin.py copyto
```

You should see some helpful info printed out to your terminal:

```bash
access your pastebin using 'pastebin.py pastefrom vp0xgmknvisu'
```

The last token in that line is your share token. We'll use that in the pastefrom command to access our data.

### pastefrom

The `pastefrom` client expects the share token as an argument.
If we envoke it using the same token as above:

```bash
python pastebin.py pastefrom vp0xgmknvisu
```

we see the data we had piped into the `copyto` server:

```text
this is a cool test
```
94 changes: 94 additions & 0 deletions sdk/python/examples/pastebin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
#!python3
import argparse
import sys
import os
import zrok
import zrok.listener
import zrok.dialer
from zrok.model import AccessRequest, ShareRequest
import signal
import threading

exit_signal = threading.Event()

def signal_handler(signum, frame):
print("\nCtrl-C detected. Next connection will close server")
exit_signal.set()

class copyto:
def handle(self, *args, **kwargs):
root = zrok.environment.root.Load()

try:
shr = zrok.share.CreateShare(root=root, request=ShareRequest(
BackendMode=zrok.model.TCP_TUNNEL_BACKEND_MODE,
ShareMode=zrok.model.PRIVATE_SHARE_MODE,
Target="pastebin"
))
except Exception as e:
print("unable to create share", e)
sys.exit(1)

data = self.loadData()
print("access your pastebin using 'pastebin.py pastefrom " + shr.Token + "'")

try:
with zrok.listener.Listener(shr.Token, root) as server:
while not exit_signal.is_set():
conn, peer = server.accept()
with conn:
conn.sendall(data.encode('utf-8'))

except KeyboardInterrupt:
pass

zrok.share.DeleteShare(root, shr)
print("Server stopped.")


def loadData(self):
if not os.isatty(sys.stdin.fileno()):
return sys.stdin.read()
else:
raise Exception("'copyto' requires input from stdin; direct your paste buffer into stdin")

def pastefrom(options):
root = zrok.environment.root.Load()

try:
acc = zrok.access.CreateAccess(root=root, request=AccessRequest(
ShareToken=options.shrToken,
))
except Exception as e:
print("unable to create access", e)
sys.exit(1)

client = zrok.dialer.Dialer(options.shrToken, root)
data = client.recv(1024)
print(data.decode('utf-8'))
try:
zrok.access.DeleteAccess(root, acc)
except Exception as e:
print("unable to delete access", e)
sys.exit(1)

if __name__ == "__main__":
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers()
subparsers.required = True

c = copyto()
parser_copyto = subparsers.add_parser('copyto')
parser_copyto.set_defaults(func=c.handle)

parser_pastefrom = subparsers.add_parser('pastefrom')
parser_pastefrom.set_defaults(func=pastefrom)
parser_pastefrom.add_argument("shrToken")

options = parser.parse_args()
signal.signal(signal.SIGINT, signal_handler)
# Create a separate thread to run the server so we can respond to ctrl-c when in 'accept'
server_thread = threading.Thread(target=options.func, args=[options])
server_thread.start()

server_thread.join()
3 changes: 3 additions & 0 deletions sdk/python/examples/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
openziti==0.8.1
requests==2.31.0
zrok-sdk
64 changes: 64 additions & 0 deletions sdk/python/sdk/zrok/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover
.hypothesis/
venv/
.python-version

# Translations
*.mo
*.pot

# Django stuff:
*.log

# Sphinx documentation
docs/_build/

# PyBuilder
target/

#Ipython Notebook
.ipynb_checkpoints
31 changes: 31 additions & 0 deletions sdk/python/sdk/zrok/.swagger-codegen-ignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Swagger Codegen Ignore
# Generated by swagger-codegen https://github.com/swagger-api/swagger-codegen

# Use this file to prevent files from being overwritten by the generator.
# The patterns follow closely to .gitignore or .dockerignore.

# As an example, the C# client generator defines ApiClient.cs.
# You can make changes and tell Swagger Codgen to ignore just this file by uncommenting the following line:
#ApiClient.cs

# You can match any string of characters against a directory, file or extension with a single asterisk (*):
#foo/*/qux
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux

# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
#foo/**/qux
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux

# You can also negate patterns with an exclamation (!).
# For example, you can ignore all files in a docs folder with the file extension .md:
#docs/*.md
# Then explicitly reverse the ignore rule for a single file:
#!docs/README.md

.travis.yml
git_push.sh
tox.ini
test-requirements.txt
test/
docs/
README.md
1 change: 1 addition & 0 deletions sdk/python/sdk/zrok/.swagger-codegen/VERSION
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.0.50
Loading

0 comments on commit 26e2dff

Please sign in to comment.