Skip to content

Commit

Permalink
feat: ssh kubevirt sync demo (#9)
Browse files Browse the repository at this point in the history
  • Loading branch information
JossWhittle authored Mar 21, 2024
1 parent 0b30e89 commit 7b2b569
Show file tree
Hide file tree
Showing 27 changed files with 1,043 additions and 126 deletions.
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,18 @@ database:
kubectl apply -f https://raw.githubusercontent.com/cloudnative-pg/cloudnative-pg/release-1.22/releases/cnpg-1.22.1.yaml
```

### Install Kubevirt CRDs
```bash
kubectl create -f https://github.com/kubevirt/kubevirt/releases/download/v1.2.0/kubevirt-cr.yaml
```

### Install Kubevirt Operator
```bash
kubectl create -f https://github.com/kubevirt/kubevirt/releases/download/v1.2.0/kubevirt-operator.yaml

kubectl -n kubevirt patch kubevirt kubevirt --type=merge --patch '{"spec":{"configuration":{"developerConfiguration":{"useEmulation":true}}}}'
```

### Build the Guacamole Controller container

Tagged as controller:0.0.0 so that docker-for-windows kubernetes can access it without trying to pull it.
Expand Down
32 changes: 7 additions & 25 deletions charts/guacamole-crds/crds/guacamole-connection.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,33 +16,15 @@ spec:
spec:
type: object
properties:
url:
hostname:
type: string
description: Url to the host.

rdp:
type: object
properties:
enabled:
type: boolean
description: Expose an RDP type connection to the host.
default: false
port:
type: integer
description: Port number for RDP connections to the host.
default: 3389

ssh:
type: object
properties:
enabled:
type: boolean
description: Expose an SHH type connection to the host.
default: false
port:
type: integer
description: Port number for SHH connections to the host.
default: 22
port:
type: integer
description: Port number for the host.
protocol:
type: string
description: Protocol for the connection.

ldap:
type: object
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ spec:
{{- end }}

spec:
terminationGracePeriodSeconds: 0
restartPolicy: Always

serviceAccountName: {{ include "guacamole.fullname" . }}-controller
Expand Down
6 changes: 6 additions & 0 deletions charts/guacamole/templates/web/web-deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,12 @@ spec:
{{- end }}

env:
- name: LOGBACK_LEVEL
value: debug
- name: GUACAMOLE_LOG_LEVEL
value: "debug"
- name: LOG_LEVEL
value: debug
- name: WEBAPP_CONTEXT
value: ROOT
- name: GUACD_HOSTNAME
Expand Down
Empty file.
146 changes: 146 additions & 0 deletions containers/controller/src/controller/api/connections/create.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
# {
# "parentIdentifier": "ROOT",
# "name": "test",
# "protocol": "rdp",
# "parameters": {
# "port": "",
# "read-only": "",
# "swap-red-blue": "",
# "cursor": "",
# "color-depth": "",
# "clipboard-encoding": "",
# "disable-copy": "",
# "disable-paste": "",
# "dest-port": "",
# "recording-exclude-output": "",
# "recording-exclude-mouse": "",
# "recording-include-keys": "",
# "create-recording-path": "",
# "enable-sftp": "",
# "sftp-port": "",
# "sftp-server-alive-interval": "",
# "enable-audio": "",
# "security": "",
# "disable-auth": "",
# "ignore-cert": "",
# "gateway-port": "",
# "server-layout": "",
# "timezone": "",
# "console": "",
# "width": "",
# "height": "",
# "dpi": "",
# "resize-method": "",
# "console-audio": "",
# "disable-audio": "",
# "enable-audio-input": "",
# "enable-printing": "",
# "enable-drive": "",
# "create-drive-path": "",
# "enable-wallpaper": "",
# "enable-theming": "",
# "enable-font-smoothing": "",
# "enable-full-window-drag": "",
# "enable-desktop-composition": "",
# "enable-menu-animations": "",
# "disable-bitmap-caching": "",
# "disable-offscreen-caching": "",
# "disable-glyph-caching": "",
# "preconnection-id": "",
# "hostname": "",
# "username": "",
# "password": "",
# "domain": "",
# "gateway-hostname": "",
# "gateway-username": "",
# "gateway-password": "",
# "gateway-domain": "",
# "initial-program": "",
# "client-name": "",
# "printer-name": "",
# "drive-name": "",
# "drive-path": "",
# "static-channels": "",
# "remote-app": "",
# "remote-app-dir": "",
# "remote-app-args": "",
# "preconnection-blob": "",
# "load-balance-info": "",
# "recording-path": "",
# "recording-name": "",
# "sftp-hostname": "",
# "sftp-host-key": "",
# "sftp-username": "",
# "sftp-password": "",
# "sftp-private-key": "",
# "sftp-passphrase": "",
# "sftp-root-directory": "",
# "sftp-directory": ""
# },
# "attributes": {
# "max-connections": "",
# "max-connections-per-user": "",
# "weight": "",
# "failover-only": "",
# "guacd-port": "",
# "guacd-encryption": "",
# "guacd-hostname": ""
# }
# }

import json
import logging
from urllib.parse import quote

import requests

from ..build_url import build_url


def api_create_connection(
hostname: str,
port: int,
token: str,
data_source: str,
conn_name: str,
conn_protocol: str,
conn_parent: str,
conn_hostname: str,
conn_port: int
) -> dict:

logging.debug(f"Creating connection {conn_name=}")
response = requests.post(
build_url(
scheme="http",
netloc=f"{hostname}:{port}",
path=f"/api/session/data/{quote(data_source)}/connections",
query=dict(
token=token
)
),
data=json.dumps(dict(
parentIdentifier=conn_parent,
name=conn_name,
protocol=conn_protocol,
parameters={
"hostname": conn_hostname,
"port": str(conn_port)
},
attributes={

}
)),
verify=False,
timeout=30,
headers={"Content-Type": "application/json"}
)

if response.status_code not in (200,):
ex = RuntimeError(("Bad status code!", response.status_code, response.text))
logging.exception("Bad status code!", exc_info=ex)
raise ex

response = json.loads(response.text)
logging.debug(f"{response=}")
return response
38 changes: 38 additions & 0 deletions containers/controller/src/controller/api/connections/delete.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import logging
from urllib.parse import quote

import requests

from ..build_url import build_url
from ..error import APIConnectionDoesNotExistError


def api_delete_connection(
hostname: str,
port: int,
token: str,
data_source: str,
conn_id: int
):

logging.debug(f"Delete connection {conn_id=}")
response = requests.delete(
build_url(
scheme="http",
netloc=f"{hostname}:{port}",

path=f"/api/session/data/{quote(data_source)}/connections/{quote(str(conn_id))}",
query=dict(
token=token
)
),
verify=False,
timeout=30,
headers={"Content-Type": "application/json"}
)

if response.status_code not in (204,):
# TODO this exception catches too much
ex = APIConnectionDoesNotExistError(("Bad status code!", response.status_code, response.text))
logging.exception("Bad status code!", exc_info=ex)
raise ex
78 changes: 78 additions & 0 deletions containers/controller/src/controller/api/connections/get.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@

import json
import logging
from urllib.parse import quote

import requests

from ..build_url import build_url
from ..error import APIConnectionDoesNotExistError


def api_get_connection(
hostname: str,
port: int,
token: str,
data_source: str,
conn_id: int
) -> dict:

logging.debug(f"Get connection {conn_id=}")
response = requests.get(
build_url(
scheme="http",
netloc=f"{hostname}:{port}",

path=f"/api/session/data/{quote(data_source)}/connections/{quote(str(conn_id))}",
query=dict(
token=token
)
),
verify=False,
timeout=30,
headers={"Content-Type": "application/json"}
)

if response.status_code not in (200,):
# TODO this exception catches too much
ex = APIConnectionDoesNotExistError(("Bad status code!", response.status_code, response.text))
logging.exception("Bad status code!", exc_info=ex)
raise ex

response = json.loads(response.text)
logging.debug(f"{response=}")
return response


def api_get_connection_parameters(
hostname: str,
port: int,
token: str,
data_source: str,
conn_id: int
) -> dict:

logging.debug(f"Get connection parameters {conn_id=}")
response = requests.get(
build_url(
scheme="http",
netloc=f"{hostname}:{port}",
path=f"/api/session/data/{quote(data_source)}/connections/{quote(str(conn_id))}/parameters",
query=dict(
token=token
)
),
verify=False,
timeout=30,
headers={"Content-Type": "application/json"}
)

if response.status_code not in (200,):
# TODO this exception catches too much
ex = APIConnectionDoesNotExistError(("Bad status code!", response.status_code, response.text))
logging.exception("Bad status code!", exc_info=ex)
raise ex

response = json.loads(response.text)
logging.debug(f"{response=}")
return response
41 changes: 41 additions & 0 deletions containers/controller/src/controller/api/connections/list.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@

import json
import logging
from urllib.parse import quote

import requests

from ..build_url import build_url


def api_list_connections(
hostname: str,
port: int,
token: str,
data_source: str
) -> dict:

logging.debug("List connections")
response = requests.get(
build_url(
scheme="http",
netloc=f"{hostname}:{port}",

path=f"/api/session/data/{quote(data_source)}/connections",
query=dict(
token=token
)
),
verify=False,
timeout=30,
headers={"Content-Type": "application/json"}
)

if response.status_code not in (200,):
ex = RuntimeError(("Bad status code!", response.status_code, response.text))
logging.exception("Bad status code!", exc_info=ex)
raise ex

response = json.loads(response.text)
logging.debug(f"{response=}")
return response
Loading

0 comments on commit 7b2b569

Please sign in to comment.